Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/auxiliary/driver_trace/tr_dump.c
4565 views
1
/**************************************************************************
2
*
3
* Copyright 2008 VMware, Inc.
4
* All Rights Reserved.
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sub license, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
13
*
14
* The above copyright notice and this permission notice (including the
15
* next paragraph) shall be included in all copies or substantial portions
16
* of the Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
*
26
**************************************************************************/
27
28
29
/**
30
* @file
31
* Trace dumping functions.
32
*
33
* For now we just use standard XML for dumping the trace calls, as this is
34
* simple to write, parse, and visually inspect, but the actual representation
35
* is abstracted out of this file, so that we can switch to a binary
36
* representation if/when it becomes justified.
37
*
38
* @author Jose Fonseca <[email protected]>
39
*/
40
41
#include "pipe/p_config.h"
42
43
#include <stdio.h>
44
#include <stdlib.h>
45
46
/* for access() */
47
#ifdef _WIN32
48
# include <io.h>
49
#endif
50
51
#include "pipe/p_compiler.h"
52
#include "os/os_thread.h"
53
#include "util/os_time.h"
54
#include "util/u_debug.h"
55
#include "util/u_memory.h"
56
#include "util/u_string.h"
57
#include "util/u_math.h"
58
#include "util/format/u_format.h"
59
60
#include "tr_dump.h"
61
#include "tr_screen.h"
62
#include "tr_texture.h"
63
64
65
static bool close_stream = false;
66
static FILE *stream = NULL;
67
static mtx_t call_mutex = _MTX_INITIALIZER_NP;
68
static long unsigned call_no = 0;
69
static bool dumping = false;
70
71
static bool trigger_active = true;
72
static char *trigger_filename = NULL;
73
74
void
75
trace_dump_trigger_active(bool active)
76
{
77
trigger_active = active;
78
}
79
80
void
81
trace_dump_check_trigger(void)
82
{
83
if (!trigger_filename)
84
return;
85
86
mtx_lock(&call_mutex);
87
if (trigger_active) {
88
trigger_active = false;
89
} else {
90
if (!access(trigger_filename, 2 /* W_OK but compiles on Windows */)) {
91
if (!unlink(trigger_filename)) {
92
trigger_active = true;
93
} else {
94
fprintf(stderr, "error removing trigger file\n");
95
trigger_active = false;
96
}
97
}
98
}
99
mtx_unlock(&call_mutex);
100
}
101
102
bool
103
trace_dump_is_triggered(void)
104
{
105
return trigger_active && !!trigger_filename;
106
}
107
108
static inline void
109
trace_dump_write(const char *buf, size_t size)
110
{
111
if (stream && trigger_active) {
112
fwrite(buf, size, 1, stream);
113
}
114
}
115
116
117
static inline void
118
trace_dump_writes(const char *s)
119
{
120
trace_dump_write(s, strlen(s));
121
}
122
123
124
static inline void
125
trace_dump_writef(const char *format, ...)
126
{
127
static char buf[1024];
128
unsigned len;
129
va_list ap;
130
va_start(ap, format);
131
len = vsnprintf(buf, sizeof(buf), format, ap);
132
va_end(ap);
133
trace_dump_write(buf, len);
134
}
135
136
137
static inline void
138
trace_dump_escape(const char *str)
139
{
140
const unsigned char *p = (const unsigned char *)str;
141
unsigned char c;
142
while((c = *p++) != 0) {
143
if(c == '<')
144
trace_dump_writes("&lt;");
145
else if(c == '>')
146
trace_dump_writes("&gt;");
147
else if(c == '&')
148
trace_dump_writes("&amp;");
149
else if(c == '\'')
150
trace_dump_writes("&apos;");
151
else if(c == '\"')
152
trace_dump_writes("&quot;");
153
else if(c >= 0x20 && c <= 0x7e)
154
trace_dump_writef("%c", c);
155
else
156
trace_dump_writef("&#%u;", c);
157
}
158
}
159
160
161
static inline void
162
trace_dump_indent(unsigned level)
163
{
164
unsigned i;
165
for(i = 0; i < level; ++i)
166
trace_dump_writes("\t");
167
}
168
169
170
static inline void
171
trace_dump_newline(void)
172
{
173
trace_dump_writes("\n");
174
}
175
176
177
static inline void
178
trace_dump_tag_begin(const char *name)
179
{
180
trace_dump_writes("<");
181
trace_dump_writes(name);
182
trace_dump_writes(">");
183
}
184
185
static inline void
186
trace_dump_tag_begin1(const char *name,
187
const char *attr1, const char *value1)
188
{
189
trace_dump_writes("<");
190
trace_dump_writes(name);
191
trace_dump_writes(" ");
192
trace_dump_writes(attr1);
193
trace_dump_writes("='");
194
trace_dump_escape(value1);
195
trace_dump_writes("'>");
196
}
197
198
199
static inline void
200
trace_dump_tag_end(const char *name)
201
{
202
trace_dump_writes("</");
203
trace_dump_writes(name);
204
trace_dump_writes(">");
205
}
206
207
void
208
trace_dump_trace_flush(void)
209
{
210
if (stream) {
211
fflush(stream);
212
}
213
}
214
215
static void
216
trace_dump_trace_close(void)
217
{
218
if (stream) {
219
trigger_active = true;
220
trace_dump_writes("</trace>\n");
221
if (close_stream) {
222
fclose(stream);
223
close_stream = false;
224
stream = NULL;
225
}
226
call_no = 0;
227
free(trigger_filename);
228
}
229
}
230
231
232
static void
233
trace_dump_call_time(int64_t time)
234
{
235
if (stream) {
236
trace_dump_indent(2);
237
trace_dump_tag_begin("time");
238
trace_dump_int(time);
239
trace_dump_tag_end("time");
240
trace_dump_newline();
241
}
242
}
243
244
245
bool
246
trace_dump_trace_begin(void)
247
{
248
const char *filename;
249
250
filename = debug_get_option("GALLIUM_TRACE", NULL);
251
if (!filename)
252
return false;
253
254
if (!stream) {
255
256
if (strcmp(filename, "stderr") == 0) {
257
close_stream = false;
258
stream = stderr;
259
}
260
else if (strcmp(filename, "stdout") == 0) {
261
close_stream = false;
262
stream = stdout;
263
}
264
else {
265
close_stream = true;
266
stream = fopen(filename, "wt");
267
if (!stream)
268
return false;
269
}
270
271
trace_dump_writes("<?xml version='1.0' encoding='UTF-8'?>\n");
272
trace_dump_writes("<?xml-stylesheet type='text/xsl' href='trace.xsl'?>\n");
273
trace_dump_writes("<trace version='0.1'>\n");
274
275
/* Many applications don't exit cleanly, others may create and destroy a
276
* screen multiple times, so we only write </trace> tag and close at exit
277
* time.
278
*/
279
atexit(trace_dump_trace_close);
280
281
const char *trigger = debug_get_option("GALLIUM_TRACE_TRIGGER", NULL);
282
if (trigger) {
283
trigger_filename = strdup(trigger);
284
trigger_active = false;
285
} else
286
trigger_active = true;
287
}
288
289
return true;
290
}
291
292
bool trace_dump_trace_enabled(void)
293
{
294
return stream ? true : false;
295
}
296
297
/*
298
* Call lock
299
*/
300
301
void trace_dump_call_lock(void)
302
{
303
mtx_lock(&call_mutex);
304
}
305
306
void trace_dump_call_unlock(void)
307
{
308
mtx_unlock(&call_mutex);
309
}
310
311
/*
312
* Dumping control
313
*/
314
315
void trace_dumping_start_locked(void)
316
{
317
dumping = true;
318
}
319
320
void trace_dumping_stop_locked(void)
321
{
322
dumping = false;
323
}
324
325
bool trace_dumping_enabled_locked(void)
326
{
327
return dumping;
328
}
329
330
void trace_dumping_start(void)
331
{
332
mtx_lock(&call_mutex);
333
trace_dumping_start_locked();
334
mtx_unlock(&call_mutex);
335
}
336
337
void trace_dumping_stop(void)
338
{
339
mtx_lock(&call_mutex);
340
trace_dumping_stop_locked();
341
mtx_unlock(&call_mutex);
342
}
343
344
bool trace_dumping_enabled(void)
345
{
346
bool ret;
347
mtx_lock(&call_mutex);
348
ret = trace_dumping_enabled_locked();
349
mtx_unlock(&call_mutex);
350
return ret;
351
}
352
353
/*
354
* Dump functions
355
*/
356
357
static int64_t call_start_time = 0;
358
359
void trace_dump_call_begin_locked(const char *klass, const char *method)
360
{
361
if (!dumping)
362
return;
363
364
++call_no;
365
trace_dump_indent(1);
366
trace_dump_writes("<call no=\'");
367
trace_dump_writef("%lu", call_no);
368
trace_dump_writes("\' class=\'");
369
trace_dump_escape(klass);
370
trace_dump_writes("\' method=\'");
371
trace_dump_escape(method);
372
trace_dump_writes("\'>");
373
trace_dump_newline();
374
375
call_start_time = os_time_get();
376
}
377
378
void trace_dump_call_end_locked(void)
379
{
380
int64_t call_end_time;
381
382
if (!dumping)
383
return;
384
385
call_end_time = os_time_get();
386
387
trace_dump_call_time(call_end_time - call_start_time);
388
trace_dump_indent(1);
389
trace_dump_tag_end("call");
390
trace_dump_newline();
391
fflush(stream);
392
}
393
394
void trace_dump_call_begin(const char *klass, const char *method)
395
{
396
mtx_lock(&call_mutex);
397
trace_dump_call_begin_locked(klass, method);
398
}
399
400
void trace_dump_call_end(void)
401
{
402
trace_dump_call_end_locked();
403
mtx_unlock(&call_mutex);
404
}
405
406
void trace_dump_arg_begin(const char *name)
407
{
408
if (!dumping)
409
return;
410
411
trace_dump_indent(2);
412
trace_dump_tag_begin1("arg", "name", name);
413
}
414
415
void trace_dump_arg_end(void)
416
{
417
if (!dumping)
418
return;
419
420
trace_dump_tag_end("arg");
421
trace_dump_newline();
422
}
423
424
void trace_dump_ret_begin(void)
425
{
426
if (!dumping)
427
return;
428
429
trace_dump_indent(2);
430
trace_dump_tag_begin("ret");
431
}
432
433
void trace_dump_ret_end(void)
434
{
435
if (!dumping)
436
return;
437
438
trace_dump_tag_end("ret");
439
trace_dump_newline();
440
}
441
442
void trace_dump_bool(int value)
443
{
444
if (!dumping)
445
return;
446
447
trace_dump_writef("<bool>%c</bool>", value ? '1' : '0');
448
}
449
450
void trace_dump_int(long long int value)
451
{
452
if (!dumping)
453
return;
454
455
trace_dump_writef("<int>%lli</int>", value);
456
}
457
458
void trace_dump_uint(long long unsigned value)
459
{
460
if (!dumping)
461
return;
462
463
trace_dump_writef("<uint>%llu</uint>", value);
464
}
465
466
void trace_dump_float(double value)
467
{
468
if (!dumping)
469
return;
470
471
trace_dump_writef("<float>%g</float>", value);
472
}
473
474
void trace_dump_bytes(const void *data,
475
size_t size)
476
{
477
static const char hex_table[16] = "0123456789ABCDEF";
478
const uint8_t *p = data;
479
size_t i;
480
481
if (!dumping)
482
return;
483
484
trace_dump_writes("<bytes>");
485
for(i = 0; i < size; ++i) {
486
uint8_t byte = *p++;
487
char hex[2];
488
hex[0] = hex_table[byte >> 4];
489
hex[1] = hex_table[byte & 0xf];
490
trace_dump_write(hex, 2);
491
}
492
trace_dump_writes("</bytes>");
493
}
494
495
void trace_dump_box_bytes(const void *data,
496
struct pipe_resource *resource,
497
const struct pipe_box *box,
498
unsigned stride,
499
unsigned slice_stride)
500
{
501
enum pipe_format format = resource->format;
502
size_t size;
503
504
assert(box->height > 0);
505
assert(box->depth > 0);
506
507
size = util_format_get_nblocksx(format, box->width ) * util_format_get_blocksize(format)
508
+ (util_format_get_nblocksy(format, box->height) - 1) * stride
509
+ (box->depth - 1) * slice_stride;
510
511
/*
512
* Only dump buffer transfers to avoid huge files.
513
* TODO: Make this run-time configurable
514
*/
515
if (resource->target != PIPE_BUFFER) {
516
size = 0;
517
}
518
519
trace_dump_bytes(data, size);
520
}
521
522
void trace_dump_string(const char *str)
523
{
524
if (!dumping)
525
return;
526
527
trace_dump_writes("<string>");
528
trace_dump_escape(str);
529
trace_dump_writes("</string>");
530
}
531
532
void trace_dump_enum(const char *value)
533
{
534
if (!dumping)
535
return;
536
537
trace_dump_writes("<enum>");
538
trace_dump_escape(value);
539
trace_dump_writes("</enum>");
540
}
541
542
void trace_dump_array_begin(void)
543
{
544
if (!dumping)
545
return;
546
547
trace_dump_writes("<array>");
548
}
549
550
void trace_dump_array_end(void)
551
{
552
if (!dumping)
553
return;
554
555
trace_dump_writes("</array>");
556
}
557
558
void trace_dump_elem_begin(void)
559
{
560
if (!dumping)
561
return;
562
563
trace_dump_writes("<elem>");
564
}
565
566
void trace_dump_elem_end(void)
567
{
568
if (!dumping)
569
return;
570
571
trace_dump_writes("</elem>");
572
}
573
574
void trace_dump_struct_begin(const char *name)
575
{
576
if (!dumping)
577
return;
578
579
trace_dump_writef("<struct name='%s'>", name);
580
}
581
582
void trace_dump_struct_end(void)
583
{
584
if (!dumping)
585
return;
586
587
trace_dump_writes("</struct>");
588
}
589
590
void trace_dump_member_begin(const char *name)
591
{
592
if (!dumping)
593
return;
594
595
trace_dump_writef("<member name='%s'>", name);
596
}
597
598
void trace_dump_member_end(void)
599
{
600
if (!dumping)
601
return;
602
603
trace_dump_writes("</member>");
604
}
605
606
void trace_dump_null(void)
607
{
608
if (!dumping)
609
return;
610
611
trace_dump_writes("<null/>");
612
}
613
614
void trace_dump_ptr(const void *value)
615
{
616
if (!dumping)
617
return;
618
619
if(value)
620
trace_dump_writef("<ptr>0x%08lx</ptr>", (unsigned long)(uintptr_t)value);
621
else
622
trace_dump_null();
623
}
624
625
void trace_dump_surface_ptr(struct pipe_surface *_surface)
626
{
627
if (!dumping)
628
return;
629
630
if (_surface) {
631
struct trace_surface *tr_surf = trace_surface(_surface);
632
trace_dump_ptr(tr_surf->surface);
633
} else {
634
trace_dump_null();
635
}
636
}
637
638
void trace_dump_transfer_ptr(struct pipe_transfer *_transfer)
639
{
640
if (!dumping)
641
return;
642
643
if (_transfer) {
644
struct trace_transfer *tr_tran = trace_transfer(_transfer);
645
trace_dump_ptr(tr_tran->transfer);
646
} else {
647
trace_dump_null();
648
}
649
}
650
651