Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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