Path: blob/21.2-virgl/src/gallium/auxiliary/driver_trace/tr_dump.c
4565 views
/**************************************************************************1*2* Copyright 2008 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/262728/**29* @file30* Trace dumping functions.31*32* For now we just use standard XML for dumping the trace calls, as this is33* simple to write, parse, and visually inspect, but the actual representation34* is abstracted out of this file, so that we can switch to a binary35* representation if/when it becomes justified.36*37* @author Jose Fonseca <[email protected]>38*/3940#include "pipe/p_config.h"4142#include <stdio.h>43#include <stdlib.h>4445/* for access() */46#ifdef _WIN3247# include <io.h>48#endif4950#include "pipe/p_compiler.h"51#include "os/os_thread.h"52#include "util/os_time.h"53#include "util/u_debug.h"54#include "util/u_memory.h"55#include "util/u_string.h"56#include "util/u_math.h"57#include "util/format/u_format.h"5859#include "tr_dump.h"60#include "tr_screen.h"61#include "tr_texture.h"626364static bool close_stream = false;65static FILE *stream = NULL;66static mtx_t call_mutex = _MTX_INITIALIZER_NP;67static long unsigned call_no = 0;68static bool dumping = false;6970static bool trigger_active = true;71static char *trigger_filename = NULL;7273void74trace_dump_trigger_active(bool active)75{76trigger_active = active;77}7879void80trace_dump_check_trigger(void)81{82if (!trigger_filename)83return;8485mtx_lock(&call_mutex);86if (trigger_active) {87trigger_active = false;88} else {89if (!access(trigger_filename, 2 /* W_OK but compiles on Windows */)) {90if (!unlink(trigger_filename)) {91trigger_active = true;92} else {93fprintf(stderr, "error removing trigger file\n");94trigger_active = false;95}96}97}98mtx_unlock(&call_mutex);99}100101bool102trace_dump_is_triggered(void)103{104return trigger_active && !!trigger_filename;105}106107static inline void108trace_dump_write(const char *buf, size_t size)109{110if (stream && trigger_active) {111fwrite(buf, size, 1, stream);112}113}114115116static inline void117trace_dump_writes(const char *s)118{119trace_dump_write(s, strlen(s));120}121122123static inline void124trace_dump_writef(const char *format, ...)125{126static char buf[1024];127unsigned len;128va_list ap;129va_start(ap, format);130len = vsnprintf(buf, sizeof(buf), format, ap);131va_end(ap);132trace_dump_write(buf, len);133}134135136static inline void137trace_dump_escape(const char *str)138{139const unsigned char *p = (const unsigned char *)str;140unsigned char c;141while((c = *p++) != 0) {142if(c == '<')143trace_dump_writes("<");144else if(c == '>')145trace_dump_writes(">");146else if(c == '&')147trace_dump_writes("&");148else if(c == '\'')149trace_dump_writes("'");150else if(c == '\"')151trace_dump_writes(""");152else if(c >= 0x20 && c <= 0x7e)153trace_dump_writef("%c", c);154else155trace_dump_writef("&#%u;", c);156}157}158159160static inline void161trace_dump_indent(unsigned level)162{163unsigned i;164for(i = 0; i < level; ++i)165trace_dump_writes("\t");166}167168169static inline void170trace_dump_newline(void)171{172trace_dump_writes("\n");173}174175176static inline void177trace_dump_tag_begin(const char *name)178{179trace_dump_writes("<");180trace_dump_writes(name);181trace_dump_writes(">");182}183184static inline void185trace_dump_tag_begin1(const char *name,186const char *attr1, const char *value1)187{188trace_dump_writes("<");189trace_dump_writes(name);190trace_dump_writes(" ");191trace_dump_writes(attr1);192trace_dump_writes("='");193trace_dump_escape(value1);194trace_dump_writes("'>");195}196197198static inline void199trace_dump_tag_end(const char *name)200{201trace_dump_writes("</");202trace_dump_writes(name);203trace_dump_writes(">");204}205206void207trace_dump_trace_flush(void)208{209if (stream) {210fflush(stream);211}212}213214static void215trace_dump_trace_close(void)216{217if (stream) {218trigger_active = true;219trace_dump_writes("</trace>\n");220if (close_stream) {221fclose(stream);222close_stream = false;223stream = NULL;224}225call_no = 0;226free(trigger_filename);227}228}229230231static void232trace_dump_call_time(int64_t time)233{234if (stream) {235trace_dump_indent(2);236trace_dump_tag_begin("time");237trace_dump_int(time);238trace_dump_tag_end("time");239trace_dump_newline();240}241}242243244bool245trace_dump_trace_begin(void)246{247const char *filename;248249filename = debug_get_option("GALLIUM_TRACE", NULL);250if (!filename)251return false;252253if (!stream) {254255if (strcmp(filename, "stderr") == 0) {256close_stream = false;257stream = stderr;258}259else if (strcmp(filename, "stdout") == 0) {260close_stream = false;261stream = stdout;262}263else {264close_stream = true;265stream = fopen(filename, "wt");266if (!stream)267return false;268}269270trace_dump_writes("<?xml version='1.0' encoding='UTF-8'?>\n");271trace_dump_writes("<?xml-stylesheet type='text/xsl' href='trace.xsl'?>\n");272trace_dump_writes("<trace version='0.1'>\n");273274/* Many applications don't exit cleanly, others may create and destroy a275* screen multiple times, so we only write </trace> tag and close at exit276* time.277*/278atexit(trace_dump_trace_close);279280const char *trigger = debug_get_option("GALLIUM_TRACE_TRIGGER", NULL);281if (trigger) {282trigger_filename = strdup(trigger);283trigger_active = false;284} else285trigger_active = true;286}287288return true;289}290291bool trace_dump_trace_enabled(void)292{293return stream ? true : false;294}295296/*297* Call lock298*/299300void trace_dump_call_lock(void)301{302mtx_lock(&call_mutex);303}304305void trace_dump_call_unlock(void)306{307mtx_unlock(&call_mutex);308}309310/*311* Dumping control312*/313314void trace_dumping_start_locked(void)315{316dumping = true;317}318319void trace_dumping_stop_locked(void)320{321dumping = false;322}323324bool trace_dumping_enabled_locked(void)325{326return dumping;327}328329void trace_dumping_start(void)330{331mtx_lock(&call_mutex);332trace_dumping_start_locked();333mtx_unlock(&call_mutex);334}335336void trace_dumping_stop(void)337{338mtx_lock(&call_mutex);339trace_dumping_stop_locked();340mtx_unlock(&call_mutex);341}342343bool trace_dumping_enabled(void)344{345bool ret;346mtx_lock(&call_mutex);347ret = trace_dumping_enabled_locked();348mtx_unlock(&call_mutex);349return ret;350}351352/*353* Dump functions354*/355356static int64_t call_start_time = 0;357358void trace_dump_call_begin_locked(const char *klass, const char *method)359{360if (!dumping)361return;362363++call_no;364trace_dump_indent(1);365trace_dump_writes("<call no=\'");366trace_dump_writef("%lu", call_no);367trace_dump_writes("\' class=\'");368trace_dump_escape(klass);369trace_dump_writes("\' method=\'");370trace_dump_escape(method);371trace_dump_writes("\'>");372trace_dump_newline();373374call_start_time = os_time_get();375}376377void trace_dump_call_end_locked(void)378{379int64_t call_end_time;380381if (!dumping)382return;383384call_end_time = os_time_get();385386trace_dump_call_time(call_end_time - call_start_time);387trace_dump_indent(1);388trace_dump_tag_end("call");389trace_dump_newline();390fflush(stream);391}392393void trace_dump_call_begin(const char *klass, const char *method)394{395mtx_lock(&call_mutex);396trace_dump_call_begin_locked(klass, method);397}398399void trace_dump_call_end(void)400{401trace_dump_call_end_locked();402mtx_unlock(&call_mutex);403}404405void trace_dump_arg_begin(const char *name)406{407if (!dumping)408return;409410trace_dump_indent(2);411trace_dump_tag_begin1("arg", "name", name);412}413414void trace_dump_arg_end(void)415{416if (!dumping)417return;418419trace_dump_tag_end("arg");420trace_dump_newline();421}422423void trace_dump_ret_begin(void)424{425if (!dumping)426return;427428trace_dump_indent(2);429trace_dump_tag_begin("ret");430}431432void trace_dump_ret_end(void)433{434if (!dumping)435return;436437trace_dump_tag_end("ret");438trace_dump_newline();439}440441void trace_dump_bool(int value)442{443if (!dumping)444return;445446trace_dump_writef("<bool>%c</bool>", value ? '1' : '0');447}448449void trace_dump_int(long long int value)450{451if (!dumping)452return;453454trace_dump_writef("<int>%lli</int>", value);455}456457void trace_dump_uint(long long unsigned value)458{459if (!dumping)460return;461462trace_dump_writef("<uint>%llu</uint>", value);463}464465void trace_dump_float(double value)466{467if (!dumping)468return;469470trace_dump_writef("<float>%g</float>", value);471}472473void trace_dump_bytes(const void *data,474size_t size)475{476static const char hex_table[16] = "0123456789ABCDEF";477const uint8_t *p = data;478size_t i;479480if (!dumping)481return;482483trace_dump_writes("<bytes>");484for(i = 0; i < size; ++i) {485uint8_t byte = *p++;486char hex[2];487hex[0] = hex_table[byte >> 4];488hex[1] = hex_table[byte & 0xf];489trace_dump_write(hex, 2);490}491trace_dump_writes("</bytes>");492}493494void trace_dump_box_bytes(const void *data,495struct pipe_resource *resource,496const struct pipe_box *box,497unsigned stride,498unsigned slice_stride)499{500enum pipe_format format = resource->format;501size_t size;502503assert(box->height > 0);504assert(box->depth > 0);505506size = util_format_get_nblocksx(format, box->width ) * util_format_get_blocksize(format)507+ (util_format_get_nblocksy(format, box->height) - 1) * stride508+ (box->depth - 1) * slice_stride;509510/*511* Only dump buffer transfers to avoid huge files.512* TODO: Make this run-time configurable513*/514if (resource->target != PIPE_BUFFER) {515size = 0;516}517518trace_dump_bytes(data, size);519}520521void trace_dump_string(const char *str)522{523if (!dumping)524return;525526trace_dump_writes("<string>");527trace_dump_escape(str);528trace_dump_writes("</string>");529}530531void trace_dump_enum(const char *value)532{533if (!dumping)534return;535536trace_dump_writes("<enum>");537trace_dump_escape(value);538trace_dump_writes("</enum>");539}540541void trace_dump_array_begin(void)542{543if (!dumping)544return;545546trace_dump_writes("<array>");547}548549void trace_dump_array_end(void)550{551if (!dumping)552return;553554trace_dump_writes("</array>");555}556557void trace_dump_elem_begin(void)558{559if (!dumping)560return;561562trace_dump_writes("<elem>");563}564565void trace_dump_elem_end(void)566{567if (!dumping)568return;569570trace_dump_writes("</elem>");571}572573void trace_dump_struct_begin(const char *name)574{575if (!dumping)576return;577578trace_dump_writef("<struct name='%s'>", name);579}580581void trace_dump_struct_end(void)582{583if (!dumping)584return;585586trace_dump_writes("</struct>");587}588589void trace_dump_member_begin(const char *name)590{591if (!dumping)592return;593594trace_dump_writef("<member name='%s'>", name);595}596597void trace_dump_member_end(void)598{599if (!dumping)600return;601602trace_dump_writes("</member>");603}604605void trace_dump_null(void)606{607if (!dumping)608return;609610trace_dump_writes("<null/>");611}612613void trace_dump_ptr(const void *value)614{615if (!dumping)616return;617618if(value)619trace_dump_writef("<ptr>0x%08lx</ptr>", (unsigned long)(uintptr_t)value);620else621trace_dump_null();622}623624void trace_dump_surface_ptr(struct pipe_surface *_surface)625{626if (!dumping)627return;628629if (_surface) {630struct trace_surface *tr_surf = trace_surface(_surface);631trace_dump_ptr(tr_surf->surface);632} else {633trace_dump_null();634}635}636637void trace_dump_transfer_ptr(struct pipe_transfer *_transfer)638{639if (!dumping)640return;641642if (_transfer) {643struct trace_transfer *tr_tran = trace_transfer(_transfer);644trace_dump_ptr(tr_tran->transfer);645} else {646trace_dump_null();647}648}649650651