viztracer 1.1.0__cp314-cp314-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of viztracer might be problematic. Click here for more details.

Files changed (109) hide show
  1. viztracer/__init__.py +19 -0
  2. viztracer/__main__.py +8 -0
  3. viztracer/attach.py +67 -0
  4. viztracer/attach_process/LICENSE +203 -0
  5. viztracer/attach_process/__init__.py +0 -0
  6. viztracer/attach_process/add_code_to_python_process.py +582 -0
  7. viztracer/attach_process/attach_x86.dll +0 -0
  8. viztracer/attach_process/inject_dll_amd64.exe +0 -0
  9. viztracer/attach_process/linux_and_mac/lldb_prepare.py +54 -0
  10. viztracer/attach_process/run_code_on_dllmain_amd64.dll +0 -0
  11. viztracer/attach_process/run_code_on_dllmain_x86.dll +0 -0
  12. viztracer/cellmagic.py +70 -0
  13. viztracer/code_monkey.py +353 -0
  14. viztracer/decorator.py +164 -0
  15. viztracer/event_base.py +81 -0
  16. viztracer/functree.py +135 -0
  17. viztracer/html/flamegraph.html +34 -0
  18. viztracer/html/trace_viewer_embedder.html +203 -0
  19. viztracer/html/trace_viewer_full.html +10207 -0
  20. viztracer/main.py +699 -0
  21. viztracer/modules/eventnode.c +172 -0
  22. viztracer/modules/eventnode.h +73 -0
  23. viztracer/modules/pythoncapi_compat.h +1726 -0
  24. viztracer/modules/quicktime.c +177 -0
  25. viztracer/modules/quicktime.h +104 -0
  26. viztracer/modules/snaptrace.c +2205 -0
  27. viztracer/modules/snaptrace.h +134 -0
  28. viztracer/modules/snaptrace_member.c +483 -0
  29. viztracer/modules/util.c +45 -0
  30. viztracer/modules/util.h +22 -0
  31. viztracer/modules/vcompressor/vc_dump.c +1131 -0
  32. viztracer/modules/vcompressor/vc_dump.h +49 -0
  33. viztracer/modules/vcompressor/vcompressor.c +396 -0
  34. viztracer/modules/vcompressor/vcompressor.h +15 -0
  35. viztracer/patch.py +307 -0
  36. viztracer/report_builder.py +311 -0
  37. viztracer/snaptrace.cp314-win32.pyd +0 -0
  38. viztracer/snaptrace.pyi +77 -0
  39. viztracer/util.py +196 -0
  40. viztracer/vcompressor.cp314-win32.pyd +0 -0
  41. viztracer/vcompressor.pyi +10 -0
  42. viztracer/viewer.py +528 -0
  43. viztracer/vizcounter.py +20 -0
  44. viztracer/vizevent.py +31 -0
  45. viztracer/vizlogging.py +20 -0
  46. viztracer/vizobject.py +28 -0
  47. viztracer/vizplugin.py +143 -0
  48. viztracer/viztracer.py +472 -0
  49. viztracer/web_dist/LICENSE +189 -0
  50. viztracer/web_dist/index.html +127 -0
  51. viztracer/web_dist/service_worker.js +279 -0
  52. viztracer/web_dist/trace_processor +300 -0
  53. viztracer/web_dist/v52.0-6b9586def/assets/MaterialSymbolsOutlined.woff2 +0 -0
  54. viztracer/web_dist/v52.0-6b9586def/assets/Roboto-100.woff2 +0 -0
  55. viztracer/web_dist/v52.0-6b9586def/assets/Roboto-300.woff2 +0 -0
  56. viztracer/web_dist/v52.0-6b9586def/assets/Roboto-400.woff2 +0 -0
  57. viztracer/web_dist/v52.0-6b9586def/assets/Roboto-500.woff2 +0 -0
  58. viztracer/web_dist/v52.0-6b9586def/assets/RobotoCondensed-Light.woff2 +0 -0
  59. viztracer/web_dist/v52.0-6b9586def/assets/RobotoCondensed-Regular.woff2 +0 -0
  60. viztracer/web_dist/v52.0-6b9586def/assets/RobotoMono-Regular.woff2 +0 -0
  61. viztracer/web_dist/v52.0-6b9586def/assets/brand.png +0 -0
  62. viztracer/web_dist/v52.0-6b9586def/assets/catapult_trace_viewer.html +3946 -0
  63. viztracer/web_dist/v52.0-6b9586def/assets/catapult_trace_viewer.js +7539 -0
  64. viztracer/web_dist/v52.0-6b9586def/assets/favicon.png +0 -0
  65. viztracer/web_dist/v52.0-6b9586def/assets/logo-128.png +0 -0
  66. viztracer/web_dist/v52.0-6b9586def/assets/logo-3d.png +0 -0
  67. viztracer/web_dist/v52.0-6b9586def/assets/rec_atrace.png +0 -0
  68. viztracer/web_dist/v52.0-6b9586def/assets/rec_battery_counters.png +0 -0
  69. viztracer/web_dist/v52.0-6b9586def/assets/rec_board_voltage.png +0 -0
  70. viztracer/web_dist/v52.0-6b9586def/assets/rec_cpu_coarse.png +0 -0
  71. viztracer/web_dist/v52.0-6b9586def/assets/rec_cpu_fine.png +0 -0
  72. viztracer/web_dist/v52.0-6b9586def/assets/rec_cpu_freq.png +0 -0
  73. viztracer/web_dist/v52.0-6b9586def/assets/rec_cpu_voltage.png +0 -0
  74. viztracer/web_dist/v52.0-6b9586def/assets/rec_frame_timeline.png +0 -0
  75. viztracer/web_dist/v52.0-6b9586def/assets/rec_ftrace.png +0 -0
  76. viztracer/web_dist/v52.0-6b9586def/assets/rec_gpu_mem_total.png +0 -0
  77. viztracer/web_dist/v52.0-6b9586def/assets/rec_java_heap_dump.png +0 -0
  78. viztracer/web_dist/v52.0-6b9586def/assets/rec_lmk.png +0 -0
  79. viztracer/web_dist/v52.0-6b9586def/assets/rec_logcat.png +0 -0
  80. viztracer/web_dist/v52.0-6b9586def/assets/rec_long_trace.png +0 -0
  81. viztracer/web_dist/v52.0-6b9586def/assets/rec_mem_hifreq.png +0 -0
  82. viztracer/web_dist/v52.0-6b9586def/assets/rec_meminfo.png +0 -0
  83. viztracer/web_dist/v52.0-6b9586def/assets/rec_native_heap_profiler.png +0 -0
  84. viztracer/web_dist/v52.0-6b9586def/assets/rec_one_shot.png +0 -0
  85. viztracer/web_dist/v52.0-6b9586def/assets/rec_profiling.png +0 -0
  86. viztracer/web_dist/v52.0-6b9586def/assets/rec_ps_stats.png +0 -0
  87. viztracer/web_dist/v52.0-6b9586def/assets/rec_ring_buf.png +0 -0
  88. viztracer/web_dist/v52.0-6b9586def/assets/rec_syscalls.png +0 -0
  89. viztracer/web_dist/v52.0-6b9586def/assets/rec_vmstat.png +0 -0
  90. viztracer/web_dist/v52.0-6b9586def/assets/scheduling_latency.png +0 -0
  91. viztracer/web_dist/v52.0-6b9586def/assets/vscode-icon.png +0 -0
  92. viztracer/web_dist/v52.0-6b9586def/engine_bundle.js +3 -0
  93. viztracer/web_dist/v52.0-6b9586def/frontend_bundle.js +5495 -0
  94. viztracer/web_dist/v52.0-6b9586def/index.html +127 -0
  95. viztracer/web_dist/v52.0-6b9586def/manifest.json +52 -0
  96. viztracer/web_dist/v52.0-6b9586def/perfetto.css +5737 -0
  97. viztracer/web_dist/v52.0-6b9586def/stdlib_docs.json +1 -0
  98. viztracer/web_dist/v52.0-6b9586def/trace_config_utils.wasm +0 -0
  99. viztracer/web_dist/v52.0-6b9586def/trace_processor.wasm +0 -0
  100. viztracer/web_dist/v52.0-6b9586def/trace_processor_memory64.wasm +0 -0
  101. viztracer/web_dist/v52.0-6b9586def/traceconv.wasm +0 -0
  102. viztracer/web_dist/v52.0-6b9586def/traceconv_bundle.js +2 -0
  103. viztracer-1.1.0.dist-info/METADATA +316 -0
  104. viztracer-1.1.0.dist-info/RECORD +109 -0
  105. viztracer-1.1.0.dist-info/WHEEL +5 -0
  106. viztracer-1.1.0.dist-info/entry_points.txt +3 -0
  107. viztracer-1.1.0.dist-info/licenses/LICENSE +222 -0
  108. viztracer-1.1.0.dist-info/licenses/NOTICE.txt +27 -0
  109. viztracer-1.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1131 @@
