]> git.cworth.org Git - apitrace/blob - trace_writer.cpp
Automatically detect whether trace is zlib or snappy compressed
[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 "os.hpp"
34 #include "trace_writer.hpp"
35 #include "trace_file.hpp"
36 #include "trace_format.hpp"
37
38
39 namespace Trace {
40
41
42 Writer::Writer() :
43     call_no(0)
44 {
45     m_file = new Trace::SnappyFile;
46     close();
47 }
48
49 Writer::~Writer()
50 {
51     close();
52     delete m_file;
53     m_file = NULL;
54 }
55
56 void
57 Writer::close(void) {
58     m_file->close();
59 }
60
61 bool
62 Writer::open(const char *filename) {
63     close();
64
65     if (!m_file->open(filename, File::Write)) {
66         return false;
67     }
68
69     call_no = 0;
70     functions.clear();
71     structs.clear();
72     enums.clear();
73     bitmasks.clear();
74
75     _writeUInt(TRACE_VERSION);
76
77     return true;
78 }
79
80 void
81 Writer::open(void) {
82
83     static unsigned dwCounter = 0;
84
85     const char *szExtension = "trace";
86     char szFileName[PATH_MAX];
87     const char *lpFileName;
88
89     lpFileName = getenv("TRACE_FILE");
90     if (lpFileName) {
91         strncpy(szFileName, lpFileName, PATH_MAX);
92     }
93     else {
94         char szProcessName[PATH_MAX];
95         char szCurrentDir[PATH_MAX];
96         OS::GetProcessName(szProcessName, PATH_MAX);
97         OS::GetCurrentDir(szCurrentDir, PATH_MAX);
98
99         for (;;) {
100             FILE *file;
101
102             if (dwCounter)
103                 snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension);
104             else
105                 snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension);
106
107             file = fopen(szFileName, "rb");
108             if (file == NULL)
109                 break;
110
111             fclose(file);
112
113             ++dwCounter;
114         }
115     }
116
117     OS::DebugMessage("apitrace: tracing to %s\n", szFileName);
118
119     open(szFileName);
120 }
121
122 void inline
123 Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
124     m_file->write(sBuffer, dwBytesToWrite);
125 }
126
127 void inline
128 Writer::_writeByte(char c) {
129     _write(&c, 1);
130 }
131
132 void inline
133 Writer::_writeUInt(unsigned long long value) {
134     char buf[2 * sizeof value];
135     unsigned len;
136
137     len = 0;
138     do {
139         assert(len < sizeof buf);
140         buf[len] = 0x80 | (value & 0x7f);
141         value >>= 7;
142         ++len;
143     } while (value);
144
145     assert(len);
146     buf[len - 1] &= 0x7f;
147
148     _write(buf, len);
149 }
150
151 void inline
152 Writer::_writeFloat(float value) {
153     assert(sizeof value == 4);
154     _write((const char *)&value, sizeof value);
155 }
156
157 void inline
158 Writer::_writeDouble(double value) {
159     assert(sizeof value == 8);
160     _write((const char *)&value, sizeof value);
161 }
162
163 void inline
164 Writer::_writeString(const char *str) {
165     size_t len = strlen(str);
166     _writeUInt(len);
167     _write(str, len);
168 }
169
170 inline bool lookup(std::vector<bool> &map, size_t index) {
171     if (index >= map.size()) {
172         map.resize(index + 1);
173         return false;
174     } else {
175         return map[index];
176     }
177 }
178
179 unsigned Writer::beginEnter(const FunctionSig *sig) {
180     OS::AcquireMutex();
181
182     if (!m_file->isOpened()) {
183         open();
184     }
185
186     _writeByte(Trace::EVENT_ENTER);
187     _writeUInt(sig->id);
188     if (!lookup(functions, sig->id)) {
189         _writeString(sig->name);
190         _writeUInt(sig->num_args);
191         for (unsigned i = 0; i < sig->num_args; ++i) {
192             _writeString(sig->arg_names[i]);
193         }
194         functions[sig->id] = true;
195     }
196
197     return call_no++;
198 }
199
200 void Writer::endEnter(void) {
201     _writeByte(Trace::CALL_END);
202     m_file->flush();
203     OS::ReleaseMutex();
204 }
205
206 void Writer::beginLeave(unsigned call) {
207     OS::AcquireMutex();
208     _writeByte(Trace::EVENT_LEAVE);
209     _writeUInt(call);
210 }
211
212 void Writer::endLeave(void) {
213     _writeByte(Trace::CALL_END);
214     m_file->flush();
215     OS::ReleaseMutex();
216 }
217
218 void Writer::beginArg(unsigned index) {
219     _writeByte(Trace::CALL_ARG);
220     _writeUInt(index);
221 }
222
223 void Writer::beginReturn(void) {
224     _writeByte(Trace::CALL_RET);
225 }
226
227 void Writer::beginArray(size_t length) {
228     _writeByte(Trace::TYPE_ARRAY);
229     _writeUInt(length);
230 }
231
232 void Writer::beginStruct(const StructSig *sig) {
233     _writeByte(Trace::TYPE_STRUCT);
234     _writeUInt(sig->id);
235     if (!lookup(structs, sig->id)) {
236         _writeString(sig->name);
237         _writeUInt(sig->num_members);
238         for (unsigned i = 0; i < sig->num_members; ++i) {
239             _writeString(sig->member_names[i]);
240         }
241         structs[sig->id] = true;
242     }
243 }
244
245 void Writer::writeBool(bool value) {
246     _writeByte(value ? Trace::TYPE_TRUE : Trace::TYPE_FALSE);
247 }
248
249 void Writer::writeSInt(signed long long value) {
250     if (value < 0) {
251         _writeByte(Trace::TYPE_SINT);
252         _writeUInt(-value);
253     } else {
254         _writeByte(Trace::TYPE_UINT);
255         _writeUInt(value);
256     }
257 }
258
259 void Writer::writeUInt(unsigned long long value) {
260     _writeByte(Trace::TYPE_UINT);
261     _writeUInt(value);
262 }
263
264 void Writer::writeFloat(float value) {
265     _writeByte(Trace::TYPE_FLOAT);
266     _writeFloat(value);
267 }
268
269 void Writer::writeDouble(double value) {
270     _writeByte(Trace::TYPE_DOUBLE);
271     _writeDouble(value);
272 }
273
274 void Writer::writeString(const char *str) {
275     if (!str) {
276         Writer::writeNull();
277         return;
278     }
279     _writeByte(Trace::TYPE_STRING);
280     _writeString(str);
281 }
282
283 void Writer::writeString(const char *str, size_t len) {
284     if (!str) {
285         Writer::writeNull();
286         return;
287     }
288     _writeByte(Trace::TYPE_STRING);
289     _writeUInt(len);
290     _write(str, len);
291 }
292
293 void Writer::writeWString(const wchar_t *str) {
294     if (!str) {
295         Writer::writeNull();
296         return;
297     }
298     _writeByte(Trace::TYPE_STRING);
299     _writeString("<wide-string>");
300 }
301
302 void Writer::writeBlob(const void *data, size_t size) {
303     if (!data) {
304         Writer::writeNull();
305         return;
306     }
307     _writeByte(Trace::TYPE_BLOB);
308     _writeUInt(size);
309     if (size) {
310         _write(data, size);
311     }
312 }
313
314 void Writer::writeEnum(const EnumSig *sig) {
315     _writeByte(Trace::TYPE_ENUM);
316     _writeUInt(sig->id);
317     if (!lookup(enums, sig->id)) {
318         _writeString(sig->name);
319         Writer::writeSInt(sig->value);
320         enums[sig->id] = true;
321     }
322 }
323
324 void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
325     _writeByte(Trace::TYPE_BITMASK);
326     _writeUInt(sig->id);
327     if (!lookup(bitmasks, sig->id)) {
328         _writeUInt(sig->num_flags);
329         for (unsigned i = 0; i < sig->num_flags; ++i) {
330             if (i != 0 && sig->flags[i].value == 0) {
331                 OS::DebugMessage("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name);
332             }
333             _writeString(sig->flags[i].name);
334             _writeUInt(sig->flags[i].value);
335         }
336         bitmasks[sig->id] = true;
337     }
338     _writeUInt(value);
339 }
340
341 void Writer::writeNull(void) {
342     _writeByte(Trace::TYPE_NULL);
343 }
344
345 void Writer::writeOpaque(const void *addr) {
346     if (!addr) {
347         Writer::writeNull();
348         return;
349     }
350     _writeByte(Trace::TYPE_OPAQUE);
351     _writeUInt((size_t)addr);
352 }
353
354 } /* namespace Trace */
355