]> git.cworth.org Git - apitrace/blob - trace_writer.cpp
Add a link to the mailing list
[apitrace] / trace_writer.cpp
1 /**************************************************************************
2  *
3  * Copyright 2007-2009 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <assert.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <zlib.h>
34
35 #include "os.hpp"
36 #include "trace_writer.hpp"
37 #include "trace_format.hpp"
38
39
40 namespace Trace {
41
42
43 Writer::Writer() :
44     g_gzFile(NULL),
45     call_no(0)
46 {
47     close();
48 };
49
50 Writer::~Writer() {
51     close();
52 };
53
54 void
55 Writer::close(void) {
56     if (g_gzFile != NULL) {
57         gzclose(g_gzFile);
58         g_gzFile = NULL;
59     }
60 }
61
62 bool
63 Writer::open(const char *filename) {
64     close();
65
66     g_gzFile = gzopen(filename, "wb");
67     if (!g_gzFile) {
68         return false;
69     }
70
71     call_no = 0;
72     functions.clear();
73     structs.clear();
74     enums.clear();
75     bitmasks.clear();
76
77     _writeUInt(TRACE_VERSION);
78
79     return true;
80 }
81
82 void inline
83 Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
84     if (g_gzFile == NULL)
85         return;
86
87     gzwrite(g_gzFile, sBuffer, dwBytesToWrite);
88 }
89
90 void inline
91 Writer::_writeByte(char c) {
92     _write(&c, 1);
93 }
94
95 void inline
96 Writer::_writeUInt(unsigned long long value) {
97     char buf[2 * sizeof value];
98     unsigned len;
99
100     len = 0;
101     do {
102         assert(len < sizeof buf);
103         buf[len] = 0x80 | (value & 0x7f);
104         value >>= 7;
105         ++len;
106     } while (value);
107
108     assert(len);
109     buf[len - 1] &= 0x7f;
110
111     _write(buf, len);
112 }
113
114 void inline
115 Writer::_writeFloat(float value) {
116     assert(sizeof value == 4);
117     _write((const char *)&value, sizeof value);
118 }
119
120 void inline
121 Writer::_writeDouble(double value) {
122     assert(sizeof value == 8);
123     _write((const char *)&value, sizeof value);
124 }
125
126 void inline
127 Writer::_writeString(const char *str) {
128     size_t len = strlen(str);
129     _writeUInt(len);
130     _write(str, len);
131 }
132
133 inline bool lookup(std::vector<bool> &map, size_t index) {
134     if (index >= map.size()) {
135         map.resize(index + 1);
136         return false;
137     } else {
138         return map[index];
139     }
140 }
141
142 unsigned Writer::beginEnter(const FunctionSig *sig) {
143     _writeByte(Trace::EVENT_ENTER);
144     _writeUInt(sig->id);
145     if (!lookup(functions, sig->id)) {
146         _writeString(sig->name);
147         _writeUInt(sig->num_args);
148         for (unsigned i = 0; i < sig->num_args; ++i) {
149             _writeString(sig->arg_names[i]);
150         }
151         functions[sig->id] = true;
152     }
153
154     return call_no++;
155 }
156
157 void Writer::endEnter(void) {
158     _writeByte(Trace::CALL_END);
159 }
160
161 void Writer::beginLeave(unsigned call) {
162     _writeByte(Trace::EVENT_LEAVE);
163     _writeUInt(call);
164 }
165
166 void Writer::endLeave(void) {
167     _writeByte(Trace::CALL_END);
168 }
169
170 void Writer::beginArg(unsigned index) {
171     _writeByte(Trace::CALL_ARG);
172     _writeUInt(index);
173 }
174
175 void Writer::beginReturn(void) {
176     _writeByte(Trace::CALL_RET);
177 }
178
179 void Writer::beginArray(size_t length) {
180     _writeByte(Trace::TYPE_ARRAY);
181     _writeUInt(length);
182 }
183
184 void Writer::beginStruct(const StructSig *sig) {
185     _writeByte(Trace::TYPE_STRUCT);
186     _writeUInt(sig->id);
187     if (!lookup(structs, sig->id)) {
188         _writeString(sig->name);
189         _writeUInt(sig->num_members);
190         for (unsigned i = 0; i < sig->num_members; ++i) {
191             _writeString(sig->member_names[i]);
192         }
193         structs[sig->id] = true;
194     }
195 }
196
197 void Writer::writeBool(bool value) {
198     _writeByte(value ? Trace::TYPE_TRUE : Trace::TYPE_FALSE);
199 }
200
201 void Writer::writeSInt(signed long long value) {
202     if (value < 0) {
203         _writeByte(Trace::TYPE_SINT);
204         _writeUInt(-value);
205     } else {
206         _writeByte(Trace::TYPE_UINT);
207         _writeUInt(value);
208     }
209 }
210
211 void Writer::writeUInt(unsigned long long value) {
212     _writeByte(Trace::TYPE_UINT);
213     _writeUInt(value);
214 }
215
216 void Writer::writeFloat(float value) {
217     _writeByte(Trace::TYPE_FLOAT);
218     _writeFloat(value);
219 }
220
221 void Writer::writeDouble(double value) {
222     _writeByte(Trace::TYPE_DOUBLE);
223     _writeDouble(value);
224 }
225
226 void Writer::writeString(const char *str) {
227     if (!str) {
228         Writer::writeNull();
229         return;
230     }
231     _writeByte(Trace::TYPE_STRING);
232     _writeString(str);
233 }
234
235 void Writer::writeString(const char *str, size_t len) {
236     if (!str) {
237         Writer::writeNull();
238         return;
239     }
240     _writeByte(Trace::TYPE_STRING);
241     _writeUInt(len);
242     _write(str, len);
243 }
244
245 void Writer::writeWString(const wchar_t *str) {
246     if (!str) {
247         Writer::writeNull();
248         return;
249     }
250     _writeByte(Trace::TYPE_STRING);
251     _writeString("<wide-string>");
252 }
253
254 void Writer::writeBlob(const void *data, size_t size) {
255     if (!data) {
256         Writer::writeNull();
257         return;
258     }
259     _writeByte(Trace::TYPE_BLOB);
260     _writeUInt(size);
261     if (size) {
262         _write(data, size);
263     }
264 }
265
266 void Writer::writeEnum(const EnumSig *sig) {
267     _writeByte(Trace::TYPE_ENUM);
268     _writeUInt(sig->id);
269     if (!lookup(enums, sig->id)) {
270         _writeString(sig->name);
271         Writer::writeSInt(sig->value);
272         enums[sig->id] = true;
273     }
274 }
275
276 void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
277     _writeByte(Trace::TYPE_BITMASK);
278     _writeUInt(sig->id);
279     if (!lookup(bitmasks, sig->id)) {
280         _writeUInt(sig->num_flags);
281         for (unsigned i = 0; i < sig->num_flags; ++i) {
282             if (i != 0 && sig->flags[i].value == 0) {
283                 OS::DebugMessage("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name);
284             }
285             _writeString(sig->flags[i].name);
286             _writeUInt(sig->flags[i].value);
287         }
288         bitmasks[sig->id] = true;
289     }
290     _writeUInt(value);
291 }
292
293 void Writer::writeNull(void) {
294     _writeByte(Trace::TYPE_NULL);
295 }
296
297 void Writer::writeOpaque(const void *addr) {
298     if (!addr) {
299         Writer::writeNull();
300         return;
301     }
302     _writeByte(Trace::TYPE_OPAQUE);
303     _writeUInt((size_t)addr);
304 }
305
306
307 void
308 LocalWriter::open(void) {
309
310     static unsigned dwCounter = 0;
311
312     const char *szExtension = "trace";
313     char szFileName[PATH_MAX];
314     const char *lpFileName;
315
316     lpFileName = getenv("TRACE_FILE");
317     if (lpFileName) {
318         strncpy(szFileName, lpFileName, PATH_MAX);
319     }
320     else {
321         char szProcessName[PATH_MAX];
322         char szCurrentDir[PATH_MAX];
323         OS::GetProcessName(szProcessName, PATH_MAX);
324         OS::GetCurrentDir(szCurrentDir, PATH_MAX);
325
326         for (;;) {
327             FILE *file;
328
329             if (dwCounter)
330                 snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension);
331             else
332                 snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension);
333
334             file = fopen(szFileName, "rb");
335             if (file == NULL)
336                 break;
337
338             fclose(file);
339
340             ++dwCounter;
341         }
342     }
343
344     OS::DebugMessage("apitrace: tracing to %s\n", szFileName);
345
346     Writer::open(szFileName);
347 }
348
349 unsigned LocalWriter::beginEnter(const FunctionSig *sig) {
350     OS::AcquireMutex();
351
352     if (!g_gzFile) {
353         open();
354     }
355
356     return Writer::beginEnter(sig);
357 }
358
359 void LocalWriter::endEnter(void) {
360     Writer::endEnter();
361     gzflush(g_gzFile, Z_SYNC_FLUSH);
362     OS::ReleaseMutex();
363 }
364
365 void LocalWriter::beginLeave(unsigned call) {
366     OS::AcquireMutex();
367     Writer::beginLeave(call);
368 }
369
370 void LocalWriter::endLeave(void) {
371     Writer::endLeave();
372     gzflush(g_gzFile, Z_SYNC_FLUSH);
373     OS::ReleaseMutex();
374 }
375
376
377 } /* namespace Trace */
378