1
+ // Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
+ // For details: https://github.com/gaogaotiantian/viztracer/blob/master/NOTICE.txt
3
+
4
+ #include <Python.h>
5
+ #include "vcompressor.h"
6
+ #include "vc_dump.h"
7
+
8
+ #define STRING_BUFFER_SIZE 512
9
+
10
+ // Not sure if we need to compress the whole file using zlib.
11
+ // Use this flag to control if we need to compress json data.
12
+ // This is for test for now
13
+ #define NEED_COMPRESS_IN_FILE 1
14
+
15
+ #define READ_DATA(ptr, type, fptr) \
16
+ { \
17
+ size_t s = fread(ptr, sizeof(type), 1, fptr); \
18
+ if (s != 1) { \
19
+ PyErr_SetString(PyExc_ValueError, "file is corrupted"); \
20
+ goto clean_exit; \
21
+ } \
22
+ }
23
+
24
+ #define PyDict_SetItemStringULL(dct, key, val) \
25
+ { \
26
+ PyObject* o = PyLong_FromUnsignedLongLong(val); \
27
+ PyDict_SetItemString(dct, key, o); \
28
+ Py_DECREF(o); \
29
+ }
30
+
31
+ #define PyDict_SetItemStringDouble(dct, key, val) \
32
+ { \
33
+ PyObject* o = PyFloat_FromDouble(val); \
34
+ PyDict_SetItemString(dct, key, o); \
35
+ Py_DECREF(o); \
36
+ }
37
+
38
+ // The input line has to be null-terminated
39
+ // This function will write the line and append a null terminator after it
40
+ #define fwritestr(line, fptr) \
41
+ { \
42
+ fwrite(line, sizeof(char), strlen(line), fptr); \
43
+ fputc('\0', fptr); \
44
+ }
45
+
46
+ #define PEEK_DATA(ptr, type, fptr) \
47
+ { \
48
+ size_t s = fread(ptr, sizeof(type), 1, fptr); \
49
+ if (s != 1) { \
50
+ PyErr_SetString(PyExc_ValueError, "file is corrupted"); \
51
+ goto clean_exit; \
52
+ } else { \
53
+ fseek(fptr, -sizeof(type), SEEK_CUR); \
54
+ } \
55
+ }
56
+
57
+ /*
58
+ * The write_encoded_int and read_encoded_int functions are used to compress
59
+ * and decompress timestamp. For a trace file, most of the data are ts and dur.
60
+ * So we sort the timestamp and only record diff of two between two contiguous
61
+ * timestamp.
62
+ *
63
+ * We use a 2-bit flag to indicate how many bytes can uint64_t data be fit in.
64
+ * For Windows, Mac and most of the Linux, the byte order is little-endian,
65
+ * which means if we want to record 0X12345678. The data in file would be:
66
+ * 78 56 34 12
67
+ * To make it simple, we just move the data left 2 bits and put the flag at
68
+ * the lowest position of the timestamp.
69
+ *
70
+ * And the parsed timestamp is always less than 0x3FFFFFFFFFFFFFFF
71
+ */
72
+ static inline void
73
+ write_encoded_int(uint64_t num, FILE* fptr)
74
+ {
75
+ if (num == (num & 0x3F)) {
76
+ uint8_t encoded_num = (num << 2) | TS_6_BIT;
77
+ fwrite(&encoded_num, sizeof(uint8_t), 1, fptr);
78
+ } else if (num == (num & 0x3FFF)) {
79
+ uint16_t encoded_num = (num << 2) | TS_14_BIT;
80
+ fwrite(&encoded_num, sizeof(uint16_t), 1, fptr);
81
+ } else if (num == (num & 0x3FFFFFFF)) {
82
+ uint32_t encoded_num = (num << 2) | TS_30_BIT;
83
+ fwrite(&encoded_num, sizeof(uint32_t), 1, fptr);
84
+ } else {
85
+ uint64_t encoded_num = (num << 2) | TS_62_BIT;
86
+ fwrite(&encoded_num, sizeof(uint64_t), 1, fptr);
87
+ }
88
+ }
89
+
90
+ static inline int
91
+ read_encoded_int(uint64_t *num, FILE* fptr)
92
+ {
93
+ uint8_t flag;
94
+ uint8_t encoded_num_8_bit = 0;
95
+ uint16_t encoded_num_16_bit = 0;
96
+ uint32_t encoded_num_32_bit = 0;
97
+ uint64_t encoded_num_64_bit = 0;
98
+ PEEK_DATA(&flag, uint8_t, fptr)
99
+ switch (flag & 0x03)
100
+ {
101
+ case TS_6_BIT:
102
+ READ_DATA(&encoded_num_8_bit, uint8_t, fptr)
103
+ (*num) = encoded_num_8_bit >> 2;
104
+ break;
105
+ case TS_14_BIT:
106
+ READ_DATA(&encoded_num_16_bit, uint16_t, fptr)
107
+ (*num) = encoded_num_16_bit >> 2;
108
+ break;
109
+ case TS_30_BIT:
110
+ READ_DATA(&encoded_num_32_bit, uint32_t, fptr)
111
+ (*num) = encoded_num_32_bit >> 2;
112
+ break;
113
+ case TS_62_BIT:
114
+ READ_DATA(&encoded_num_64_bit, uint64_t, fptr)
115
+ (*num) = encoded_num_64_bit >> 2;
116
+ break;
117
+ default:
118
+ break;
119
+ }
120
+ clean_exit:
121
+ if (PyErr_Occurred()) {
122
+ return 1;
123
+ }
124
+ return 0;
125
+ }
126
+
127
+
128
+ int
129
+ freadstrn(char* buffer, int n, FILE* fptr)
130
+ {
131
+ int c;
132
+ int idx = 0;
133
+ while (1) {
134
+ c = fgetc(fptr);
135
+ if (c == EOF || c == '\0') {
136
+ buffer[idx++] = '\0';
137
+ break;
138
+ } else {
139
+ buffer[idx++] = c;
140
+ }
141
+ if (idx == n) {
142
+ break;
143
+ }
144
+ }
145
+ return idx;
146
+ }
147
+
148
+ char*
149
+ freadstr(FILE* fptr)
150
+ {
151
+ char* str = NULL;
152
+ int c = 0;
153
+ size_t len = 256;
154
+ size_t idx = 0;
155
+ str = malloc(len * sizeof(char));
156
+ if (str == NULL) {
157
+ return NULL;
158
+ }
159
+ while ((c = fgetc(fptr)) != EOF && c != '\0') {
160
+ str[idx++] = c;
161
+ if (idx == len) {
162
+ len *= 2;
163
+ str = realloc(str, len * sizeof(char));
164
+ if (str == NULL) {
165
+ return NULL;
166
+ }
167
+ }
168
+ }
169
+ str[idx++] = '\0';
170
+ return str;
171
+ }
172
+
173
+ int
174
+ dump_metadata(FILE* fptr)
175
+ {
176
+ uint64_t version = VCOMPRESSOR_VERSION;
177
+ if (!fptr) {
178
+ return -1;
179
+ }
180
+
181
+ fwrite(&version, 1, sizeof(uint64_t), fptr);
182
+
183
+ return 0;
184
+ }
185
+
186
+
187
+ PyObject*
188
+ json_dumps_to_bytes(PyObject* json_data)
189
+ {
190
+ PyObject* json_ret = NULL;
191
+ PyObject* bytes_data = NULL;
192
+ PyObject* dumps_func = NULL;
193
+
194
+ if (!json_data) {
195
+ PyErr_SetString(PyExc_ValueError, "json_data can not be NULL");
196
+ goto clean_exit;
197
+ }
198
+ dumps_func = PyObject_GetAttrString(json_module, "dumps");
199
+ if (!dumps_func) {
200
+ goto clean_exit;
201
+ }
202
+
203
+ // json dumps json_data
204
+ json_ret = PyObject_CallOneArg(dumps_func, json_data);
205
+ if (!json_ret) {
206
+ goto clean_exit;
207
+ }
208
+
209
+ // convert string to bytes
210
+ bytes_data = PyObject_CallMethod(json_ret, "encode", NULL);
211
+ Py_DECREF(json_ret);
212
+ if (!bytes_data) {
213
+ goto clean_exit;
214
+ }
215
+ if (!PyBytes_Check(bytes_data)) {
216
+ // need to release bytes_data here, bytes_data will not release after clean_exit
217
+ Py_DECREF(bytes_data);
218
+ PyErr_SetString(PyExc_ValueError, "Failed to convert string to bytes");
219
+ goto clean_exit;
220
+ }
221
+
222
+ clean_exit:
223
+ Py_XDECREF(dumps_func);
224
+
225
+ if (PyErr_Occurred()) {
226
+ return NULL;
227
+ }
228
+
229
+ return bytes_data;
230
+ }
231
+
232
+
233
+ PyObject*
234
+ json_loads_from_bytes(PyObject* bytes_data)
235
+ {
236
+ PyObject* loads_func = NULL;
237
+ PyObject* string_data = NULL;
238
+ PyObject* json_data = NULL;
239
+
240
+ if (!PyBytes_Check(bytes_data)) {
241
+ Py_DECREF(bytes_data);
242
+ PyErr_SetString(PyExc_ValueError, "expect a bytes object to decode");
243
+ goto clean_exit;
244
+ }
245
+
246
+ loads_func = PyObject_GetAttrString(json_module, "loads");
247
+ if (!loads_func) {
248
+ goto clean_exit;
249
+ }
250
+
251
+ // decode depressed bytes to string
252
+ string_data = PyObject_CallMethod(bytes_data, "decode", NULL);
253
+ if (!string_data) {
254
+ goto clean_exit;
255
+ }
256
+
257
+ // convert string to json
258
+ json_data = PyObject_CallOneArg(loads_func, string_data);
259
+ if (!json_data) {
260
+ goto clean_exit;
261
+ }
262
+
263
+ clean_exit:
264
+ Py_XDECREF(loads_func);
265
+
266
+ if (PyErr_Occurred()) {
267
+ return NULL;
268
+ }
269
+
270
+ return json_data;
271
+ }
272
+
273
+
274
+ PyObject*
275
+ compress_bytes(PyObject* bytes_data)
276
+ {
277
+ PyObject* compress_func = NULL;
278
+ PyObject* compressed_data = NULL;
279
+
280
+ if (!PyBytes_Check(bytes_data)) {
281
+ Py_DECREF(bytes_data);
282
+ PyErr_SetString(PyExc_ValueError, "expect a bytes object to compress");
283
+ goto clean_exit;
284
+ }
285
+
286
+ compress_func = PyObject_GetAttrString(zlib_module, "compress");
287
+ if (!compress_func) {
288
+ goto clean_exit;
289
+ }
290
+
291
+ compressed_data = PyObject_CallOneArg(compress_func, bytes_data);
292
+ if (!compressed_data) {
293
+ goto clean_exit;
294
+ }
295
+ if (!PyBytes_Check(compressed_data)) {
296
+ Py_DECREF(compressed_data);
297
+ PyErr_SetString(PyExc_ValueError, "zlib.compress() returns a none bytes object");
298
+ goto clean_exit;
299
+ }
300
+
301
+ clean_exit:
302
+ Py_XDECREF(compress_func);
303
+
304
+ if (PyErr_Occurred()) {
305
+ return NULL;
306
+ }
307
+
308
+ return compressed_data;
309
+ }
310
+
311
+
312
+ PyObject*
313
+ decompress_bytes(PyObject* bytes_data)
314
+ {
315
+ // decompress data
316
+ PyObject* decompressed_data = NULL;
317
+ PyObject* decompress_func = NULL;
318
+
319
+ if (!PyBytes_Check(bytes_data)) {
320
+ Py_DECREF(bytes_data);
321
+ PyErr_SetString(PyExc_ValueError, "expect a bytes object to decompress");
322
+ goto clean_exit;
323
+ }
324
+
325
+ decompress_func = PyObject_GetAttrString(zlib_module, "decompress");
326
+ if (!decompress_func) {
327
+ goto clean_exit;
328
+ }
329
+
330
+ decompressed_data = PyObject_CallOneArg(decompress_func, bytes_data);
331
+ if (!decompressed_data) {
332
+ goto clean_exit;
333
+ }
334
+ if (!PyBytes_Check(decompressed_data)) {
335
+ Py_DECREF(decompressed_data);
336
+ PyErr_SetString(PyExc_ValueError, "zlib.decompress() returns a none bytes object");
337
+ goto clean_exit;
338
+ }
339
+ clean_exit:
340
+ Py_XDECREF(decompress_func);
341
+
342
+ if (PyErr_Occurred()) {
343
+ return NULL;
344
+ }
345
+
346
+ return decompressed_data;
347
+ }
348
+
349
+
350
+ int
351
+ json_dumps_and_compress_to_file(PyObject* json_data, FILE* fptr)
352
+ {
353
+ char* buffer;
354
+ uint64_t uncompressed_size = 0;
355
+ uint64_t compressed_size = 0;
356
+ PyObject* bytes_data = NULL;
357
+ PyObject* compressed_data = NULL;
358
+
359
+ bytes_data = json_dumps_to_bytes(json_data);
360
+ if (!bytes_data) {
361
+ goto clean_exit;
362
+ }
363
+ uncompressed_size = PyBytes_Size(bytes_data);
364
+ if (NEED_COMPRESS_IN_FILE) {
365
+ compressed_data = compress_bytes(bytes_data);
366
+ if (!compressed_data) {
367
+ goto clean_exit;
368
+ }
369
+ compressed_size = PyBytes_Size(compressed_data);
370
+ buffer = PyBytes_AsString(compressed_data);
371
+ fwrite(&uncompressed_size, sizeof(uint64_t), 1, fptr);
372
+ fwrite(&compressed_size, sizeof(uint64_t), 1, fptr);
373
+ fwrite(buffer, sizeof(char), compressed_size, fptr);
374
+ Py_DECREF(compressed_data);
375
+ } else {
376
+ buffer = PyBytes_AsString(bytes_data);
377
+ fwrite(&uncompressed_size, sizeof(uint64_t), 1, fptr);
378
+ fwrite(buffer, sizeof(char), uncompressed_size, fptr);
379
+ }
380
+
381
+ clean_exit:
382
+ Py_DECREF(bytes_data);
383
+ if (PyErr_Occurred()) {
384
+ return 1;
385
+ }
386
+ return 0;
387
+ }
388
+
389
+
390
+ PyObject*
391
+ json_loads_and_decompress_from_file(FILE* fptr)
392
+ {
393
+ char* buffer = NULL;
394
+ uint64_t compressed_size = 0;
395
+ uint64_t uncompressed_size = 0;
396
+ uint64_t read_length = 0;
397
+ PyObject* json_data = NULL;
398
+ PyObject* compressed_data = NULL;
399
+ PyObject* bytes_data = NULL;
400
+
401
+ if (NEED_COMPRESS_IN_FILE) {
402
+ READ_DATA(&uncompressed_size, uint64_t, fptr)
403
+ READ_DATA(&compressed_size, uint64_t, fptr)
404
+ buffer = (char *)malloc(sizeof(char)*compressed_size);
405
+ if (!buffer) {
406
+ PyErr_Format(PyExc_RuntimeError, "Failed to malloc memory size %lld", compressed_size);
407
+ goto clean_exit;
408
+ }
409
+ read_length = fread(buffer, sizeof(char), compressed_size, fptr);
410
+ if (read_length != compressed_size) {
411
+ PyErr_Format(PyExc_ValueError, "file is corrupted");
412
+ free(buffer);
413
+ goto clean_exit;
414
+ }
415
+ compressed_data = PyBytes_FromStringAndSize(buffer, compressed_size);
416
+ free(buffer);
417
+ if (!compressed_data) {
418
+ goto clean_exit;
419
+ }
420
+ bytes_data = decompress_bytes(compressed_data);
421
+ Py_DECREF(compressed_data);
422
+ } else {
423
+ READ_DATA(&uncompressed_size, uint64_t, fptr)
424
+ buffer = (char *)malloc(sizeof(char)*uncompressed_size);
425
+ if (!buffer) {
426
+ PyErr_Format(PyExc_RuntimeError, "Failed to malloc memory size %lld", uncompressed_size);
427
+ goto clean_exit;
428
+ }
429
+ read_length = fread(buffer, sizeof(char), uncompressed_size, fptr);
430
+ if (read_length != uncompressed_size) {
431
+ PyErr_Format(PyExc_ValueError, "file is corrupted");
432
+ free(buffer);
433
+ goto clean_exit;
434
+ }
435
+ bytes_data = PyBytes_FromStringAndSize(buffer, uncompressed_size);
436
+ free(buffer);
437
+ }
438
+
439
+ if (!bytes_data) {
440
+ goto clean_exit;
441
+ }
442
+ json_data = json_loads_from_bytes(bytes_data);
443
+ Py_DECREF(bytes_data);
444
+ if (!json_data) {
445
+ goto clean_exit;
446
+ }
447
+
448
+ clean_exit:
449
+
450
+ if (PyErr_Occurred()) {
451
+ return NULL;
452
+ }
453
+ return json_data;
454
+ }
455
+
456
+
457
+ int
458
+ dump_parsed_trace_events(PyObject* trace_events, FILE* fptr)
459
+ {
460
+ // Dump process and thread names
461
+ PyObject* process_names = PyDict_GetItemString(trace_events, "process_names");
462
+ PyObject* thread_names = PyDict_GetItemString(trace_events, "thread_names");
463
+ PyObject* fee_events = PyDict_GetItemString(trace_events, "fee_events");
464
+ PyObject* counter_events = PyDict_GetItemString(trace_events, "counter_events");
465
+ PyObject* other_events = PyDict_GetItemString(trace_events, "other_events");
466
+ Py_ssize_t ppos = 0;
467
+ PyObject* key = NULL;
468
+ PyObject* value = NULL;
469
+
470
+ // Iterate through process names
471
+ ppos = 0;
472
+ while (PyDict_Next(process_names, &ppos, &key, &value)) {
473
+ uint64_t pid = PyLong_AsLong(PyTuple_GetItem(key, 0));
474
+ uint64_t tid = PyLong_AsLong(PyTuple_GetItem(key, 1));
475
+ const char* name = PyUnicode_AsUTF8(value);
476
+ fputc(VC_HEADER_PROCESS_NAME, fptr);
477
+ fwrite(&pid, sizeof(uint64_t), 1, fptr);
478
+ fwrite(&tid, sizeof(uint64_t), 1, fptr);
479
+ fwritestr(name, fptr);
480
+ }
481
+
482
+ // Iterate through thread names
483
+ ppos = 0;
484
+ while (PyDict_Next(thread_names, &ppos, &key, &value)) {
485
+ uint64_t pid = PyLong_AsLong(PyTuple_GetItem(key, 0));
486
+ uint64_t tid = PyLong_AsLong(PyTuple_GetItem(key, 1));
487
+ const char* name = PyUnicode_AsUTF8(value);
488
+ fputc(VC_HEADER_THREAD_NAME, fptr);
489
+ fwrite(&pid, sizeof(uint64_t), 1, fptr);
490
+ fwrite(&tid, sizeof(uint64_t), 1, fptr);
491
+ fwritestr(name, fptr);
492
+ }
493
+
494
+ // Iterate through fee events
495
+ ppos = 0;
496
+ while (PyDict_Next(fee_events, &ppos, &key, &value)) {
497
+ if (write_fee_events(key, value, fptr) != 0){
498
+ goto clean_exit;
499
+ }
500
+ }
501
+
502
+ // Iterate through counter events
503
+ ppos = 0;
504
+ while (PyDict_Next(counter_events, &ppos, &key, &value)) {
505
+ uint64_t pid = PyLong_AsLong(PyTuple_GetItem(key, 0));
506
+ uint64_t tid = PyLong_AsLong(PyTuple_GetItem(key, 1));
507
+ const char* name = PyUnicode_AsUTF8(PyTuple_GetItem(key, 2));
508
+ fputc(VC_HEADER_COUNTER_EVENTS, fptr);
509
+ fwrite(&pid, sizeof(uint64_t), 1, fptr);
510
+ fwrite(&tid, sizeof(uint64_t), 1, fptr);
511
+ fwritestr(name, fptr);
512
+ if (diff_and_write_counter_args(value, fptr) != 0) {
513
+ goto clean_exit;
514
+ }
515
+ }
516
+
517
+ // just write other events
518
+ fputc(VC_HEADER_OTHER_EVENTS, fptr);
519
+ if (json_dumps_and_compress_to_file(other_events, fptr) != 0) {
520
+ goto clean_exit;
521
+ }
522
+ clean_exit:
523
+ if (PyErr_Occurred()) {
524
+ return 1;
525
+ }
526
+
527
+ return 0;
528
+ }
529
+
530
+
531
+ int
532
+ write_fee_events(PyObject* fee_key, PyObject* fee_value, FILE* fptr) {
533
+ PyObject* args_list = NULL;
534
+ uint64_t pid = PyLong_AsLong(PyTuple_GetItem(fee_key, 0));
535
+ uint64_t tid = PyLong_AsLong(PyTuple_GetItem(fee_key, 1));
536
+ uint64_t ts_size = PyList_GET_SIZE(fee_value);
537
+ uint64_t args_offset = 0;
538
+ int64_t last_ts = 0;
539
+ const char* name = PyUnicode_AsUTF8(PyTuple_GetItem(fee_key, 2));
540
+ int place_holder = 0;
541
+ fputc(VC_HEADER_FEE, fptr);
542
+ fwrite(&pid, sizeof(uint64_t), 1, fptr);
543
+ fwrite(&tid, sizeof(uint64_t), 1, fptr);
544
+ fwritestr(name, fptr);
545
+ fwrite(&ts_size, sizeof(uint64_t), 1, fptr);
546
+ if (!PyObject_CallMethod(fee_value, "sort", NULL)) {
547
+ goto clean_exit;
548
+ }
549
+ // write place holder for args offset
550
+ place_holder = ftell(fptr);
551
+ fwrite(&args_offset, sizeof(uint64_t), 1, fptr);
552
+ if (PyTuple_GetItem(fee_key, 3) == Py_True) {
553
+ args_list = PyList_New(0);
554
+ }
555
+ for (Py_ssize_t idx = 0; idx < (Py_ssize_t)ts_size; idx++) {
556
+ PyObject * event_ts_tuple = PyList_GET_ITEM(fee_value, idx);
557
+ double ts = PyFloat_AsDouble(PyTuple_GET_ITEM(event_ts_tuple, 0));
558
+ double dur = PyFloat_AsDouble(PyTuple_GET_ITEM(event_ts_tuple, 1));
559
+ int64_t ts64 = ts * 100;
560
+ uint64_t dur64 = dur * 100;
561
+ uint64_t delta_ts = ts64 - last_ts;
562
+ last_ts = ts64;
563
+ if (idx == 0) {
564
+ // write the first timestamp as int64_t, for timestamp on windows may be negative
565
+ fwrite(&ts64, sizeof(int64_t), 1, fptr);
566
+ } else {
567
+ write_encoded_int(delta_ts, fptr);
568
+ }
569
+ write_encoded_int(dur64, fptr);
570
+ if (args_list) {
571
+ PyList_Append(args_list, PyTuple_GET_ITEM(event_ts_tuple, 2));
572
+ }
573
+ }
574
+
575
+ if (args_list) {
576
+ args_offset = ftell(fptr);
577
+ fseek(fptr, place_holder, SEEK_SET);
578
+ fwrite(&args_offset, sizeof(args_offset), 1, fptr);
579
+ fseek(fptr, args_offset, SEEK_SET);
580
+ if (json_dumps_and_compress_to_file(args_list, fptr) != 0) {
581
+ goto clean_exit;
582
+ }
583
+ }
584
+
585
+ clean_exit:
586
+ Py_XDECREF(args_list);
587
+
588
+ if (PyErr_Occurred()) {
589
+ return 1;
590
+ }
591
+ return 0;
592
+ }
593
+
594
+
595
+ PyObject*
596
+ load_fee_events(FILE* fptr) {
597
+ uint64_t pid = 0;
598
+ uint64_t tid = 0;
599
+ uint64_t count = 0;
600
+ uint64_t dur = 0;
601
+ uint64_t delta_ts = 0;
602
+ uint64_t args_offset = 0;
603
+ uint64_t place_holder_ts = 0;
604
+ uint64_t place_holder_end = 0;
605
+ int64_t last_ts = 0;
606
+ char buffer[STRING_BUFFER_SIZE] = {0};
607
+ PyObject* fee_events_list = PyList_New(0);
608
+ PyObject* event = NULL;
609
+ PyObject* name = NULL;
610
+ PyObject* args_list = NULL;
611
+ PyObject* unicode_X = PyUnicode_FromString("X");
612
+ PyObject* unicode_FEE = PyUnicode_FromString("FEE");
613
+
614
+ READ_DATA(&pid, uint64_t, fptr);
615
+ READ_DATA(&tid, uint64_t, fptr);
616
+ freadstrn(buffer, STRING_BUFFER_SIZE - 1, fptr);
617
+ READ_DATA(&count, uint64_t, fptr);
618
+ name = PyUnicode_FromString(buffer);
619
+ READ_DATA(&args_offset, uint64_t, fptr);
620
+ if (args_offset != 0) {
621
+ // read fee args
622
+ place_holder_ts = ftell(fptr);
623
+ if (fseek(fptr, args_offset, SEEK_SET) != 0) {
624
+ PyErr_SetString(PyExc_ValueError, "seek to args offset failed!");
625
+ goto clean_exit;
626
+ }
627
+ args_list = json_loads_and_decompress_from_file(fptr);
628
+ if (!args_list) {
629
+ goto clean_exit;
630
+ }
631
+ // There's error checking in PyList_Size
632
+ if (PyList_Size(args_list) != (Py_ssize_t)count) {
633
+ PyErr_SetString(PyExc_ValueError, "args length is not equal to count!");
634
+ goto clean_exit;
635
+ }
636
+ place_holder_end = ftell(fptr);
637
+ fseek(fptr, place_holder_ts, SEEK_SET);
638
+ }
639
+
640
+ for (uint64_t i = 0; i < count; i++) {
641
+ if (i == 0) {
642
+ READ_DATA(&last_ts, int64_t, fptr);
643
+ } else {
644
+ if (read_encoded_int(&delta_ts, fptr) != 0) {
645
+ goto clean_exit;
646
+ }
647
+ }
648
+ if (read_encoded_int(&dur, fptr) != 0) {
649
+ goto clean_exit;
650
+ }
651
+ event = PyDict_New();
652
+ PyDict_SetItemString(event, "ph", unicode_X);
653
+ PyDict_SetItemString(event, "name", name);
654
+ PyDict_SetItemString(event, "cat", unicode_FEE);
655
+ PyDict_SetItemStringULL(event, "pid", pid);
656
+ PyDict_SetItemStringULL(event, "tid", tid);
657
+ last_ts = delta_ts + last_ts;
658
+ PyDict_SetItemStringDouble(event, "ts", (double)last_ts / 100);
659
+ PyDict_SetItemStringDouble(event, "dur", (double)dur / 100);
660
+ if (args_list) {
661
+ PyDict_SetItemString(event, "args", PyList_GET_ITEM(args_list, i));
662
+ }
663
+ PyList_Append(fee_events_list, event);
664
+ Py_DECREF(event);
665
+ }
666
+ if (args_list) {
667
+ fseek(fptr, place_holder_end, SEEK_SET);
668
+ }
669
+
670
+ clean_exit:
671
+ Py_XDECREF(name);
672
+ Py_XDECREF(args_list);
673
+ Py_DECREF(unicode_X);
674
+ Py_DECREF(unicode_FEE);
675
+
676
+ if (PyErr_Occurred()) {
677
+ return NULL;
678
+ }
679
+
680
+ return fee_events_list;
681
+ }
682
+
683
+
684
+ int
685
+ diff_and_write_counter_args(PyObject* counter_args, FILE* fptr) {
686
+ /* there may be several args in a counter, log them all may take more spaces
687
+ * so this step is to do diffing between two contiguous timestamp
688
+ * and finally we only log those changed args
689
+ * Here's a counter_args example that we parsed
690
+ * {
691
+ * 1.1: {"a": 20, "b": 10}
692
+ * 2.2: {"a": 30, "b": 10}
693
+ * }
694
+ * In this case, "b" value is not changed, so we only need to log
695
+ * {
696
+ * 1.1: {"a": 20, "b": 10}
697
+ * 2.2: {"a": 30}
698
+ * }
699
+ */
700
+ PyObject* cached_args_dict = PyDict_New();
701
+ PyObject* diffed_args = PyDict_New();
702
+ PyObject* ts_keys = PyDict_Keys(counter_args);
703
+ PyObject* ts = NULL;
704
+ PyObject* cur_diffed_arg = NULL;
705
+ PyObject* cur_counter_arg = NULL;
706
+ PyObject* arg_key_list = NULL;
707
+ PyObject* counter_arg_key = NULL;
708
+ PyObject* counter_arg_value = NULL;
709
+ PyObject* cached_arg_value = NULL;
710
+ PyObject* overflowed_num_string = NULL;
711
+ Py_ssize_t ppos = 0;
712
+ uint64_t ts_key_count = 0;
713
+ uint64_t arg_nums = 0;
714
+ // sort the args by timestamp so we can diff
715
+ if (!ts_keys || !PyList_Check(ts_keys)) {
716
+ PyErr_SetString(PyExc_ValueError, "failed to get timestamp list");
717
+ goto clean_exit;
718
+ }
719
+ ts_key_count = PyList_GET_SIZE(ts_keys);
720
+ if (PyList_Sort(ts_keys) == -1) {
721
+ goto clean_exit;
722
+ }
723
+ /* Do diffing between two timestamps and store the result.
724
+ * In this for loop, we iterate all the counter_args by the sort of timestamp.
725
+ * And we mainly have three variables used to do the diffing:
726
+ * cur_counter_arg: the full args of this timestamp
727
+ * cached_args_dict: the full args of last timestamp
728
+ * cur_diffed_arg: diffed result between cached_args_dict and cur_counter_arg
729
+ */
730
+ for (uint64_t i = 0; i < ts_key_count; i++) {
731
+ ts = PyList_GET_ITEM(ts_keys, i);
732
+ cur_counter_arg = PyDict_GetItem(counter_args, ts);
733
+ cur_diffed_arg = PyDict_New();
734
+ ppos = 0;
735
+ /* This while statement is to find the different arg between cur_counter_arg and cached_args_dict.
736
+ * It will iterate the arg value of cur_counter_arg, and compare with the value in cached_args_dict.
737
+ * If the value is same, just ignore this value
738
+ * If the value is different, then store it in cur_diffed_arg and update it in cached_args_dict.
739
+ */
740
+ while (PyDict_Next(cur_counter_arg, &ppos, &counter_arg_key, &counter_arg_value)) {
741
+ cached_arg_value = PyDict_GetItem(cached_args_dict, counter_arg_key);
742
+ if (!cached_arg_value) {
743
+ PyDict_SetItem(cached_args_dict, counter_arg_key, counter_arg_value);
744
+ PyDict_SetItem(cur_diffed_arg, counter_arg_key, counter_arg_value);
745
+ } else {
746
+ int compare_result = PyObject_RichCompareBool(cached_arg_value, counter_arg_value, Py_EQ);
747
+ if (compare_result == -1) {
748
+ // compare error
749
+ goto clean_exit;
750
+ } else if (compare_result == 0) {
751
+ // if value is not equal in last timestamp, store the newest value
752
+ PyDict_SetItem(cached_args_dict, counter_arg_key, counter_arg_value);
753
+ PyDict_SetItem(cur_diffed_arg, counter_arg_key, counter_arg_value);
754
+ }
755
+ }
756
+ }
757
+ ppos = 0;
758
+ /* This while statement is to find the arg that is in cached_args_dict but not in cur_counter_arg.
759
+ * Considering the situation that an arg is deleted at some timestamp, for example:
760
+ * {
761
+ * 1.1: {"a": 20, "b": 10}
762
+ * 2.2: {"a": 20}
763
+ * }
764
+ * In this case, we need to mark b value as UNKNOWN at timestamp 2.2
765
+ * This step is to iterate arg in cached_args_dict and determine if the arg is in cur_counter_arg
766
+ * Normally, the value of counter_arg is always numeric
767
+ * So we use Py_None to mark the value as UNKNOWN
768
+ */
769
+ while (PyDict_Next(cached_args_dict, &ppos, &counter_arg_key, &cached_arg_value)) {
770
+ counter_arg_value = PyDict_GetItem(cur_counter_arg, counter_arg_key);
771
+ if (!counter_arg_value && cached_arg_value != Py_None) {
772
+ PyDict_SetItem(cached_args_dict, counter_arg_key, Py_None);
773
+ PyDict_SetItem(cur_diffed_arg, counter_arg_key, Py_None);
774
+ }
775
+ }
776
+ PyDict_SetItem(diffed_args, ts, cur_diffed_arg);
777
+ Py_DECREF(cur_diffed_arg);
778
+ }
779
+ // write all the arg keys
780
+ // write the number of timestamp of this counter
781
+ arg_nums = PyDict_Size(cached_args_dict);
782
+ fwrite(&arg_nums, sizeof(uint64_t), 1, fptr);
783
+ arg_key_list = PyDict_Keys(cached_args_dict);
784
+ if (!arg_key_list) {
785
+ PyErr_SetString(PyExc_ValueError, "failed to get arg name list");
786
+ goto clean_exit;
787
+ }
788
+ // write all the name for all arguments appeared
789
+ for (uint64_t i = 0; i < arg_nums; i++) {
790
+ const char * key_name = NULL;
791
+ counter_arg_key = PyList_GetItem(arg_key_list, i);
792
+ key_name = PyUnicode_AsUTF8(counter_arg_key);
793
+ fwritestr(key_name, fptr);
794
+ }
795
+ // write [timestamp - values] * ts_key_count
796
+ fwrite(&ts_key_count, sizeof(uint64_t), 1, fptr);
797
+ for (uint64_t i = 0; i < ts_key_count; i++) {
798
+ double ts_double = 0;
799
+ int64_t ts_64 = 0;
800
+ ts = PyList_GET_ITEM(ts_keys, i);
801
+ cur_diffed_arg = PyDict_GetItem(diffed_args, ts);
802
+ ts_double = PyFloat_AsDouble(ts);
803
+ ts_64 = ts_double * 1000;
804
+ fwrite(&ts_64, sizeof(int64_t), 1, fptr);
805
+ for (uint64_t j = 0; j < arg_nums; j++) {
806
+ counter_arg_value = PyDict_GetItem(cur_diffed_arg, PyList_GET_ITEM(arg_key_list, j));
807
+ if (!counter_arg_value) {
808
+ fputc(VC_HEADER_COUNTER_ARG_SAME, fptr);
809
+ } else if (PyLong_CheckExact(counter_arg_value)) {
810
+ // if PyLongObject is overflowed, just store the string
811
+ int overflow = 0;
812
+ int64_t counter_value_int64 = PyLong_AsLongLongAndOverflow(counter_arg_value, &overflow);
813
+ if (overflow == 0) {
814
+ fputc(VC_HEADER_COUNTER_ARG_LONG, fptr);
815
+ fwrite(&counter_value_int64, sizeof(int64_t), 1, fptr);
816
+ } else {
817
+ const char * num_string = NULL;
818
+ overflowed_num_string = PyObject_Repr(counter_arg_value);
819
+ num_string = PyUnicode_AsUTF8(overflowed_num_string);
820
+ fputc(VC_HEADER_COUNTER_ARG_LONG_STRING, fptr);
821
+ fwritestr(num_string, fptr);
822
+ Py_DECREF(overflowed_num_string);
823
+ }
824
+ } else if (PyFloat_CheckExact(counter_arg_value)) {
825
+ double counter_value_double = PyFloat_AsDouble(counter_arg_value);
826
+ fputc(VC_HEADER_COUNTER_ARG_FLOAT, fptr);
827
+ fwrite(&counter_value_double, sizeof(double), 1, fptr);
828
+ } else if (counter_arg_value == Py_None) {
829
+ fputc(VC_HEADER_COUNTER_ARG_UNKNOWN, fptr);
830
+ } else {
831
+ PyErr_SetString(PyExc_ValueError, "Counter can only take numeric values");
832
+ goto clean_exit;
833
+ }
834
+ }
835
+ }
836
+
837
+ clean_exit:
838
+ Py_XDECREF(arg_key_list);
839
+ Py_XDECREF(ts_keys);
840
+ Py_DECREF(cached_args_dict);
841
+ Py_DECREF(diffed_args);
842
+
843
+ if (PyErr_Occurred()) {
844
+ return 1;
845
+ }
846
+
847
+ return 0;
848
+ }
849
+
850
+ PyObject*
851
+ load_counter_event(FILE* fptr)
852
+ {
853
+ PyObject* counter_events_list = PyList_New(0);
854
+ PyObject* arg_key_list = PyList_New(0);
855
+ PyObject* cached_args = PyDict_New();
856
+ PyObject* counter_ph = PyUnicode_FromString("C");
857
+ PyObject* counter_event = NULL;
858
+ PyObject* current_arg = NULL;
859
+ PyObject* counter_arg_key = NULL;
860
+ PyObject* counter_arg_value = NULL;
861
+ PyObject* counter_name = NULL;
862
+ PyObject* counter_pid = NULL;
863
+ PyObject* counter_tid = NULL;
864
+ uint64_t pid = 0;
865
+ uint64_t tid = 0;
866
+ uint64_t arg_key_count = 0;
867
+ uint64_t counter_event_count = 0;
868
+ int64_t ts_64 = 0;
869
+ uint8_t header = 0;
870
+ int64_t value_longlong = 0;
871
+ double value_double = 0;
872
+ char buffer[STRING_BUFFER_SIZE] = {0};
873
+ char* string_value = NULL;
874
+ char* name = NULL;
875
+
876
+ // read pid, tid, name and keys
877
+ READ_DATA(&pid, uint64_t, fptr);
878
+ READ_DATA(&tid, uint64_t, fptr);
879
+ name = freadstr(fptr);
880
+ READ_DATA(&arg_key_count, uint64_t, fptr);
881
+ counter_name = PyUnicode_FromString(name);
882
+ free(name);
883
+ counter_pid = PyLong_FromUnsignedLongLong(pid);
884
+ counter_tid = PyLong_FromUnsignedLongLong(tid);
885
+ for (uint64_t i = 0; i < arg_key_count; i++) {
886
+ freadstrn(buffer, STRING_BUFFER_SIZE - 1, fptr);
887
+ counter_arg_key = PyUnicode_FromString(buffer);
888
+ PyList_Append(arg_key_list, counter_arg_key);
889
+ Py_DECREF(counter_arg_key);
890
+ }
891
+
892
+ // read counter events
893
+ // cached_args stores the newest value
894
+ // current_arg stores the counter arg of current timestamp
895
+ READ_DATA(&counter_event_count, uint64_t, fptr);
896
+ for (uint64_t i = 0; i < counter_event_count; i++) {
897
+ current_arg = PyDict_New();
898
+ READ_DATA(&ts_64, int64_t, fptr);
899
+ for (uint64_t j = 0; j < arg_key_count; j++) {
900
+ READ_DATA(&header, uint8_t, fptr);
901
+ counter_arg_key = PyList_GetItem(arg_key_list, j);
902
+ // counter arg not change means current value is same with it in last arg
903
+ // so we need to read it from cached_args
904
+ // other state means current value is different from it in last arg
905
+ // so we need to read it from file and save it in cached_args
906
+ switch (header)
907
+ {
908
+ case VC_HEADER_COUNTER_ARG_UNKNOWN:
909
+ PyDict_SetItem(cached_args, counter_arg_key, Py_None);
910
+ break;
911
+ case VC_HEADER_COUNTER_ARG_SAME:
912
+ counter_arg_value = PyDict_GetItem(cached_args, counter_arg_key);
913
+ if (counter_arg_value && counter_arg_value != Py_None) {
914
+ PyDict_SetItem(current_arg, counter_arg_key, counter_arg_value);
915
+ }
916
+ break;
917
+ case VC_HEADER_COUNTER_ARG_LONG:
918
+ READ_DATA(&value_longlong, int64_t, fptr);
919
+ counter_arg_value = PyLong_FromLongLong(value_longlong);
920
+ PyDict_SetItem(current_arg, counter_arg_key, counter_arg_value);
921
+ PyDict_SetItem(cached_args, counter_arg_key, counter_arg_value);
922
+ Py_DECREF(counter_arg_value);
923
+ break;
924
+ case VC_HEADER_COUNTER_ARG_FLOAT:
925
+ READ_DATA(&value_double, double, fptr);
926
+ counter_arg_value = PyFloat_FromDouble(value_double);
927
+ PyDict_SetItem(current_arg, counter_arg_key, counter_arg_value);
928
+ PyDict_SetItem(cached_args, counter_arg_key, counter_arg_value);
929
+ Py_DECREF(counter_arg_value);
930
+ break;
931
+ case VC_HEADER_COUNTER_ARG_LONG_STRING:
932
+ string_value = freadstr(fptr);
933
+ counter_arg_value = PyLong_FromString(string_value, NULL, 0);
934
+ free(string_value);
935
+ PyDict_SetItem(current_arg, counter_arg_key, counter_arg_value);
936
+ PyDict_SetItem(cached_args, counter_arg_key, counter_arg_value);
937
+ Py_DECREF(counter_arg_value);
938
+ break;
939
+ default:
940
+ PyErr_SetString(PyExc_ValueError, "counter arg header error!");
941
+ goto clean_exit;
942
+ }
943
+ }
944
+ counter_event = PyDict_New();
945
+ PyList_Append(counter_events_list, counter_event);
946
+ Py_DECREF(counter_event);
947
+ PyDict_SetItemString(counter_event, "name", counter_name);
948
+ PyDict_SetItemString(counter_event, "pid", counter_pid);
949
+ PyDict_SetItemString(counter_event, "tid", counter_tid);
950
+ PyDict_SetItemString(counter_event, "ph", counter_ph);
951
+ PyDict_SetItemString(counter_event, "args", current_arg);
952
+ Py_DECREF(current_arg);
953
+ PyDict_SetItemStringDouble(counter_event, "ts", (double)ts_64 / 1000);
954
+ }
955
+
956
+ clean_exit:
957
+ if (counter_name) {
958
+ Py_DECREF(counter_name);
959
+ }
960
+ if (counter_pid) {
961
+ Py_DECREF(counter_pid);
962
+ }
963
+ if (counter_tid) {
964
+ Py_DECREF(counter_tid);
965
+ }
966
+
967
+ Py_DECREF(counter_ph);
968
+ Py_DECREF(arg_key_list);
969
+ Py_DECREF(cached_args);
970
+
971
+ if (PyErr_Occurred()) {
972
+ Py_DECREF(counter_events_list);
973
+ return NULL;
974
+ }
975
+
976
+ return counter_events_list;
977
+ }
978
+
979
+ PyObject*
980
+ load_events_from_file(FILE* fptr)
981
+ {
982
+ uint64_t version = 0;
983
+ uint8_t header = 0;
984
+ PyObject* parsed_events = PyDict_New();
985
+ PyObject* trace_events = PyList_New(0);
986
+ PyObject* file_info = NULL;
987
+ PyObject* name = NULL;
988
+ PyObject* event = NULL;
989
+ PyObject* counter_events = NULL;
990
+ PyObject* fee_events = NULL;
991
+ PyObject* other_events = NULL;
992
+ uint64_t pid = 0;
993
+ uint64_t tid = 0;
994
+ PyObject* args = NULL;
995
+ PyObject* unicode_X = PyUnicode_FromString("X");
996
+ PyObject* unicode_M = PyUnicode_FromString("M");
997
+ PyObject* unicode_FEE = PyUnicode_FromString("FEE");
998
+ PyObject* unicode_process_name = PyUnicode_FromString("process_name");
999
+ PyObject* unicode_thread_name = PyUnicode_FromString("thread_name");
1000
+
1001
+ char buffer[STRING_BUFFER_SIZE] = {0};
1002
+
1003
+ READ_DATA(&version, uint64_t, fptr);
1004
+ if (version != VCOMPRESSOR_VERSION) {
1005
+ Py_DECREF(trace_events);
1006
+ PyErr_SetString(PyExc_ValueError, "VCompressor does not support this version of file");
1007
+ goto clean_exit;
1008
+ }
1009
+
1010
+ PyDict_SetItemString(parsed_events, "traceEvents", trace_events);
1011
+ Py_DECREF(trace_events);
1012
+
1013
+ while (fread(&header, sizeof(uint8_t), 1, fptr)) {
1014
+ switch (header) {
1015
+ case VC_HEADER_PROCESS_NAME:
1016
+ event = PyDict_New();
1017
+ READ_DATA(&pid, uint64_t, fptr);
1018
+ READ_DATA(&tid, uint64_t, fptr);
1019
+ freadstrn(buffer, STRING_BUFFER_SIZE - 1, fptr);
1020
+ name = PyUnicode_FromString(buffer);
1021
+ event = PyDict_New();
1022
+ args = PyDict_New();
1023
+ PyDict_SetItemString(event, "ph", unicode_M);
1024
+ PyDict_SetItemString(event, "name", unicode_process_name);
1025
+ PyDict_SetItemStringULL(event, "pid", pid);
1026
+ PyDict_SetItemStringULL(event, "tid", tid);
1027
+ PyDict_SetItemString(event, "args", args);
1028
+ PyDict_SetItemString(args, "name", name);
1029
+ PyList_Append(trace_events, event);
1030
+ Py_DECREF(name);
1031
+ Py_DECREF(event);
1032
+ Py_DECREF(args);
1033
+ break;
1034
+ case VC_HEADER_THREAD_NAME:
1035
+ event = PyDict_New();
1036
+ READ_DATA(&pid, uint64_t, fptr);
1037
+ READ_DATA(&tid, uint64_t, fptr);
1038
+ freadstrn(buffer, STRING_BUFFER_SIZE - 1, fptr);
1039
+ name = PyUnicode_FromString(buffer);
1040
+ event = PyDict_New();
1041
+ args = PyDict_New();
1042
+ PyDict_SetItemString(event, "ph", unicode_M);
1043
+ PyDict_SetItemString(event, "name", unicode_thread_name);
1044
+ PyDict_SetItemStringULL(event, "pid", pid);
1045
+ PyDict_SetItemStringULL(event, "tid", tid);
1046
+ PyDict_SetItemString(event, "args", args);
1047
+ PyDict_SetItemString(args, "name", name);
1048
+ PyList_Append(trace_events, event);
1049
+ Py_DECREF(name);
1050
+ Py_DECREF(event);
1051
+ Py_DECREF(args);
1052
+ break;
1053
+ case VC_HEADER_FEE:
1054
+ fee_events = load_fee_events(fptr);
1055
+ if (!fee_events) {
1056
+ goto clean_exit;
1057
+ }
1058
+ PyObject_CallMethod(trace_events, "extend", "O", fee_events);
1059
+ Py_DECREF(fee_events);
1060
+ if (PyErr_Occurred()) {
1061
+ goto clean_exit;
1062
+ }
1063
+ break;
1064
+ case VC_HEADER_FILE_INFO:
1065
+ file_info = load_file_info(fptr);
1066
+ if (!file_info) {
1067
+ goto clean_exit;
1068
+ }
1069
+ PyDict_SetItemString(parsed_events, "file_info", file_info);
1070
+ Py_DECREF(file_info);
1071
+ break;
1072
+ case VC_HEADER_COUNTER_EVENTS:
1073
+ counter_events = load_counter_event(fptr);
1074
+ if (!counter_events) {
1075
+ goto clean_exit;
1076
+ }
1077
+ PyObject_CallMethod(trace_events, "extend", "O", counter_events);
1078
+ Py_DECREF(counter_events);
1079
+ if (PyErr_Occurred()) {
1080
+ goto clean_exit;
1081
+ }
1082
+ break;
1083
+ case VC_HEADER_OTHER_EVENTS:
1084
+ other_events = json_loads_and_decompress_from_file(fptr);
1085
+ if (!other_events) {
1086
+ goto clean_exit;
1087
+ }
1088
+ PyObject_CallMethod(trace_events, "extend", "O", other_events);
1089
+ Py_DECREF(other_events);
1090
+ if (PyErr_Occurred()) {
1091
+ goto clean_exit;
1092
+ }
1093
+ break;
1094
+ default:
1095
+ printf("wrong header %d\n", header);
1096
+ }
1097
+ }
1098
+
1099
+ clean_exit:
1100
+ Py_DECREF(unicode_X);
1101
+ Py_DECREF(unicode_M);
1102
+ Py_DECREF(unicode_FEE);
1103
+ Py_DECREF(unicode_process_name);
1104
+ Py_DECREF(unicode_thread_name);
1105
+
1106
+ if (PyErr_Occurred()) {
1107
+ Py_DECREF(parsed_events);
1108
+ return NULL;
1109
+ }
1110
+ return parsed_events;
1111
+
1112
+ }
1113
+
1114
+
1115
+ int
1116
+ dump_file_info(PyObject* file_info, FILE* fptr)
1117
+ {
1118
+ // write data
1119
+ fputc(VC_HEADER_FILE_INFO, fptr);
1120
+ if (json_dumps_and_compress_to_file(file_info, fptr) == 0){
1121
+ return 0;
1122
+ } else {
1123
+ return 1;
1124
+ }
1125
+ }
1126
+
1127
+ PyObject*
1128
+ load_file_info(FILE* fptr)
1129
+ {
1130
+ return json_loads_and_decompress_from_file(fptr);
1131
+ }