]> git.cworth.org Git - apitrace/blob - common/trace_writer.cpp
f4b82d8f300e0084eb5b6e0943afa49f4be8b2fd
[apitrace] / common / 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_file.hpp"
35 #include "trace_writer.hpp"
36 #include "trace_format.hpp"
37
38
39 namespace trace {
40
41
42 Writer::Writer() :
43     call_no(0)
44 {
45     m_file = File::createSnappy();
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 inline
81 Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
82     m_file->write(sBuffer, dwBytesToWrite);
83 }
84
85 void inline
86 Writer::_writeByte(char c) {
87     _write(&c, 1);
88 }
89
90 void inline
91 Writer::_writeUInt(unsigned long long value) {
92     char buf[2 * sizeof value];
93     unsigned len;
94
95     len = 0;
96     do {
97         assert(len < sizeof buf);
98         buf[len] = 0x80 | (value & 0x7f);
99         value >>= 7;
100         ++len;
101     } while (value);
102
103     assert(len);
104     buf[len - 1] &= 0x7f;
105
106     _write(buf, len);
107 }
108
109 void inline
110 Writer::_writeFloat(float value) {
111     assert(sizeof value == 4);
112     _write((const char *)&value, sizeof value);
113 }
114
115 void inline
116 Writer::_writeDouble(double value) {
117     assert(sizeof value == 8);
118     _write((const char *)&value, sizeof value);
119 }
120
121 void inline
122 Writer::_writeString(const char *str) {
123     size_t len = strlen(str);
124     _writeUInt(len);
125     _write(str, len);
126 }
127
128 inline bool lookup(std::vector<bool> &map, size_t index) {
129     if (index >= map.size()) {
130         map.resize(index + 1);
131         return false;
132     } else {
133         return map[index];
134     }
135 }
136
137 unsigned Writer::beginEnter(const FunctionSig *sig, unsigned thread_id) {
138     _writeByte(trace::EVENT_ENTER);
139     _writeUInt(thread_id);
140     _writeUInt(sig->id);
141     if (!lookup(functions, sig->id)) {
142         _writeString(sig->name);
143         _writeUInt(sig->num_args);
144         for (unsigned i = 0; i < sig->num_args; ++i) {
145             _writeString(sig->arg_names[i]);
146         }
147         functions[sig->id] = true;
148     }
149
150     return call_no++;
151 }
152
153 void Writer::endEnter(void) {
154     _writeByte(trace::CALL_END);
155 }
156
157 void Writer::beginLeave(unsigned call) {
158     _writeByte(trace::EVENT_LEAVE);
159     _writeUInt(call);
160 }
161
162 void Writer::endLeave(void) {
163     _writeByte(trace::CALL_END);
164 }
165
166 void Writer::beginArg(unsigned index) {
167     _writeByte(trace::CALL_ARG);
168     _writeUInt(index);
169 }
170
171 void Writer::beginReturn(void) {
172     _writeByte(trace::CALL_RET);
173 }
174
175 void Writer::beginArray(size_t length) {
176     _writeByte(trace::TYPE_ARRAY);
177     _writeUInt(length);
178 }
179
180 void Writer::beginStruct(const StructSig *sig) {
181     _writeByte(trace::TYPE_STRUCT);
182     _writeUInt(sig->id);
183     if (!lookup(structs, sig->id)) {
184         _writeString(sig->name);
185         _writeUInt(sig->num_members);
186         for (unsigned i = 0; i < sig->num_members; ++i) {
187             _writeString(sig->member_names[i]);
188         }
189         structs[sig->id] = true;
190     }
191 }
192
193 void Writer::writeBool(bool value) {
194     _writeByte(value ? trace::TYPE_TRUE : trace::TYPE_FALSE);
195 }
196
197 void Writer::writeSInt(signed long long value) {
198     if (value < 0) {
199         _writeByte(trace::TYPE_SINT);
200         _writeUInt(-value);
201     } else {
202         _writeByte(trace::TYPE_UINT);
203         _writeUInt(value);
204     }
205 }
206
207 void Writer::writeUInt(unsigned long long value) {
208     _writeByte(trace::TYPE_UINT);
209     _writeUInt(value);
210 }
211
212 void Writer::writeFloat(float value) {
213     _writeByte(trace::TYPE_FLOAT);
214     _writeFloat(value);
215 }
216
217 void Writer::writeDouble(double value) {
218     _writeByte(trace::TYPE_DOUBLE);
219     _writeDouble(value);
220 }
221
222 void Writer::writeString(const char *str) {
223     if (!str) {
224         Writer::writeNull();
225         return;
226     }
227     _writeByte(trace::TYPE_STRING);
228     _writeString(str);
229 }
230
231 void Writer::writeString(const char *str, size_t len) {
232     if (!str) {
233         Writer::writeNull();
234         return;
235     }
236     _writeByte(trace::TYPE_STRING);
237     _writeUInt(len);
238     _write(str, len);
239 }
240
241 void Writer::writeWString(const wchar_t *str) {
242     if (!str) {
243         Writer::writeNull();
244         return;
245     }
246     _writeByte(trace::TYPE_STRING);
247     _writeString("<wide-string>");
248 }
249
250 void Writer::writeBlob(const void *data, size_t size) {
251     if (!data) {
252         Writer::writeNull();
253         return;
254     }
255     _writeByte(trace::TYPE_BLOB);
256     _writeUInt(size);
257     if (size) {
258         _write(data, size);
259     }
260 }
261
262 void Writer::writeEnum(const EnumSig *sig, signed long long value) {
263     _writeByte(trace::TYPE_ENUM);
264     _writeUInt(sig->id);
265     if (!lookup(enums, sig->id)) {
266         _writeUInt(sig->num_values);
267         for (unsigned i = 0; i < sig->num_values; ++i) {
268             _writeString(sig->values[i].name);
269             writeSInt(sig->values[i].value);
270         }
271         enums[sig->id] = true;
272     }
273     writeSInt(value);
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::log("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::writePointer(unsigned long long addr) {
298     if (!addr) {
299         Writer::writeNull();
300         return;
301     }
302     _writeByte(trace::TYPE_OPAQUE);
303     _writeUInt(addr);
304 }
305
306
307 } /* namespace trace */
308