Home | History | Annotate | Download | only in trace
      1 /**************************************************************************
      2  *
      3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      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 TUNGSTEN GRAPHICS 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 <jrfonseca (at) tungstengraphics.com>
     39  */
     40 
     41 #include "pipe/p_config.h"
     42 
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 
     46 #include "pipe/p_compiler.h"
     47 #include "os/os_thread.h"
     48 #include "util/u_debug.h"
     49 #include "util/u_memory.h"
     50 #include "util/u_string.h"
     51 #include "util/u_math.h"
     52 #include "util/u_format.h"
     53 
     54 #include "tr_dump.h"
     55 #include "tr_screen.h"
     56 #include "tr_texture.h"
     57 
     58 
     59 static FILE *stream = NULL;
     60 static unsigned refcount = 0;
     61 pipe_static_mutex(call_mutex);
     62 static long unsigned call_no = 0;
     63 static boolean dumping = FALSE;
     64 
     65 
     66 static INLINE void
     67 trace_dump_write(const char *buf, size_t size)
     68 {
     69    if (stream) {
     70       fwrite(buf, size, 1, stream);
     71    }
     72 }
     73 
     74 
     75 static INLINE void
     76 trace_dump_writes(const char *s)
     77 {
     78    trace_dump_write(s, strlen(s));
     79 }
     80 
     81 
     82 static INLINE void
     83 trace_dump_writef(const char *format, ...)
     84 {
     85    static char buf[1024];
     86    unsigned len;
     87    va_list ap;
     88    va_start(ap, format);
     89    len = util_vsnprintf(buf, sizeof(buf), format, ap);
     90    va_end(ap);
     91    trace_dump_write(buf, len);
     92 }
     93 
     94 
     95 static INLINE void
     96 trace_dump_escape(const char *str)
     97 {
     98    const unsigned char *p = (const unsigned char *)str;
     99    unsigned char c;
    100    while((c = *p++) != 0) {
    101       if(c == '<')
    102          trace_dump_writes("&lt;");
    103       else if(c == '>')
    104          trace_dump_writes("&gt;");
    105       else if(c == '&')
    106          trace_dump_writes("&amp;");
    107       else if(c == '\'')
    108          trace_dump_writes("&apos;");
    109       else if(c == '\"')
    110          trace_dump_writes("&quot;");
    111       else if(c >= 0x20 && c <= 0x7e)
    112          trace_dump_writef("%c", c);
    113       else
    114          trace_dump_writef("&#%u;", c);
    115    }
    116 }
    117 
    118 
    119 static INLINE void
    120 trace_dump_indent(unsigned level)
    121 {
    122    unsigned i;
    123    for(i = 0; i < level; ++i)
    124       trace_dump_writes("\t");
    125 }
    126 
    127 
    128 static INLINE void
    129 trace_dump_newline(void)
    130 {
    131    trace_dump_writes("\n");
    132 }
    133 
    134 
    135 static INLINE void
    136 trace_dump_tag(const char *name)
    137 {
    138    trace_dump_writes("<");
    139    trace_dump_writes(name);
    140    trace_dump_writes("/>");
    141 }
    142 
    143 
    144 static INLINE void
    145 trace_dump_tag_begin(const char *name)
    146 {
    147    trace_dump_writes("<");
    148    trace_dump_writes(name);
    149    trace_dump_writes(">");
    150 }
    151 
    152 static INLINE void
    153 trace_dump_tag_begin1(const char *name,
    154                       const char *attr1, const char *value1)
    155 {
    156    trace_dump_writes("<");
    157    trace_dump_writes(name);
    158    trace_dump_writes(" ");
    159    trace_dump_writes(attr1);
    160    trace_dump_writes("='");
    161    trace_dump_escape(value1);
    162    trace_dump_writes("'>");
    163 }
    164 
    165 
    166 static INLINE void
    167 trace_dump_tag_begin2(const char *name,
    168                       const char *attr1, const char *value1,
    169                       const char *attr2, const char *value2)
    170 {
    171    trace_dump_writes("<");
    172    trace_dump_writes(name);
    173    trace_dump_writes(" ");
    174    trace_dump_writes(attr1);
    175    trace_dump_writes("=\'");
    176    trace_dump_escape(value1);
    177    trace_dump_writes("\' ");
    178    trace_dump_writes(attr2);
    179    trace_dump_writes("=\'");
    180    trace_dump_escape(value2);
    181    trace_dump_writes("\'>");
    182 }
    183 
    184 
    185 static INLINE void
    186 trace_dump_tag_begin3(const char *name,
    187                       const char *attr1, const char *value1,
    188                       const char *attr2, const char *value2,
    189                       const char *attr3, const char *value3)
    190 {
    191    trace_dump_writes("<");
    192    trace_dump_writes(name);
    193    trace_dump_writes(" ");
    194    trace_dump_writes(attr1);
    195    trace_dump_writes("=\'");
    196    trace_dump_escape(value1);
    197    trace_dump_writes("\' ");
    198    trace_dump_writes(attr2);
    199    trace_dump_writes("=\'");
    200    trace_dump_escape(value2);
    201    trace_dump_writes("\' ");
    202    trace_dump_writes(attr3);
    203    trace_dump_writes("=\'");
    204    trace_dump_escape(value3);
    205    trace_dump_writes("\'>");
    206 }
    207 
    208 
    209 static INLINE void
    210 trace_dump_tag_end(const char *name)
    211 {
    212    trace_dump_writes("</");
    213    trace_dump_writes(name);
    214    trace_dump_writes(">");
    215 }
    216 
    217 static void
    218 trace_dump_trace_close(void)
    219 {
    220    if(stream) {
    221       trace_dump_writes("</trace>\n");
    222       fclose(stream);
    223       stream = NULL;
    224       refcount = 0;
    225       call_no = 0;
    226    }
    227 }
    228 
    229 boolean trace_dump_trace_begin()
    230 {
    231    const char *filename;
    232 
    233    filename = debug_get_option("GALLIUM_TRACE", NULL);
    234    if(!filename)
    235       return FALSE;
    236 
    237    if(!stream) {
    238 
    239       stream = fopen(filename, "wt");
    240       if(!stream)
    241          return FALSE;
    242 
    243       trace_dump_writes("<?xml version='1.0' encoding='UTF-8'?>\n");
    244       trace_dump_writes("<?xml-stylesheet type='text/xsl' href='trace.xsl'?>\n");
    245       trace_dump_writes("<trace version='0.1'>\n");
    246 
    247 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE)
    248       /* Linux applications rarely cleanup GL / Gallium resources so catch
    249        * application exit here */
    250       atexit(trace_dump_trace_close);
    251 #endif
    252    }
    253 
    254    ++refcount;
    255 
    256    return TRUE;
    257 }
    258 
    259 boolean trace_dump_trace_enabled(void)
    260 {
    261    return stream ? TRUE : FALSE;
    262 }
    263 
    264 void trace_dump_trace_end(void)
    265 {
    266    if(stream)
    267       if(!--refcount)
    268          trace_dump_trace_close();
    269 }
    270 
    271 /*
    272  * Call lock
    273  */
    274 
    275 void trace_dump_call_lock(void)
    276 {
    277    pipe_mutex_lock(call_mutex);
    278 }
    279 
    280 void trace_dump_call_unlock(void)
    281 {
    282    pipe_mutex_unlock(call_mutex);
    283 }
    284 
    285 /*
    286  * Dumping control
    287  */
    288 
    289 void trace_dumping_start_locked(void)
    290 {
    291    dumping = TRUE;
    292 }
    293 
    294 void trace_dumping_stop_locked(void)
    295 {
    296    dumping = FALSE;
    297 }
    298 
    299 boolean trace_dumping_enabled_locked(void)
    300 {
    301    return dumping;
    302 }
    303 
    304 void trace_dumping_start(void)
    305 {
    306    pipe_mutex_lock(call_mutex);
    307    trace_dumping_start_locked();
    308    pipe_mutex_unlock(call_mutex);
    309 }
    310 
    311 void trace_dumping_stop(void)
    312 {
    313    pipe_mutex_lock(call_mutex);
    314    trace_dumping_stop_locked();
    315    pipe_mutex_unlock(call_mutex);
    316 }
    317 
    318 boolean trace_dumping_enabled(void)
    319 {
    320    boolean ret;
    321    pipe_mutex_lock(call_mutex);
    322    ret = trace_dumping_enabled_locked();
    323    pipe_mutex_unlock(call_mutex);
    324    return ret;
    325 }
    326 
    327 /*
    328  * Dump functions
    329  */
    330 
    331 void trace_dump_call_begin_locked(const char *klass, const char *method)
    332 {
    333    if (!dumping)
    334       return;
    335 
    336    ++call_no;
    337    trace_dump_indent(1);
    338    trace_dump_writes("<call no=\'");
    339    trace_dump_writef("%lu", call_no);
    340    trace_dump_writes("\' class=\'");
    341    trace_dump_escape(klass);
    342    trace_dump_writes("\' method=\'");
    343    trace_dump_escape(method);
    344    trace_dump_writes("\'>");
    345    trace_dump_newline();
    346 }
    347 
    348 void trace_dump_call_end_locked(void)
    349 {
    350    if (!dumping)
    351       return;
    352 
    353    trace_dump_indent(1);
    354    trace_dump_tag_end("call");
    355    trace_dump_newline();
    356    fflush(stream);
    357 }
    358 
    359 void trace_dump_call_begin(const char *klass, const char *method)
    360 {
    361    pipe_mutex_lock(call_mutex);
    362    trace_dump_call_begin_locked(klass, method);
    363 }
    364 
    365 void trace_dump_call_end(void)
    366 {
    367    trace_dump_call_end_locked();
    368    pipe_mutex_unlock(call_mutex);
    369 }
    370 
    371 void trace_dump_arg_begin(const char *name)
    372 {
    373    if (!dumping)
    374       return;
    375 
    376    trace_dump_indent(2);
    377    trace_dump_tag_begin1("arg", "name", name);
    378 }
    379 
    380 void trace_dump_arg_end(void)
    381 {
    382    if (!dumping)
    383       return;
    384 
    385    trace_dump_tag_end("arg");
    386    trace_dump_newline();
    387 }
    388 
    389 void trace_dump_ret_begin(void)
    390 {
    391    if (!dumping)
    392       return;
    393 
    394    trace_dump_indent(2);
    395    trace_dump_tag_begin("ret");
    396 }
    397 
    398 void trace_dump_ret_end(void)
    399 {
    400    if (!dumping)
    401       return;
    402 
    403    trace_dump_tag_end("ret");
    404    trace_dump_newline();
    405 }
    406 
    407 void trace_dump_bool(int value)
    408 {
    409    if (!dumping)
    410       return;
    411 
    412    trace_dump_writef("<bool>%c</bool>", value ? '1' : '0');
    413 }
    414 
    415 void trace_dump_int(long long int value)
    416 {
    417    if (!dumping)
    418       return;
    419 
    420    trace_dump_writef("<int>%lli</int>", value);
    421 }
    422 
    423 void trace_dump_uint(long long unsigned value)
    424 {
    425    if (!dumping)
    426       return;
    427 
    428    trace_dump_writef("<uint>%llu</uint>", value);
    429 }
    430 
    431 void trace_dump_float(double value)
    432 {
    433    if (!dumping)
    434       return;
    435 
    436    trace_dump_writef("<float>%g</float>", value);
    437 }
    438 
    439 void trace_dump_bytes(const void *data,
    440                       size_t size)
    441 {
    442    static const char hex_table[16] = "0123456789ABCDEF";
    443    const uint8_t *p = data;
    444    size_t i;
    445 
    446    if (!dumping)
    447       return;
    448 
    449    trace_dump_writes("<bytes>");
    450    for(i = 0; i < size; ++i) {
    451       uint8_t byte = *p++;
    452       char hex[2];
    453       hex[0] = hex_table[byte >> 4];
    454       hex[1] = hex_table[byte & 0xf];
    455       trace_dump_write(hex, 2);
    456    }
    457    trace_dump_writes("</bytes>");
    458 }
    459 
    460 void trace_dump_box_bytes(const void *data,
    461 			  enum pipe_format format,
    462 			  const struct pipe_box *box,
    463 			  unsigned stride,
    464 			  unsigned slice_stride)
    465 {
    466    size_t size;
    467 
    468    if (slice_stride)
    469       size = box->depth * slice_stride;
    470    else if (stride)
    471       size = util_format_get_nblocksy(format, box->height) * stride;
    472    else {
    473       size = util_format_get_nblocksx(format, box->width) * util_format_get_blocksize(format);
    474    }
    475 
    476    trace_dump_bytes(data, size);
    477 }
    478 
    479 void trace_dump_string(const char *str)
    480 {
    481    if (!dumping)
    482       return;
    483 
    484    trace_dump_writes("<string>");
    485    trace_dump_escape(str);
    486    trace_dump_writes("</string>");
    487 }
    488 
    489 void trace_dump_enum(const char *value)
    490 {
    491    if (!dumping)
    492       return;
    493 
    494    trace_dump_writes("<enum>");
    495    trace_dump_escape(value);
    496    trace_dump_writes("</enum>");
    497 }
    498 
    499 void trace_dump_array_begin(void)
    500 {
    501    if (!dumping)
    502       return;
    503 
    504    trace_dump_writes("<array>");
    505 }
    506 
    507 void trace_dump_array_end(void)
    508 {
    509    if (!dumping)
    510       return;
    511 
    512    trace_dump_writes("</array>");
    513 }
    514 
    515 void trace_dump_elem_begin(void)
    516 {
    517    if (!dumping)
    518       return;
    519 
    520    trace_dump_writes("<elem>");
    521 }
    522 
    523 void trace_dump_elem_end(void)
    524 {
    525    if (!dumping)
    526       return;
    527 
    528    trace_dump_writes("</elem>");
    529 }
    530 
    531 void trace_dump_struct_begin(const char *name)
    532 {
    533    if (!dumping)
    534       return;
    535 
    536    trace_dump_writef("<struct name='%s'>", name);
    537 }
    538 
    539 void trace_dump_struct_end(void)
    540 {
    541    if (!dumping)
    542       return;
    543 
    544    trace_dump_writes("</struct>");
    545 }
    546 
    547 void trace_dump_member_begin(const char *name)
    548 {
    549    if (!dumping)
    550       return;
    551 
    552    trace_dump_writef("<member name='%s'>", name);
    553 }
    554 
    555 void trace_dump_member_end(void)
    556 {
    557    if (!dumping)
    558       return;
    559 
    560    trace_dump_writes("</member>");
    561 }
    562 
    563 void trace_dump_null(void)
    564 {
    565    if (!dumping)
    566       return;
    567 
    568    trace_dump_writes("<null/>");
    569 }
    570 
    571 void trace_dump_ptr(const void *value)
    572 {
    573    if (!dumping)
    574       return;
    575 
    576    if(value)
    577       trace_dump_writef("<ptr>0x%08lx</ptr>", (unsigned long)(uintptr_t)value);
    578    else
    579       trace_dump_null();
    580 }
    581 
    582 
    583 void trace_dump_resource_ptr(struct pipe_resource *_resource)
    584 {
    585    if (!dumping)
    586       return;
    587 
    588    if (_resource) {
    589       struct trace_resource *tr_resource = trace_resource(_resource);
    590       trace_dump_ptr(tr_resource->resource);
    591    } else {
    592       trace_dump_null();
    593    }
    594 }
    595 
    596 void trace_dump_surface_ptr(struct pipe_surface *_surface)
    597 {
    598    if (!dumping)
    599       return;
    600 
    601    if (_surface) {
    602       struct trace_surface *tr_surf = trace_surface(_surface);
    603       trace_dump_ptr(tr_surf->surface);
    604    } else {
    605       trace_dump_null();
    606    }
    607 }
    608 
    609 void trace_dump_transfer_ptr(struct pipe_transfer *_transfer)
    610 {
    611    if (!dumping)
    612       return;
    613 
    614    if (_transfer) {
    615       struct trace_transfer *tr_tran = trace_transfer(_transfer);
    616       trace_dump_ptr(tr_tran->transfer);
    617    } else {
    618       trace_dump_null();
    619    }
    620 }
    621