From 7e329020a9dc8e0201f3ebe256b5ddbacd57dcc3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Fri, 19 Nov 2010 17:05:18 +0000 Subject: [PATCH] First stab at binary trace and retracing. It's enough to retrace trivial/tri Mesa demo. --- .gitignore | 6 +- CMakeLists.txt | 38 +++- apitrace.xsl | 228 ------------------------ base.py | 4 +- dump.cpp | 37 ++++ glretrace.py | 118 ++++++++++++ log.cpp | 453 +++++++++++++++-------------------------------- log.hpp | 5 +- trace_format.hpp | 89 ++++++++++ trace_model.cpp | 177 ++++++++++++++++++ trace_model.hpp | 189 ++++++++++++++++++++ trace_parser.hpp | 253 ++++++++++++++++++++++++++ xml2txt.py | 451 ---------------------------------------------- 13 files changed, 1053 insertions(+), 995 deletions(-) delete mode 100644 apitrace.xsl create mode 100644 dump.cpp create mode 100644 glretrace.py create mode 100644 trace_format.hpp create mode 100644 trace_model.cpp create mode 100644 trace_model.hpp create mode 100644 trace_parser.hpp delete mode 100755 xml2txt.py diff --git a/.gitignore b/.gitignore index 7fac701..32ddb97 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ *.dll *.exe *.exp -*.gz +*.trace *.ilk *.lib *.o @@ -15,7 +15,6 @@ *.pyc *.pyo *.so -*.xml *.zip CMakeFiles CMakeCache.txt @@ -29,5 +28,8 @@ d3d9.cpp d3d10.cpp d3d10_1.cpp dxsdk +dump glx.cpp +glretrace +glretrace.cpp opengl32.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ae0740..41f896b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,9 +4,18 @@ project (apitrace) find_package (PythonInterp REQUIRED) find_package (OpenGL REQUIRED) - find_package (ZLIB) +find_package (GLUT) + +find_library (GLEW_glew_LIBRARY GLEW + /usr/lib +) + +find_path (GLEW_INCLUDE_DIR GL/glew.h + /usr/include/GL +) + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") # Nobody likes to include windows.h: # - Microsoft's GL/gl.h header depends on windows.h but doesn't include it; @@ -93,3 +102,30 @@ else () target_link_libraries (glxtrace dl) endif () +add_executable (dump dump.cpp trace_model.cpp) + + +if (GLEW_INCLUDE_DIR) + add_custom_command ( + OUTPUT glretrace.cpp + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/glretrace.py > ${CMAKE_CURRENT_BINARY_DIR}/glretrace.cpp + DEPENDS glretrace.py glx.py gl.py dl.py base.py + ) + + include_directories ( + ${OPENGL_INCLUDE_PATH} + ${GLUT_INCLUDE_DIR} + ${GLEW_INCLUDE_DIR} + ) + + add_executable (glretrace glretrace.cpp trace_model.cpp) + + target_link_libraries (glretrace + ${OPENGL_gl_LIBRARY} + ${OPENGL_glu_LIBRARY} + ${GLUT_glut_LIBRARY} + ${GLEW_glew_LIBRARY} + ) +endif (GLEW_INCLUDE_DIR) + + diff --git a/apitrace.xsl b/apitrace.xsl deleted file mode 100644 index ccb4d80..0000000 --- a/apitrace.xsl +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - - - - - - D3D Trace - - - -
    - -
