]> git.cworth.org Git - apitrace/blob - common/trace_writer.cpp
Use skiplist-based FastCallSet within trace::CallSet
[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::beginRepr(void) {
194     _writeByte(trace::TYPE_REPR);
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, signed long long value) {
267     _writeByte(trace::TYPE_ENUM);
268     _writeUInt(sig->id);
269     if (!lookup(enums, sig->id)) {
270         _writeUInt(sig->num_values);
271         for (unsigned i = 0; i < sig->num_values; ++i) {
272             _writeString(sig->values[i].name);
273             writeSInt(sig->values[i].value);
274         }
275         enums[sig->id] = true;
276     }
277     writeSInt(value);
278 }
279
280 void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
281     _writeByte(trace::TYPE_BITMASK);
282     _writeUInt(sig->id);
283     if (!lookup(bitmasks, sig->id)) {
284         _writeUInt(sig->num_flags);
285         for (unsigned i = 0; i < sig->num_flags; ++i) {
286             if (i != 0 && sig->flags[i].value == 0) {
287                 os::log("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name);
288             }
289             _writeString(sig->flags[i].name);
290             _writeUInt(sig->flags[i].value);
291         }
292         bitmasks[sig->id] = true;
293     }
294     _writeUInt(value);
295 }
296
297 void Writer::writeNull(void) {
298     _writeByte(trace::TYPE_NULL);
299 }
300
301 void Writer::writePointer(unsigned long long addr) {
302     if (!addr) {
303         Writer::writeNull();
304         return;
305     }
306     _writeByte(trace::TYPE_OPAQUE);
307     _writeUInt(addr);
308 }
309
310
311 } /* namespace trace */
312