- - -
- - -
  • - - - - ( -
      - -
    - ) - -
  • -
    - - -
  • - - - = - - - , - -
  • -
    - - - - - - - - - - - - - - - = - - - - - - - - - - - - - - - & - - - - - - - - - - - - - - - - - - - - - - - - - - { -
      - -
    - } -
    - - - -
    -
    - - - - - - -
    - - - -
    - - - -
    -
    -
    diff --git a/base.py b/base.py index e672a3c..3c93c42 100644 --- a/base.py +++ b/base.py @@ -172,7 +172,7 @@ class Enum(Concrete): print ' switch(%s) {' % instance for value in self.values: print ' case %s:' % value - print ' Log::LiteralNamedConstant("%s");' % value + print ' Log::LiteralNamedConstant("%s", %s);' % (value, value) print ' break;' print ' default:' print ' Log::LiteralSInt(%s);' % instance @@ -199,7 +199,7 @@ class Flags(Concrete): print ' Log::BeginBitmask("%s");' % (self.type,) for value in self.values: print ' if((l_Value & %s) == %s) {' % (value, value) - print ' Log::LiteralNamedConstant("%s");' % value + print ' Log::LiteralNamedConstant("%s", %s);' % (value, value) print ' l_Value &= ~%s;' % value print ' }' print ' if(l_Value) {' diff --git a/dump.cpp b/dump.cpp new file mode 100644 index 0000000..09d74c4 --- /dev/null +++ b/dump.cpp @@ -0,0 +1,37 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +#include "trace_parser.hpp" + + +int main(int argc, char **argv) +{ + for (int i = 1; i < argc; ++i) { + Trace::Parser p; + p.parse(argv[i]); + } + return 0; +} diff --git a/glretrace.py b/glretrace.py new file mode 100644 index 0000000..82cd713 --- /dev/null +++ b/glretrace.py @@ -0,0 +1,118 @@ +########################################################################## +# +# Copyright 2010 VMware, Inc. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +##########################################################################/ + + +import base +from glx import libgl + + +def is_arg_supported(arg_type): + if isinstance(arg_type, (base.Literal, base._String, base.Enum)): + return True + if isinstance(arg_type, (base.Alias, base.Flags)): + return is_arg_supported(arg_type.type) + return False + + +def is_function_supported(function): + for arg_type, arg_name in function.args: + if not is_arg_supported(arg_type): + return False + return True + + +def extract_value(arg_type, arg_value): + if isinstance(arg_type, base.Literal): + return 'Trace::as%s(%s)' % (arg_type.format, value) + if isinstance(arg_type, base.Enum): + return 'Trace::asSInt(%s)' % (value) + if isinstance(arg_type, (base.Alias, base.Flags)): + return extract_value(arg_type.type, value) + assert false + return '0' + + +if __name__ == '__main__': + print + print '#include ' + print '#include ' + print '#include ' + print '#include ' + print + print '#include "trace_parser.hpp"' + print + + functions = filter(is_function_supported, libgl.functions) + + for function in functions: + print 'static void retrace_%s(Trace::Call &call) {' % function.name + for arg_type, arg_name in function.args: + print ' %s %s;' % (arg_type, arg_name) + for arg_type, arg_name in function.args: + value = 'call.get_arg("%s")' % (arg_name,) + value = extract_value(arg_type, value) + print ' %s = static_cast<%s>(%s);' % (arg_name, arg_type, value) + arg_names = ", ".join([arg_name for arg_type, arg_name in function.args]) + print ' %s(%s);' % (function.name, arg_names) + print '}' + print + + print 'static bool retrace_call(Trace::Call &call) {' + for function in functions: + print ' if (call.name == "%s") {' % function.name + print ' retrace_%s(call);' % function.name + print ' return true;' + print ' }' + print ' std::cerr << "Unsupported call " << call.name << "\\n";' + print ' return false;' + print '}' + print ''' + +class Retracer : public Trace::Parser +{ + void handle_call(Trace::Call &call) { + std::cout << call; + std::cout.flush(); + retrace_call(call); + } +}; + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitWindowPosition( 0, 0 ); + glutInitWindowSize( 800, 600 ); + glutInitDisplayMode( GLUT_DEPTH | GLUT_RGB | GLUT_SINGLE ); + glutCreateWindow(argv[0]); + glewInit(); + for (int i = 1; i < argc; ++i) { + Retracer p; + p.parse(argv[i]); + glutMainLoop(); + } + return 0; +} + +''' diff --git a/log.cpp b/log.cpp index a7128f8..a78ba53 100644 --- a/log.cpp +++ b/log.cpp @@ -24,6 +24,7 @@ **************************************************************************/ +#include #include #include #include @@ -33,6 +34,7 @@ #include "os.hpp" #include "log.hpp" +#include "trace_format.hpp" namespace Log { @@ -40,397 +42,230 @@ namespace Log { static gzFile g_gzFile = NULL; static void _Close(void) { - if(g_gzFile != NULL) { - gzclose(g_gzFile); - g_gzFile = NULL; - } + if(g_gzFile != NULL) { + gzclose(g_gzFile); + g_gzFile = NULL; + } } static void _Open(const char *szName, const char *szExtension) { - _Close(); - - static unsigned dwCounter = 0; - - char szProcessName[PATH_MAX]; - char szFileName[PATH_MAX]; - - OS::GetProcessName(szProcessName, PATH_MAX); - - for(;;) { - FILE *file; - - if(dwCounter) - snprintf(szFileName, PATH_MAX, "%s.%s.%u.%s.gz", szProcessName, szName, dwCounter, szExtension); - else - snprintf(szFileName, PATH_MAX, "%s.%s.%s.gz", szProcessName, szName, szExtension); - - file = fopen(szFileName, "rb"); - if(file == NULL) - break; - - fclose(file); - - ++dwCounter; - } - - fprintf(stderr, "Logging to %s\n", szFileName); - g_gzFile = gzopen(szFileName, "wb"); + _Close(); + + static unsigned dwCounter = 0; + + char szProcessName[PATH_MAX]; + char szFileName[PATH_MAX]; + + OS::GetProcessName(szProcessName, PATH_MAX); + + for(;;) { + FILE *file; + + if(dwCounter) + snprintf(szFileName, PATH_MAX, "%s.%s.%u.%s", szProcessName, szName, dwCounter, szExtension); + else + snprintf(szFileName, PATH_MAX, "%s.%s.%s", szProcessName, szName, szExtension); + + file = fopen(szFileName, "rb"); + if(file == NULL) + break; + + fclose(file); + + ++dwCounter; + } + + fprintf(stderr, "Logging to %s\n", szFileName); + g_gzFile = gzopen(szFileName, "wb"); } static inline void Write(const char *sBuffer, size_t dwBytesToWrite) { - if(g_gzFile == NULL) - return; - - gzwrite(g_gzFile, sBuffer, dwBytesToWrite); -} - -static inline void Write(const char *szText) { - Write(szText, strlen(szText)); -} - -static inline void Write(char c) -{ - Write(&c, 1); -} - -static inline void -WriteF(const char *format, ...) -{ - char szBuffer[4096]; - va_list ap; - va_start(ap, format); - vsnprintf(szBuffer, sizeof(szBuffer), format, ap); - va_end(ap); - Write(szBuffer); + if(g_gzFile == NULL) + return; + + gzwrite(g_gzFile, sBuffer, dwBytesToWrite); } static inline void -Escape(wchar_t c) -{ - switch(c) { - case '&': - Write("&"); - break; - case '<': - Write("<"); - break; - case '>': - Write(">"); - break; - case '"': - Write("""); - break; - case '\'': - Write("'"); - break; - case '\t': - Write(" "); - break; - case '\r': - Write(" "); - break; - case '\n': - Write(" "); - break; - default: - if (c >= 0x20 && c <= 0x7e) { - Write((char)c); - } else { - Write('.'); - } - } +WriteByte(char c) { + Write(&c, 1); } -static inline void -Escape(const char *s) -{ - unsigned char c; - while((c = *s++) != 0) { - Escape(c); - } -} +void inline +WriteUInt(unsigned long long value) { + char buf[2 * sizeof value]; + unsigned len; -static inline void -Escape(const wchar_t *s) -{ - unsigned char c; - while((c = *s++) != 0) { - Escape(c); - } -} + len = 0; + do { + assert(len < sizeof buf); + buf[len] = 0x80 | (value & 0x7f); + value >>= 7; + ++len; + } while (value); -static inline void -EscapeF(const char *format, ...) -{ - char szBuffer[4096]; - va_list ap; - va_start(ap, format); - vsnprintf(szBuffer, sizeof(szBuffer), format, ap); - va_end(ap); - Escape(szBuffer); -} - -static inline void -Indent(unsigned level) { - for(unsigned i = 0; i < level; ++i) - Write("\t"); -} - -static inline void -NewLine(void) { - Write("\r\n"); -} + assert(len); + buf[len - 1] &= 0x7f; -static inline void -Tag(const char *name) { - Write("<"); - Write(name); - Write("/>"); + Write(buf, len); } static inline void -BeginTag(const char *name) { - Write("<"); - Write(name); - Write(">"); +WriteFloat(float value) { + assert(sizeof value == 4); + Write((const char *)&value, sizeof value); } static inline void -BeginTag(const char *name, - const char *attr1, const char *value1) { - Write("<"); - Write(name); - Write(" "); - Write(attr1); - Write("=\""); - Escape(value1); - Write("\">"); +WriteDouble(double value) { + assert(sizeof value == 8); + Write((const char *)&value, sizeof value); } static inline void -BeginTag(const char *name, - const char *attr1, const char *value1, - const char *attr2, const char *value2) { - Write("<"); - Write(name); - Write(" "); - Write(attr1); - Write("=\""); - Escape(value1); - Write("\" "); - Write(attr2); - Write("=\""); - Escape(value2); - Write("\">"); -} - -static inline void -BeginTag(const char *name, - const char *attr1, const char *value1, - const char *attr2, const char *value2, - const char *attr3, const char *value3) { - Write("<"); - Write(name); - Write(" "); - Write(attr1); - Write("=\""); - Escape(value1); - Write("\" "); - Write(attr2); - Write("=\""); - Escape(value2); - Write("\" "); - Write(attr3); - Write("=\""); - Escape(value3); - Write("\">"); -} - -static inline void -EndTag(const char *name) { - Write(""); +WriteString(const char *str) { + size_t len = strlen(str); + WriteUInt(len); + Write(str, len); } void Open(const char *name) { - _Open(name, "xml"); - Write(""); - NewLine(); - Write(""); - NewLine(); - BeginTag("trace"); - NewLine(); + _Open(name, "trace"); + WriteUInt(TRACE_VERSION); } void Close(void) { - EndTag("trace"); - NewLine(); - _Close(); + _Close(); } void BeginCall(const char *function) { - OS::AcquireMutex(); - Indent(1); - BeginTag("call", "name", function); - NewLine(); + OS::AcquireMutex(); + WriteString(function); } void EndCall(void) { - Indent(1); - EndTag("call"); - NewLine(); - gzflush(g_gzFile, Z_SYNC_FLUSH); - OS::ReleaseMutex(); + WriteByte(Trace::CALL_END); + gzflush(g_gzFile, Z_SYNC_FLUSH); + OS::ReleaseMutex(); } void BeginArg(const char *type, const char *name) { - Indent(2); - BeginTag("arg", "type", type, "name", name); + WriteByte(Trace::CALL_ARG); + WriteString(name); } -void EndArg(void) { - EndTag("arg"); - NewLine(); -} +void EndArg(void) { } void BeginReturn(const char *type) { - Indent(2); - BeginTag("ret", "type", type); + WriteByte(Trace::CALL_RET); } -void EndReturn(void) { - EndTag("ret"); - NewLine(); -} +void EndReturn(void) { } -void BeginArray(const char *type, size_t length) -{ - BeginTag("array", "type", type); +void BeginArray(const char *type, size_t length) { + WriteByte(Trace::TYPE_ARRAY); + WriteUInt(length); } -void EndArray(void) -{ - EndTag("array"); -} +void EndArray(void) { } -void BeginElement(const char *type) -{ - BeginTag("elem", "type", type); -} +void BeginElement(const char *type) { } -void EndElement(void) -{ - EndTag("elem"); -} +void EndElement(void) { } -void BeginStruct(const char *type) -{ - BeginTag("struct", "type", type); +void BeginStruct(const char *type) { + WriteByte(Trace::TYPE_STRUCT); } -void EndStruct(void) -{ - EndTag("struct"); +void EndStruct(void) { + WriteString(""); } -void BeginMember(const char *type, const char *name) -{ - BeginTag("member", "type", type, "name", name); +void BeginMember(const char *type, const char *name) { + WriteString(name); } -void EndMember(void) -{ - EndTag("member"); -} +void EndMember(void) { } -void BeginBitmask(const char *type) -{ - BeginTag("bitmask"); +void BeginBitmask(const char *type) { + WriteByte(Trace::TYPE_BITMASK); } -void EndBitmask(void) -{ - EndTag("bitmask"); +void EndBitmask(void) { + WriteByte(Trace::TYPE_VOID); } void BeginPointer(const char *type, const void *addr) { - char saddr[256]; - snprintf(saddr, sizeof(saddr), "%p", addr); - BeginTag("ref", "type", type, "addr", saddr); + WriteByte(Trace::TYPE_POINTER); + WriteUInt((size_t)addr); } -void EndPointer(void) -{ - EndTag("ref"); +void EndPointer(void) { } + +void LiteralBool(bool value) { + WriteByte(Trace::TYPE_BOOL); + WriteByte(value ? 0 : 1); } -void LiteralBool(bool value) -{ - BeginTag("bool"); - WriteF("%u", value ? 0 : 1); - EndTag("bool"); +void LiteralSInt(signed long long value) { + if (value < 0) { + WriteByte(Trace::TYPE_SINT); + WriteUInt(-value); + } else { + WriteByte(Trace::TYPE_UINT); + WriteUInt(value); + } } -void LiteralSInt(signed long long value) -{ - BeginTag("int"); - WriteF("%lli", value); - EndTag("int"); +void LiteralUInt(unsigned long long value) { + WriteByte(Trace::TYPE_UINT); + WriteUInt(value); } -void LiteralUInt(unsigned long long value) -{ - BeginTag("uint"); - WriteF("%llu", value); - EndTag("uint"); +void LiteralFloat(float value) { + WriteByte(Trace::TYPE_FLOAT); + WriteFloat(value); } -void LiteralFloat(double value) -{ - BeginTag("float"); - WriteF("%f", value); - EndTag("float"); +void LiteralFloat(double value) { + WriteByte(Trace::TYPE_DOUBLE); + WriteDouble(value); } -void LiteralString(const char *str) -{ - if (!str) { - LiteralNull(); - return; - } - BeginTag("string"); - Escape(str); - EndTag("string"); +void LiteralString(const char *str) { + if (!str) { + LiteralNull(); + return; + } + WriteByte(Trace::TYPE_STRING); + WriteString(str); } -void LiteralWString(const wchar_t *str) -{ - if (!str) { - LiteralNull(); - return; - } - BeginTag("wstring"); - Escape(str); - EndTag("wstring"); +void LiteralWString(const wchar_t *str) { + + if (!str) { + LiteralNull(); + return; + } + WriteByte(Trace::TYPE_STRING); + WriteString(""); } - -void LiteralNamedConstant(const char *str) -{ - BeginTag("const"); - Escape(str); - EndTag("const"); + +void LiteralNamedConstant(const char *name, long long value) { + WriteByte(Trace::TYPE_CONST); + WriteString(name); + LiteralSInt(value); } -void LiteralNull(void) -{ - Tag("null"); +void LiteralNull(void) { + WriteByte(Trace::TYPE_POINTER); + WriteUInt(0); + WriteByte(Trace::TYPE_OPAQUE); } -void LiteralOpaque(void) -{ - Tag("opaque"); +void LiteralOpaque(void) { + WriteByte(Trace::TYPE_OPAQUE); } } /* namespace Log */ diff --git a/log.hpp b/log.hpp index b05541b..fa1f91e 100644 --- a/log.hpp +++ b/log.hpp @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2007-2009 VMware, Inc. + * Copyright 2007-2010 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -61,10 +61,11 @@ namespace Log { void LiteralBool(bool value); void LiteralSInt(signed long long value); void LiteralUInt(unsigned long long value); + void LiteralFloat(float value); void LiteralFloat(double value); void LiteralString(const char *str); void LiteralWString(const wchar_t *str); - void LiteralNamedConstant(const char *str); + void LiteralNamedConstant(const char *name, long long value); void LiteralNull(void); void LiteralOpaque(void); } diff --git a/trace_format.hpp b/trace_format.hpp new file mode 100644 index 0000000..fe37a80 --- /dev/null +++ b/trace_format.hpp @@ -0,0 +1,89 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#ifndef _TRACE_FORMAT_HPP_ +#define _TRACE_FORMAT_HPP_ + +namespace Trace { + +#define TRACE_VERSION 0 + +enum CallDetail { + CALL_END = 0, + CALL_ARG, + CALL_RET, + CALL_THREAD, +}; + +enum Type { + TYPE_VOID = 0, + TYPE_BOOL, + TYPE_SINT, + TYPE_UINT, + TYPE_FLOAT, + TYPE_DOUBLE, + TYPE_STRING, // Null terminated, human readible string + TYPE_BLOB, // Block of bytes + TYPE_CONST, + TYPE_BITMASK, + TYPE_ARRAY, + TYPE_STRUCT, + TYPE_POINTER, + TYPE_OPAQUE, +}; + +/* + * trace = call* EOF + * + * call = name (detail)* END + * + * detail = ARG name value + * | RET value + * | ... + * + * value = VOID + * | BOOL BOOL_VALUE + * | SINT INT_VALUE + * | UINT INT_VALUE + * | FLOAT FLOAT_VALUE + * | STRING string + * | BLOB string + * | CONST name value + * | BITMASK value+ + * | ARRAY length + * + * bool = 0 | 1 + * + * name = string + * + * string = length (BYTE)* + * + * length = INT_VALUE + */ + + +} /* namespace Trace */ + +#endif /* _TRACE_FORMAT_HPP_ */ diff --git a/trace_model.cpp b/trace_model.cpp new file mode 100644 index 0000000..1d33ba6 --- /dev/null +++ b/trace_model.cpp @@ -0,0 +1,177 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +#include "trace_model.hpp" + + +namespace Trace { + + +void Void::visit(Visitor &visitor) { + visitor.visit(this); +} + +void Bool::visit(Visitor &visitor) { + visitor.visit(this); +} + +void SInt::visit(Visitor &visitor) { + visitor.visit(this); +} + +void UInt::visit(Visitor &visitor) { + visitor.visit(this); +} + +void Float::visit(Visitor &visitor) { + visitor.visit(this); +} + +void String::visit(Visitor &visitor) { + visitor.visit(this); +} + +void Const::visit(Visitor &visitor) { + visitor.visit(this); +} + +void Array::visit(Visitor &visitor) { + visitor.visit(this); +} + + +class Dumper : public Visitor +{ +public: + std::ostream &os; + + Dumper() : os(std::cout) {} + + Dumper(std::ostream &_os) : os(_os) {} + + void visit(Void *node) { + } + + void visit(Bool *node) { + os << (node->value ? "true" : "false"); + } + + void visit(SInt *node) { + os << node->value; + } + + void visit(UInt *node) { + os << node->value; + } + + void visit(Float *node) { + os << node->value; + } + + void visit(String *node) { + os << '"' << node->value << '"'; + } + + void visit(Const *node) { + os << node->name; + } + + void visit(Array *node) { + const char *sep = ""; + os << "{"; + for (std::vector::iterator it = node->values.begin(); it != node->values.end(); ++it) { + os << sep; + (*it)->visit(*this); + sep = ", "; + } + os << "}"; + } +}; + + +std::ostream & operator <<(std::ostream &os, Value *value) { + Dumper d(os); + if (value) { + value->visit(d); + } + return os; +} + + +static const Value *unwrap(const Value *node) { + const Const *c = dynamic_cast(node); + if (c) + return c->value; + return node; +} + +signed long long asSInt(const Value *node) { + node = unwrap(node); + const SInt *sint = dynamic_cast(node); + if (sint) + return sint->value; + const UInt *uint = dynamic_cast(node); + if (uint) + return uint->value; + assert(0); + return 0; +} + +unsigned long long asUInt(const Value *node) { + node = unwrap(node); + const UInt *uint = dynamic_cast(node); + if (uint) + return uint->value; + assert(0); + return 0; +} + + +double asFloat(const Value *node) { + node = unwrap(node); + const Float *fl = dynamic_cast(node); + assert(fl); + return fl->value; +} + + +std::ostream & operator <<(std::ostream &os, Call &call) { + const char *sep = ""; + os << call.name << "("; + for (std::list::iterator it = call.args.begin(); it != call.args.end(); ++it) { + os << sep << it->first << " = " << it->second; + sep = ", "; + } + os << ")"; + if (call.ret) { + os << " = " << call.ret; + } + os << "\n"; + return os; +} + + +} /* namespace Trace */ diff --git a/trace_model.hpp b/trace_model.hpp new file mode 100644 index 0000000..9bb3e1d --- /dev/null +++ b/trace_model.hpp @@ -0,0 +1,189 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#ifndef _TRACE_MODEL_HPP_ +#define _TRACE_MODEL_HPP_ + + +#include + +#include +#include +#include +#include +#include + + +namespace Trace { + + +class Visitor; +class Dumper; +class UInt; + + +class Value +{ +public: + virtual void visit(Visitor &visitor) = 0; +}; + + +class Void : public Value +{ +public: + void visit(Visitor &visitor); +}; + + +class Bool : public Value +{ +public: + Bool(bool _value) : value(_value) {} + + void visit(Visitor &visitor); + + bool value; +}; + + +class SInt : public Value +{ +public: + SInt(signed long long _value) : value(_value) {} + + void visit(Visitor &visitor); + + signed long long value; +}; + + +class UInt : public Value +{ +public: + UInt(unsigned long long _value) : value(_value) {} + + void visit(Visitor &visitor); + + unsigned long long value; +}; + + +class Float : public Value +{ +public: + Float(double _value) : value(_value) {} + + void visit(Visitor &visitor); + + double value; +}; + + +class String : public Value +{ +public: + String(std::string _value) : value(_value) {} + + void visit(Visitor &visitor); + + std::string value; +}; + + +class Const : public Value +{ +public: + Const(std::string _name, Value *_value) : name(_name), value(_value) {} + + void visit(Visitor &visitor); + + std::string name; + Value *value; +}; + + +class Array : public Value +{ +public: + Array(size_t len) : values(len) {} + + void visit(Visitor &visitor); + + std::vector values; +}; + + +class Visitor +{ +public: + virtual void visit(Void *) {assert(0);} + virtual void visit(Bool *) {assert(0);} + virtual void visit(SInt *) {assert(0);} + virtual void visit(UInt *) {assert(0);} + virtual void visit(Float *) {assert(0);} + virtual void visit(String *) {assert(0);} + virtual void visit(Const *) {assert(0);} + virtual void visit(Array *) {assert(0);} +}; + + +std::ostream & operator <<(std::ostream &os, Value *value); + + +signed long long asSInt(const Value *node); +unsigned long long asUInt(const Value *node); +double asFloat(const Value *node); + + +typedef std::pair Arg; + +class Call +{ +public: + std::string name; + std::list args; + Value *ret; + + Call() : ret(0) { } + + Value * get_arg(const char *name) { + for (std::list::iterator it = args.begin(); it != args.end(); ++it) { + if (it->first == name) { + return it->second; + } + } + return NULL; + } +}; + + + +std::ostream & operator <<(std::ostream &os, Call &call); + + +} /* namespace Trace */ + +#endif /* _TRACE_MODEL_HPP_ */ diff --git a/trace_parser.hpp b/trace_parser.hpp new file mode 100644 index 0000000..50f315c --- /dev/null +++ b/trace_parser.hpp @@ -0,0 +1,253 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#ifndef _TRACE_PARSER_HPP_ +#define _TRACE_PARSER_HPP_ + + +#include + +#include + +#include + +#include "trace_format.hpp" +#include "trace_model.hpp" + + +namespace Trace { + + +class Parser +{ +protected: + gzFile file; +public: + Parser() { + file = NULL; + } + + bool parse(const char *filename) { + unsigned long long version; + + file = gzopen(filename, "rb"); + if (!file) { + return false; + } + + version = read_uint(); + if (version != TRACE_VERSION) { + std::cerr << "Unsupported format version" << version << "\n"; + return false; + } + + while (!gzeof(file)) { + parse_call(); + } + + return true; + } + + void parse_call(void) { + Call call; + call.name = read_string(); + int c; + do { + c = gzgetc(file); + if (c == Trace::CALL_END || c == -1) { + break; + } + switch(c) { + case Trace::CALL_END: + return; + case Trace::CALL_ARG: + call.args.push_back(parse_arg()); + break; + case Trace::CALL_RET: + call.ret = parse_value(); + break; + default: + assert(0); + std::cerr << "Unknown call detail " << c << "\n"; + break; + } + } while(true); + handle_call(call); + } + + virtual void handle_call(Call &call) { + std::cout << call; + } + + Arg parse_arg(void) { + std::string name = read_string(); + Value *value = parse_value(); + return Arg(name, value); + } + + Value *parse_value(void) { + int c; + c = gzgetc(file); + switch(c) { + case Trace::TYPE_BOOL: + return parse_bool(); + case Trace::TYPE_SINT: + return parse_sint(); + case Trace::TYPE_UINT: + return parse_uint(); + case Trace::TYPE_FLOAT: + return parse_float(); + case Trace::TYPE_DOUBLE: + return parse_double(); + case Trace::TYPE_STRING: + return parse_string(); + case Trace::TYPE_CONST: + return parse_const(); + case Trace::TYPE_BITMASK: + return parse_bitmask(); + case Trace::TYPE_ARRAY: + return parse_array(); + case Trace::TYPE_POINTER: + return parse_pointer(); + case Trace::TYPE_VOID: + return NULL; + default: + std::cerr << "Unknown type " << c << "\n"; + assert(0); + return NULL; + } + } + + Value *parse_bool() { + int c; + c = gzgetc(file); + return new Bool(c); + } + + Value *parse_sint() { + return new SInt(-read_uint()); + } + + Value *parse_uint() { + return new UInt(read_uint()); + } + + Value *parse_float() { + float value; + gzread(file, &value, sizeof value); + return new Float(value); + } + + Value *parse_double() { + double value; + gzread(file, &value, sizeof value); + return new Float(value); + } + + Value *parse_string() { + return new String(read_string()); + } + + Value *parse_const() { + std::string name = read_string(); + Value *value = parse_value(); + return new Const(name, value); + } + + Value *parse_bitmask() { + unsigned long long value = 0; + int c; + do { + c = gzgetc(file); + switch(c) { + case Trace::TYPE_SINT: + value |= -read_uint(); + break; + case Trace::TYPE_UINT: + value |= read_uint(); + break; + case Trace::TYPE_CONST: + read_string(); + break; + case Trace::TYPE_VOID: + goto done; + default: + std::cerr << "Unexpected type " << c << "\n"; + assert(0); + return NULL; + } + } while(true); +done: + return new UInt(value); + } + + Value *parse_array() { + size_t len = read_uint(); + Array *array = new Array(len); + for (size_t i = 0; i < len; ++i) { + array->values[i] = parse_value(); + } + return array; + } + + Value *parse_pointer() { + unsigned long long addr; + Value *value; + addr = read_uint(); + value = parse_value(); + if (!value) + value = new UInt(addr); + return value; + } + + std::string read_string(void) { + size_t len = read_uint(); + char * buf = new char[len]; + gzread(file, buf, len); + std::string value(buf, len); + delete [] buf; + return value; + } + + unsigned long long read_uint(void) { + unsigned long long value = 0; + int c; + unsigned shift = 0; + do { + c = gzgetc(file); + if (c == -1) { + break; + } + value |= (unsigned long long)(c & 0x7f) << shift; + shift += 7; + } while(c & 0x80); + return value; + } +}; + + +} /* namespace Trace */ + +#endif /* _TRACE_PARSER_HPP_ */ diff --git a/xml2txt.py b/xml2txt.py deleted file mode 100755 index e0c5efd..0000000 --- a/xml2txt.py +++ /dev/null @@ -1,451 +0,0 @@ -#!/usr/bin/env python -########################################################################## -# -# Copyright 2008-2009 VMware, Inc. -# All Rights Reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -##########################################################################/ - - -import sys -import optparse -import xml.parsers.expat -import gzip - -from model import * - - -ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4) - - -class XmlToken: - - def __init__(self, type, name_or_data, attrs = None, line = None, column = None): - assert type in (ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF) - self.type = type - self.name_or_data = name_or_data - self.attrs = attrs - self.line = line - self.column = column - - def __str__(self): - if self.type == ELEMENT_START: - return '<' + self.name_or_data + ' ...>' - if self.type == ELEMENT_END: - return '' - if self.type == CHARACTER_DATA: - return self.name_or_data - if self.type == EOF: - return 'end of file' - assert 0 - - -class XmlTokenizer: - """Expat based XML tokenizer.""" - - def __init__(self, fp, skip_ws = True): - self.fp = fp - self.tokens = [] - self.index = 0 - self.final = False - self.skip_ws = skip_ws - - self.character_pos = 0, 0 - self.character_data = '' - - self.parser = xml.parsers.expat.ParserCreate() - self.parser.StartElementHandler = self.handle_element_start - self.parser.EndElementHandler = self.handle_element_end - self.parser.CharacterDataHandler = self.handle_character_data - - def handle_element_start(self, name, attributes): - self.finish_character_data() - line, column = self.pos() - token = XmlToken(ELEMENT_START, name, attributes, line, column) - self.tokens.append(token) - - def handle_element_end(self, name): - self.finish_character_data() - line, column = self.pos() - token = XmlToken(ELEMENT_END, name, None, line, column) - self.tokens.append(token) - - def handle_character_data(self, data): - if not self.character_data: - self.character_pos = self.pos() - self.character_data += data - - def finish_character_data(self): - if self.character_data: - if not self.skip_ws or not self.character_data.isspace(): - line, column = self.character_pos - token = XmlToken(CHARACTER_DATA, self.character_data, None, line, column) - self.tokens.append(token) - self.character_data = '' - - def next(self): - size = 16*1024 - while self.index >= len(self.tokens) and not self.final: - self.tokens = [] - self.index = 0 - data = self.fp.read(size) - self.final = len(data) < size - data = data.rstrip('\0') - try: - self.parser.Parse(data, self.final) - except xml.parsers.expat.ExpatError, e: - #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS: - if e.code == 3: - pass - else: - raise e - if self.index >= len(self.tokens): - line, column = self.pos() - token = XmlToken(EOF, None, None, line, column) - else: - token = self.tokens[self.index] - self.index += 1 - return token - - def pos(self): - return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber - - -class TokenMismatch(Exception): - - def __init__(self, expected, found): - self.expected = expected - self.found = found - - def __str__(self): - return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found)) - - - -class XmlParser: - """Base XML document parser.""" - - def __init__(self, fp): - self.tokenizer = XmlTokenizer(fp) - self.consume() - - def consume(self): - self.token = self.tokenizer.next() - - def match_element_start(self, name): - return self.token.type == ELEMENT_START and self.token.name_or_data == name - - def match_element_end(self, name): - return self.token.type == ELEMENT_END and self.token.name_or_data == name - - def element_start(self, name): - while self.token.type == CHARACTER_DATA: - self.consume() - if self.token.type != ELEMENT_START: - raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token) - if self.token.name_or_data != name: - raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token) - attrs = self.token.attrs - self.consume() - return attrs - - def element_end(self, name): - while self.token.type == CHARACTER_DATA: - self.consume() - if self.token.type != ELEMENT_END: - raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token) - if self.token.name_or_data != name: - raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token) - self.consume() - - def character_data(self, strip = True): - data = '' - while self.token.type == CHARACTER_DATA: - data += self.token.name_or_data - self.consume() - if strip: - data = data.strip() - return data - - -class GzipFile(gzip.GzipFile): - - def _read_eof(self): - # Ignore incomplete files - try: - gzip.GzipFile._read_eof(self) - except IOError: - pass - - -class TraceParser(XmlParser): - - def __init__(self, stream): - XmlParser.__init__(self, stream) - self.call_no = 0 - - def parse(self): - self.element_start('trace') - while self.token.type not in (ELEMENT_END, EOF): - self.parse_call() - if self.token.type != EOF: - self.element_end('trace') - - def parse_call(self): - attrs = self.element_start('call') - name = attrs['name'] - args = [] - ret = None - properties = {} - while self.token.type == ELEMENT_START: - if self.token.name_or_data == 'arg': - arg = self.parse_arg() - args.append(arg) - elif self.token.name_or_data == 'ret': - ret = self.parse_ret() - elif self.token.name_or_data in ('duration', 'starttsc', 'endtsc'): - property = self.token.name_or_data - properties[property] = self.parse_hex(self.token.name_or_data) - elif self.token.name_or_data == 'call': - # ignore nested function calls - self.parse_call() - else: - raise TokenMismatch(" or ", self.token) - self.element_end('call') - - self.call_no += 1 - - call = Call(self.call_no, name, args, ret, properties) - - self.handle_call(call) - - def parse_arg(self): - attrs = self.element_start('arg') - name = attrs['name'] - value = self.parse_value() - self.element_end('arg') - - return name, value - - def parse_ret(self): - attrs = self.element_start('ret') - value = self.parse_value() - self.element_end('ret') - - return value - - def parse_hex(self, token_name): - attrs = self.element_start(token_name) - value = int(self.character_data(), 16) - self.element_end(token_name) - return value - - def parse_value(self): - if self.token.type == ELEMENT_START: - if self.token.name_or_data == 'int': - return self.parse_int() - if self.token.name_or_data == 'uint': - return self.parse_uint() - if self.token.name_or_data == 'float': - return self.parse_float() - if self.token.name_or_data == 'string': - return self.parse_string() - if self.token.name_or_data == 'wstring': - return self.parse_wstring() - if self.token.name_or_data == 'const': - return self.parse_const() - if self.token.name_or_data == 'bitmask': - return self.parse_bitmask() - if self.token.name_or_data == 'ref': - return self.parse_ref() - raise TokenMismatch(", , or text", self.token) - - def parse_elems(self): - elems = [self.parse_elem()] - while self.token.type != ELEMENT_END: - elems.append(self.parse_elem()) - return Struct("", elems) - - def parse_elem(self): - attrs = self.element_start('elem') - value = self.parse_value() - self.element_end('elem') - - try: - name = attrs['name'] - except KeyError: - name = "" - - return name, value - - def parse_ref(self): - attrs = self.element_start('ref') - if self.token.type != ELEMENT_END: - value = self.parse_value() - else: - value = None - self.element_end('ref') - - return Pointer(attrs['addr'], value) - - def parse_bitmask(self): - self.element_start('bitmask') - elems = [] - while self.token.type != ELEMENT_END: - elems.append(self.parse_value()) - self.element_end('bitmask') - return Bitmask(elems) - - def parse_int(self): - self.element_start('int') - value = self.character_data() - self.element_end('int') - return Literal(int(value)) - - def parse_uint(self): - self.element_start('uint') - value = self.character_data() - self.element_end('uint') - return Literal(int(value)) - - def parse_float(self): - self.element_start('float') - value = self.character_data() - self.element_end('float') - return Literal(float(value)) - - def parse_string(self): - self.element_start('string') - value = self.character_data() - self.element_end('string') - return Literal(value) - - def parse_wstring(self): - self.element_start('wstring') - value = self.character_data() - self.element_end('wstring') - return Literal(value) - - def parse_const(self): - self.element_start('const') - value = self.character_data() - self.element_end('const') - return NamedConstant(value) - - def handle_call(self, call): - pass - - -class DumpTraceParser(TraceParser): - - def __init__(self, stream, formatter): - XmlParser.__init__(self, stream) - self.formatter = formatter - self.pretty_printer = PrettyPrinter(self.formatter) - self.call_no = 0 - - def handle_call(self, call): - call.visit(self.pretty_printer) - self.formatter.newline() - - -class StatsTraceParser(TraceParser): - - def __init__(self, stream, formatter): - TraceParser.__init__(self, stream, formatter) - self.stats = {} - - def parse(self): - TraceParser.parse(self) - - sys.stdout.write('%s\t%s\t%s\n' % ("name", "calls", "duration")) - for name, (calls, duration) in self.stats.iteritems(): - sys.stdout.write('%s\t%u\t%f\n' % (name, calls, duration/1000000.0)) - - def handle_call(self, name, args, ret, duration): - try: - nr_calls, total_duration = self.stats[name] - except KeyError: - nr_calls = 1 - total_duration = duration - else: - nr_calls += 1 - if duration is not None: - total_duration += duration - self.stats[name] = nr_calls, total_duration - - -class Main: - - def __init__(self): - pass - - def main(self): - optparser = self.get_optparser() - (options, args) = optparser.parse_args(sys.argv[1:]) - - if args: - for arg in args: - if arg.endswith('.gz'): - from gzip import GzipFile - stream = GzipFile(arg, 'rb') - elif arg.endswith('.bz2'): - from bz2 import BZ2File - stream = BZ2File(arg, 'rU') - else: - stream = open(arg, 'rt') - self.process_arg(stream, options) - else: - self.process_arg(stream, options) - - def get_optparser(self): - optparser = optparse.OptionParser( - usage="\n\t%prog [options] [traces] ...") - optparser.add_option( - '-s', '--stats', - action="store_true", - dest="stats", default=False, - help="generate statistics instead") - optparser.add_option( - '--color', '--colour', - type="choice", choices=('never', 'always', 'auto'), metavar='WHEN', - dest="color", default="always", - help="coloring: never, always, or auto [default: %default]") - return optparser - - def process_arg(self, stream, options): - if options.color == 'always' or options.color == 'auto' and sys.stdout.isatty(): - formatter = format.DefaultFormatter(sys.stdout) - else: - formatter = format.Formatter(sys.stdout) - - if options.stats: - factory = StatsTraceParser - else: - factory = DumpTraceParser - - parser = DumpTraceParser(stream, formatter) - parser.parse() - - -if __name__ == '__main__': - Main().main() - -- 2.43.0