From: José Fonseca Date: Wed, 21 Sep 2011 06:46:50 +0000 (+0100) Subject: Put all common code in a subdirectory. X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=a8c164caecc408462d3e4c1626c87ab9974f6a48;p=apitrace Put all common code in a subdirectory. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c91c90..360e830 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,7 +163,10 @@ include_directories (${CMAKE_CURRENT_SOURCE_DIR}/thirdparty) ############################################################################## # Common libraries / utilities -include_directories (${CMAKE_CURRENT_SOURCE_DIR}) +include_directories ( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/common +) add_custom_command ( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp @@ -180,19 +183,19 @@ else (WIN32) endif (WIN32) add_library (common - trace_file.cpp - trace_snappyfile.cpp - trace_model.cpp - trace_parser.cpp - trace_writer.cpp - trace_local_writer.cpp - trace_model_writer.cpp - trace_loader.cpp - image.cpp - image_bmp.cpp - image_pnm.cpp - image_png.cpp - ${os} + common/trace_file.cpp + common/trace_snappyfile.cpp + common/trace_model.cpp + common/trace_parser.cpp + common/trace_writer.cpp + common/trace_local_writer.cpp + common/trace_model_writer.cpp + common/trace_loader.cpp + common/image.cpp + common/image_bmp.cpp + common/image_pnm.cpp + common/image_png.cpp + common/${os} ) set_target_properties (common PROPERTIES @@ -383,7 +386,6 @@ add_executable (glretrace glstate_params.cpp retrace.cpp ${glws} - image.cpp ${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp ) diff --git a/common/formatter.hpp b/common/formatter.hpp new file mode 100644 index 0000000..181e2d1 --- /dev/null +++ b/common/formatter.hpp @@ -0,0 +1,174 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +/* + * Helpers for coloring output. + */ + +#ifndef _FORMATTER_HPP_ +#define _FORMATTER_HPP_ + + +#include + + +namespace Formatter { + +/* + * See also http://bytes.com/topic/c/answers/63822-design-question-little-c-header-colorizing-text-linux-comments-ideas + */ + +class Attribute { +public: + virtual ~Attribute() {} + + virtual void apply(std::ostream &) const {} +}; + + +enum Color { + RED, + GREEN, + BLUE, +}; + + +class Formatter { +public: + virtual ~Formatter() {} + + virtual Attribute *normal(void) const { return new Attribute; } + virtual Attribute *bold(void) const { return new Attribute; } + virtual Attribute *italic(void) const { return new Attribute; } + virtual Attribute *color(Color) const { return new Attribute; } +}; + + +class AnsiAttribute : public Attribute { +protected: + const char *escape; +public: + AnsiAttribute(const char *_escape) : escape(_escape) {} + void apply(std::ostream& os) const { + os << "\33[" << escape; + } +}; + + +/** + * Formatter for plain-text files which outputs ANSI escape codes. See + * http://en.wikipedia.org/wiki/ANSI_escape_code for more information + * concerning ANSI escape codes. + */ +class AnsiFormatter : public Formatter { +protected: +public: + virtual Attribute *normal(void) const { return new AnsiAttribute("0m"); } + virtual Attribute *bold(void) const { return new AnsiAttribute("1m"); } + virtual Attribute *italic(void) const { return new AnsiAttribute("3m"); } + virtual Attribute *color(Color c) const { + static const char *color_escapes[] = { + "31m", /* red */ + "32m", /* green */ + "34m", /* blue */ + }; + return new AnsiAttribute(color_escapes[c]); + } +}; + + +inline std::ostream& operator<<(std::ostream& os, const Attribute *attr) { + attr->apply(os); + return os; +} + + +#ifdef _WIN32 + +#include + +class WindowsAttribute : public Attribute { +protected: + WORD wAttributes; +public: + WindowsAttribute(WORD _wAttributes) : wAttributes(_wAttributes) {} + void apply(std::ostream& os) const { + DWORD nStdHandleOutput; + if (os == std::cout) { + nStdHandleOutput = STD_OUTPUT_HANDLE; + } else if (os == std::cerr) { + nStdHandleOutput = STD_ERROR_HANDLE; + } else { + return; + } + HANDLE hConsoleOutput = GetStdHandle(nStdHandleOutput); + if (hConsoleOutput == INVALID_HANDLE_VALUE) { + return; + } + + SetConsoleTextAttribute(hConsoleOutput, wAttributes); + } +}; + + +/** + * Formatter for the Windows Console. + */ +class WindowsFormatter : public Formatter { +protected: +public: + virtual Attribute *normal(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); } + virtual Attribute *bold(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); } + virtual Attribute *italic(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); } + virtual Attribute *color(Color c) const { + static const WORD color_escapes[] = { + FOREGROUND_RED | FOREGROUND_INTENSITY, + FOREGROUND_GREEN | FOREGROUND_INTENSITY, + FOREGROUND_BLUE | FOREGROUND_INTENSITY, + }; + return new WindowsAttribute(color_escapes[c]); + } +}; + +#endif + + +inline Formatter *defaultFormatter(bool color = true) { + if (color) { +#ifdef _WIN32 + return new WindowsFormatter; +#else + return new AnsiFormatter; +#endif + } else { + return new Formatter; + } +} + + +} /* namespace Formatter */ + + +#endif /* _FORMATTER_HPP_ */ diff --git a/common/image.cpp b/common/image.cpp new file mode 100644 index 0000000..4da9c13 --- /dev/null +++ b/common/image.cpp @@ -0,0 +1,76 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * Copyright 2008-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 +#include + +#include "image.hpp" + + +namespace Image { + + +double Image::compare(Image &ref) +{ + if (width != ref.width || + height != ref.height || + channels != ref.channels) { + return 0.0; + } + + const unsigned char *pSrc = start(); + const unsigned char *pRef = ref.start(); + + assert(channels >= 3); + + unsigned long long error = 0; + for (unsigned y = 0; y < height; ++y) { + for (unsigned x = 0; x < width; ++x) { + // FIXME: Ignore alpha channel until we are able to pick a visual + // that matches the traces + for (unsigned c = 0; c < 3; ++c) { + int delta = pSrc[x*channels + c] - pRef[x*channels + c]; + error += delta*delta; + } + } + + pSrc += stride(); + pRef += ref.stride(); + } + + double numerator = error*2 + 1; + double denominator = height*width*3ULL*255ULL*255ULL*2; + double quotient = numerator/denominator; + + // Precision in bits + double precision = -log(quotient)/log(2.0); + + return precision; +} + + +} /* namespace Image */ diff --git a/common/image.hpp b/common/image.hpp new file mode 100644 index 0000000..dc53ec9 --- /dev/null +++ b/common/image.hpp @@ -0,0 +1,115 @@ +/************************************************************************** + * + * Copyright 2008-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. + * + **************************************************************************/ + +/* + * Image I/O. + */ + +#ifndef _IMAGE_HPP_ +#define _IMAGE_HPP_ + + +#include + + +namespace Image { + + +class Image { +public: + unsigned width; + unsigned height; + unsigned channels; + + // Flipped vertically or not + bool flipped; + + // Pixels in RGBA format + unsigned char *pixels; + + inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) : + width(w), + height(h), + channels(c), + flipped(f), + pixels(new unsigned char[h*w*c]) + {} + + inline ~Image() { + delete [] pixels; + } + + inline unsigned char *start(void) { + return flipped ? pixels + (height - 1)*width*channels : pixels; + } + + inline const unsigned char *start(void) const { + return flipped ? pixels + (height - 1)*width*channels : pixels; + } + + inline unsigned char *end(void) { + return flipped ? pixels - width*channels : pixels + height*width*channels; + } + + inline const unsigned char *end(void) const { + return flipped ? pixels - width*channels : pixels + height*width*channels; + } + + inline signed stride(void) const { + return flipped ? -width*channels : width*channels; + } + + bool writeBMP(const char *filename) const; + + void writePNM(std::ostream &os, const char *comment = NULL) const; + + inline bool writePNM(const char *filename, const char *comment = NULL) const { + std::ofstream os(filename, std::ofstream::binary); + if (!os) { + return false; + } + writePNM(os, comment); + return true; + } + + bool writePNG(const char *filename) const; + + double compare(Image &ref); +}; + +bool writePixelsToBuffer(unsigned char *pixels, + unsigned w, unsigned h, unsigned numChannels, + bool flipped, + char **buffer, + int *size); + +Image * +readPNG(const char *filename); + + +} /* namespace Image */ + + +#endif /* _IMAGE_HPP_ */ diff --git a/common/image_bmp.cpp b/common/image_bmp.cpp new file mode 100644 index 0000000..346f39a --- /dev/null +++ b/common/image_bmp.cpp @@ -0,0 +1,139 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * Copyright 2008-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 +#include + +#include "image.hpp" + + +namespace Image { + + +#pragma pack(push,2) +struct FileHeader { + uint16_t bfType; + uint32_t bfSize; + uint16_t bfReserved1; + uint16_t bfReserved2; + uint32_t bfOffBits; +}; +#pragma pack(pop) + +struct InfoHeader { + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + int32_t biXPelsPerMeter; + int32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; +}; + +struct Pixel { + uint8_t rgbBlue; + uint8_t rgbGreen; + uint8_t rgbRed; + uint8_t rgbAlpha; +}; + + +bool +Image::writeBMP(const char *filename) const { + assert(channels == 4); + + struct FileHeader bmfh; + struct InfoHeader bmih; + unsigned x, y; + + bmfh.bfType = 0x4d42; + bmfh.bfSize = 14 + 40 + height*width*4; + bmfh.bfReserved1 = 0; + bmfh.bfReserved2 = 0; + bmfh.bfOffBits = 14 + 40; + + bmih.biSize = 40; + bmih.biWidth = width; + bmih.biHeight = height; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = 0; + bmih.biSizeImage = height*width*4; + bmih.biXPelsPerMeter = 0; + bmih.biYPelsPerMeter = 0; + bmih.biClrUsed = 0; + bmih.biClrImportant = 0; + + std::ofstream stream(filename, std::ofstream::binary); + + if (!stream) { + return false; + } + + stream.write((const char *)&bmfh, 14); + stream.write((const char *)&bmih, 40); + + unsigned stride = width*4; + + if (flipped) { + for (y = 0; y < height; ++y) { + const unsigned char *ptr = pixels + y * stride; + for (x = 0; x < width; ++x) { + struct Pixel pixel; + pixel.rgbRed = ptr[x*4 + 0]; + pixel.rgbGreen = ptr[x*4 + 1]; + pixel.rgbBlue = ptr[x*4 + 2]; + pixel.rgbAlpha = ptr[x*4 + 3]; + stream.write((const char *)&pixel, 4); + } + } + } else { + y = height; + while (y--) { + const unsigned char *ptr = pixels + y * stride; + for (x = 0; x < width; ++x) { + struct Pixel pixel; + pixel.rgbRed = ptr[x*4 + 0]; + pixel.rgbGreen = ptr[x*4 + 1]; + pixel.rgbBlue = ptr[x*4 + 2]; + pixel.rgbAlpha = ptr[x*4 + 3]; + stream.write((const char *)&pixel, 4); + } + } + } + + stream.close(); + + return true; +} + + +} /* namespace Image */ diff --git a/common/image_png.cpp b/common/image_png.cpp new file mode 100644 index 0000000..fd22213 --- /dev/null +++ b/common/image_png.cpp @@ -0,0 +1,312 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * Copyright 2008-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 +#include + +#include +#include +#include + +#include + +#include "image.hpp" + + +namespace Image { + + +bool +Image::writePNG(const char *filename) const { + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + + fp = fopen(filename, "wb"); + if (!fp) + goto no_fp; + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + goto no_png; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, NULL); + goto no_png; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + goto no_png; + } + + png_init_io(png_ptr, fp); + + int color_type; + switch (channels) { + case 4: + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case 3: + color_type = PNG_COLOR_TYPE_RGB; + break; + case 2: + color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + break; + case 1: + color_type = PNG_COLOR_TYPE_GRAY; + break; + default: + assert(0); + return false; + } + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); + + png_write_info(png_ptr, info_ptr); + + if (!flipped) { + for (unsigned y = 0; y < height; ++y) { + png_bytep row = (png_bytep)(pixels + y*width*channels); + png_write_rows(png_ptr, &row, 1); + } + } else { + unsigned y = height; + while (y--) { + png_bytep row = (png_bytep)(pixels + y*width*channels); + png_write_rows(png_ptr, &row, 1); + } + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(fp); + return true; + +no_png: + fclose(fp); +no_fp: + return false; +} + + +Image * +readPNG(const char *filename) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + png_infop end_info; + Image *image; + + fp = fopen(filename, "rb"); + if (!fp) + goto no_fp; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + goto no_png; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + goto no_png; + } + + end_info = png_create_info_struct(png_ptr); + if (!end_info) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + goto no_png; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + goto no_png; + } + + png_init_io(png_ptr, fp); + + png_read_info(png_ptr, info_ptr); + + png_uint_32 width, height; + int bit_depth, color_type, interlace_type, compression_type, filter_method; + + png_get_IHDR(png_ptr, info_ptr, + &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_method); + + image = new Image(width, height); + if (!image) + goto no_image; + + /* Convert to RGBA8 */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_gray_1_2_4_to_8(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + if (bit_depth == 16) + png_set_strip_16(png_ptr); + + for (unsigned y = 0; y < height; ++y) { + png_bytep row = (png_bytep)(image->pixels + y*width*4); + png_read_row(png_ptr, row, NULL); + } + + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(fp); + return image; + +no_image: + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); +no_png: + fclose(fp); +no_fp: + return NULL; +} + + +struct png_tmp_buffer +{ + char *buffer; + size_t size; +}; + +static void +pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) +{ + struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_get_io_ptr(png_ptr); + size_t nsize = buf->size + length; + + /* allocate or grow buffer */ + if (buf->buffer) + buf->buffer = (char*)realloc(buf->buffer, nsize); + else + buf->buffer = (char*)malloc(nsize); + + if (!buf->buffer) + png_error(png_ptr, "Buffer allocation error"); + + memcpy(buf->buffer + buf->size, data, length); + buf->size += length; +} + +bool writePixelsToBuffer(unsigned char *pixels, + unsigned width, unsigned height, unsigned numChannels, + bool flipped, + char **buffer, + int *size) +{ + struct png_tmp_buffer png_mem; + png_structp png_ptr; + png_infop info_ptr; + int type; + + png_mem.buffer = NULL; + png_mem.size = 0; + + switch (numChannels) { + case 4: + type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case 3: + type = PNG_COLOR_TYPE_RGB; + break; + case 2: + type = PNG_COLOR_TYPE_GRAY_ALPHA; + break; + case 1: + type = PNG_COLOR_TYPE_GRAY; + break; + default: + goto no_png; + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + goto no_png; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, NULL); + goto no_png; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + goto no_png; + } + + png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL); + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, + type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); + + png_write_info(png_ptr, info_ptr); + + if (!flipped) { + for (unsigned y = 0; y < height; ++y) { + png_bytep row = (png_bytep)(pixels + y*width*numChannels); + png_write_rows(png_ptr, &row, 1); + } + } else { + unsigned y = height; + while (y--) { + png_bytep row = (png_bytep)(pixels + y*width*numChannels); + png_write_rows(png_ptr, &row, 1); + } + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + *buffer = png_mem.buffer; + *size = png_mem.size; + + return true; + +no_png: + *buffer = NULL; + *size = 0; + + if (png_mem.buffer) + free(png_mem.buffer); + return false; +} + +} /* namespace Image */ diff --git a/common/image_pnm.cpp b/common/image_pnm.cpp new file mode 100644 index 0000000..5397a1a --- /dev/null +++ b/common/image_pnm.cpp @@ -0,0 +1,112 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * Copyright 2008-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 +#include +#include + +#include "image.hpp" + + +namespace Image { + +/** + * http://en.wikipedia.org/wiki/Netpbm_format + * http://netpbm.sourceforge.net/doc/ppm.html + */ +void +Image::writePNM(std::ostream &os, const char *comment) const { + assert(channels == 1 || channels >= 3); + + os << (channels == 1 ? "P5" : "P6") << "\n"; + if (comment) { + os << "#" << comment << "\n"; + } + os << width << " " << height << "\n"; + os << "255" << "\n"; + + const unsigned char *row; + + if (channels == 1 || channels == 3) { + for (row = start(); row != end(); row += stride()) { + os.write((const char *)row, width*channels); + } + } else { + unsigned char *tmp = new unsigned char[width*3]; + if (channels == 4) { + for (row = start(); row != end(); row += stride()) { + const uint32_t *src = (const uint32_t *)row; + uint32_t *dst = (uint32_t *)tmp; + unsigned x; + for (x = 0; x + 4 <= width; x += 4) { + /* + * It's much faster to access dwords than bytes. + * + * FIXME: Big-endian version. + */ + + uint32_t rgba0 = *src++ & 0xffffff; + uint32_t rgba1 = *src++ & 0xffffff; + uint32_t rgba2 = *src++ & 0xffffff; + uint32_t rgba3 = *src++ & 0xffffff; + uint32_t rgb0 = rgba0 + | (rgba1 << 24); + uint32_t rgb1 = (rgba1 >> 8) + | (rgba2 << 16); + uint32_t rgb2 = (rgba2 >> 16) + | (rgba3 << 8); + *dst++ = rgb0; + *dst++ = rgb1; + *dst++ = rgb2; + } + for (; x < width; ++x) { + tmp[x*3 + 0] = row[x*4 + 0]; + tmp[x*3 + 1] = row[x*4 + 1]; + tmp[x*3 + 2] = row[x*4 + 2]; + } + os.write((const char *)tmp, width*3); + } + } else if (channels == 2) { + for (row = start(); row != end(); row += stride()) { + const unsigned char *src = row; + unsigned char *dst = tmp; + for (unsigned x = 0; x < width; ++x) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = 0; + } + os.write((const char *)tmp, width*3); + } + } else { + assert(0); + } + delete [] tmp; + } +} + + +} /* namespace Image */ diff --git a/common/json.hpp b/common/json.hpp new file mode 100644 index 0000000..9e6b960 --- /dev/null +++ b/common/json.hpp @@ -0,0 +1,337 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * 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. + * + **************************************************************************/ + +/* + * Trace writing functions. + */ + +#ifndef _JSON_HPP_ +#define _JSON_HPP_ + +#include +#include +#include + +#include +#include +#include + + +class JSONWriter +{ +private: + std::ostream &os; + + int level; + bool value; + char space; + + void newline(void) { + os << "\n"; + for (int i = 0; i < level; ++i) + os << " "; + } + + void separator(void) { + if (value) { + os << ","; + switch (space) { + case '\0': + break; + case '\n': + newline(); + break; + default: + os << space; + break; + } + } else { + if (space == '\n') { + newline(); + } + } + } + + void escapeAsciiString(const char *str) { + os << "\""; + + const unsigned char *src = (const unsigned char *)str; + unsigned char c; + while ((c = *src++)) { + if ((c == '\"') || + (c == '\\')) { + // escape character + os << '\\' << (unsigned char)c; + } else if ((c >= 0x20 && c <= 0x7e) || + c == '\t' || + c == '\r' || + c == '\n') { + // pass-through character + os << (unsigned char)c; + } else { + assert(0); + os << "?"; + } + } + + os << "\""; + } + + void escapeUnicodeString(const char *str) { + os << "\""; + + const char *locale = setlocale(LC_CTYPE, ""); + const char *src = str; + mbstate_t state; + + memset(&state, 0, sizeof state); + + do { + // Convert characters one at a time in order to recover from + // conversion errors + wchar_t c; + size_t written = mbsrtowcs(&c, &src, 1, &state); + if (written == 0) { + // completed + break; + } if (written == (size_t)-1) { + // conversion error -- skip + os << "?"; + do { + ++src; + } while (*src & 0x80); + } else if ((c == '\"') || + (c == '\\')) { + // escape character + os << '\\' << (unsigned char)c; + } else if ((c >= 0x20 && c <= 0x7e) || + c == '\t' || + c == '\r' || + c == '\n') { + // pass-through character + os << (unsigned char)c; + } else { + // unicode + os << "\\u" << std::setfill('0') << std::hex << std::setw(4) << (unsigned)c; + os << std::dec; + } + } while (src); + + setlocale(LC_CTYPE, locale); + + os << "\""; + } + + void encodeBase64String(const unsigned char *bytes, size_t size) { + const char *table64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned char c0, c1, c2, c3; + char buf[4]; + unsigned written; + + os << "\""; + + written = 0; + while (size >= 3) { + c0 = bytes[0] >> 2; + c1 = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xf0) >> 4); + c2 = ((bytes[1] & 0x0f) << 2) | ((bytes[2] & 0xc0) >> 6); + c3 = bytes[2] & 0x3f; + + buf[0] = table64[c0]; + buf[1] = table64[c1]; + buf[2] = table64[c2]; + buf[3] = table64[c3]; + + os.write(buf, 4); + + bytes += 3; + size -= 3; + ++written; + + if (written >= 76/4 && size) { + os << "\n"; + written = 0; + } + } + + if (size > 0) { + c0 = bytes[0] >> 2; + c1 = ((bytes[0] & 0x03) << 4); + buf[2] = '='; + buf[3] = '='; + + if (size > 1) { + c1 |= ((bytes[1] & 0xf0) >> 4); + c2 = ((bytes[1] & 0x0f) << 2); + if (size > 2) { + c2 |= ((bytes[2] & 0xc0) >> 6); + c3 = bytes[2] & 0x3f; + buf[3] = table64[c3]; + } + buf[2] = table64[c2]; + } + buf[1] = table64[c1]; + buf[0] = table64[c0]; + + os.write(buf, 4); + } + + os << "\""; + } + +public: + JSONWriter(std::ostream &_os) : + os(_os), + level(0), + value(false), + space(0) + { + beginObject(); + } + + ~JSONWriter() { + endObject(); + newline(); + } + + inline void beginObject() { + separator(); + os << "{"; + ++level; + value = false; + } + + inline void endObject() { + --level; + if (value) + newline(); + os << "}"; + value = true; + space = '\n'; + } + + inline void beginMember(const char * name) { + space = 0; + separator(); + newline(); + escapeAsciiString(name); + os << ": "; + value = false; + } + + inline void beginMember(const std::string &name) { + beginMember(name.c_str()); + } + + inline void endMember(void) { + assert(value); + value = true; + space = 0; + } + + inline void beginArray() { + separator(); + os << "["; + ++level; + value = false; + space = 0; + } + + inline void endArray(void) { + --level; + if (space == '\n') { + newline(); + } + os << "]"; + value = true; + space = '\n'; + } + + inline void writeString(const char *s) { + separator(); + escapeUnicodeString(s); + value = true; + space = ' '; + } + + inline void writeString(const std::string &s) { + writeString(s.c_str()); + } + + inline void writeBase64(const void *bytes, size_t size) { + separator(); + encodeBase64String((const unsigned char *)bytes, size); + value = true; + space = ' '; + } + + inline void writeNull(void) { + separator(); + os << "null"; + value = true; + space = ' '; + } + + inline void writeBool(bool b) { + separator(); + os << (b ? "true" : "false"); + value = true; + space = ' '; + } + + template + inline void writeNumber(T n) { + if (n != n) { + // NaN + writeNull(); + } else { + separator(); + os << std::dec << std::setprecision(9) << n; + value = true; + space = ' '; + } + } + + inline void writeStringMember(const char *name, const char *s) { + beginMember(name); + writeString(s); + endMember(); + } + + inline void writeBoolMember(const char *name, bool b) { + beginMember(name); + writeBool(b); + endMember(); + } + + template + inline void writeNumberMember(const char *name, T n) { + beginMember(name); + writeNumber(n); + endMember(); + } +}; + +#endif /* _JSON_HPP_ */ diff --git a/common/os.hpp b/common/os.hpp new file mode 100644 index 0000000..8e487b5 --- /dev/null +++ b/common/os.hpp @@ -0,0 +1,98 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +/* + * Simple OS abstraction layer. + */ + +#ifndef _OS_HPP_ +#define _OS_HPP_ + +#include +#include +#include + +#ifdef _WIN32 +#ifndef snprintf +#define snprintf _snprintf +#endif +#ifndef vsnprintf +#define vsnprintf _vsnprintf +#endif +#define PATH_SEP '\\' +#else /* !_WIN32 */ +#define PATH_SEP '/' +#endif /* !_WIN32 */ + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +namespace OS { + +void AcquireMutex(void); + +void ReleaseMutex(void); + +bool GetProcessName(char *str, size_t size); +bool GetCurrentDir(char *str, size_t size); + +void DebugMessage(const char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format (printf, 1, 2))) +#endif +; + +#if defined _WIN32 || defined __CYGWIN__ + /* We always use .def files on windows for now */ + #if 0 + #define PUBLIC __declspec(dllexport) + #else + #define PUBLIC + #endif + #define PRIVATE +#else + #if __GNUC__ >= 4 + #define PUBLIC __attribute__ ((visibility("default"))) + #define PRIVATE __attribute__ ((visibility("hidden"))) + #else + #define PUBLIC + #define PRIVATE + #endif +#endif + +/** + * Get the current time in microseconds from an unknown base. + */ +long long GetTime(void); + +void Abort(void); + +void SetExceptionCallback(void (*callback)(void)); +void ResetExceptionCallback(void); + +} /* namespace OS */ + +#endif /* _OS_HPP_ */ diff --git a/common/os_posix.cpp b/common/os_posix.cpp new file mode 100644 index 0000000..98a790b --- /dev/null +++ b/common/os_posix.cpp @@ -0,0 +1,236 @@ +/************************************************************************** + * + * Copyright 2010-2011 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __APPLE__ +#include +#endif + +#include "os.hpp" + + +namespace OS { + + +static pthread_mutex_t +mutex = PTHREAD_MUTEX_INITIALIZER; + + +void +AcquireMutex(void) +{ + pthread_mutex_lock(&mutex); +} + + +void +ReleaseMutex(void) +{ + pthread_mutex_unlock(&mutex); +} + + +bool +GetProcessName(char *str, size_t size) +{ + char szProcessPath[PATH_MAX + 1]; + char *lpProcessName; + + // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe +#ifdef __APPLE__ + uint32_t len = sizeof szProcessPath; + if (_NSGetExecutablePath(szProcessPath, &len) != 0) { + *str = 0; + return false; + } +#else + ssize_t len; + len = readlink("/proc/self/exe", szProcessPath, sizeof(szProcessPath) - 1); + if (len == -1) { + // /proc/self/exe is not available on setuid processes, so fallback to + // /proc/self/cmdline. + int fd = open("/proc/self/cmdline", O_RDONLY); + if (fd >= 0) { + len = read(fd, szProcessPath, sizeof(szProcessPath) - 1); + close(fd); + } + } + if (len <= 0) { + snprintf(str, size, "%i", (int)getpid()); + return true; + } +#endif + szProcessPath[len] = 0; + + lpProcessName = strrchr(szProcessPath, '/'); + lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath; + + strncpy(str, lpProcessName, size); + if (size) + str[size - 1] = 0; + + return true; +} + +bool +GetCurrentDir(char *str, size_t size) +{ + char *ret; + ret = getcwd(str, size); + str[size - 1] = 0; + return ret ? true : false; +} + +void +DebugMessage(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + fflush(stdout); + vfprintf(stderr, format, ap); + va_end(ap); +} + +long long GetTime(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec + tv.tv_sec*1000000LL; +} + +void +Abort(void) +{ + exit(0); +} + + +static void (*gCallback)(void) = NULL; + +#define NUM_SIGNALS 16 + +struct sigaction old_actions[NUM_SIGNALS]; + + +/* + * See also: + * - http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c + * - http://ggi.cvs.sourceforge.net/viewvc/ggi/ggi-core/libgg/gg/cleanup.c?view=markup + */ +static void signal_handler(int sig, siginfo_t *info, void *context) +{ + static int recursion_count = 0; + + fprintf(stderr, "signal_handler: sig = %i\n", sig); + + if (recursion_count) { + fprintf(stderr, "recursion with sig %i\n", sig); + } else { + if (gCallback) { + ++recursion_count; + gCallback(); + --recursion_count; + } + } + + struct sigaction *old_action; + if (sig >= NUM_SIGNALS) { + /* This should never happen */ + fprintf(stderr, "Unexpected signal %i\n", sig); + raise(SIGKILL); + } + old_action = &old_actions[sig]; + + if (old_action->sa_flags & SA_SIGINFO) { + // Handler is in sa_sigaction + old_action->sa_sigaction(sig, info, context); + } else { + if (old_action->sa_handler == SIG_DFL) { + fprintf(stderr, "taking default action for signal %i\n", sig); + +#if 1 + struct sigaction dfl_action; + dfl_action.sa_handler = SIG_DFL; + sigemptyset (&dfl_action.sa_mask); + dfl_action.sa_flags = 0; + sigaction(sig, &dfl_action, NULL); + + raise(sig); +#else + raise(SIGKILL); +#endif + } else if (old_action->sa_handler == SIG_IGN) { + /* ignore */ + } else { + /* dispatch to handler */ + old_action->sa_handler(sig); + } + } +} + +void +SetExceptionCallback(void (*callback)(void)) +{ + assert(!gCallback); + if (!gCallback) { + gCallback = callback; + + struct sigaction new_action; + new_action.sa_sigaction = signal_handler; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_SIGINFO | SA_RESTART; + + + for (int sig = 1; sig < NUM_SIGNALS; ++sig) { + // SIGKILL and SIGSTOP can't be handled + if (sig != SIGKILL && sig != SIGSTOP) { + if (sigaction(sig, NULL, &old_actions[sig]) >= 0) { + sigaction(sig, &new_action, NULL); + } + } + } + } +} + +void +ResetExceptionCallback(void) +{ + gCallback = NULL; +} + +} /* namespace OS */ + diff --git a/common/os_win32.cpp b/common/os_win32.cpp new file mode 100644 index 0000000..587503c --- /dev/null +++ b/common/os_win32.cpp @@ -0,0 +1,175 @@ +/************************************************************************** + * + * 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 +#include +#include +#include +#include + +#include "os.hpp" + + +namespace OS { + + +/* + * Trick from http://locklessinc.com/articles/pthreads_on_windows/ + */ +static CRITICAL_SECTION +CriticalSection = { + (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0 +}; + + +void +AcquireMutex(void) +{ + EnterCriticalSection(&CriticalSection); +} + + +void +ReleaseMutex(void) +{ + LeaveCriticalSection(&CriticalSection); +} + + +bool +GetProcessName(char *str, size_t size) +{ + char szProcessPath[PATH_MAX]; + char *lpProcessName; + char *lpProcessExt; + + GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0])); + + lpProcessName = strrchr(szProcessPath, '\\'); + lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath; + + lpProcessExt = strrchr(lpProcessName, '.'); + if (lpProcessExt) { + *lpProcessExt = '\0'; + } + + strncpy(str, lpProcessName, size); + + return true; +} + +bool +GetCurrentDir(char *str, size_t size) +{ + DWORD ret; + ret = GetCurrentDirectoryA(size, str); + str[size - 1] = 0; + return ret == 0 ? false : true; +} + +void +DebugMessage(const char *format, ...) +{ + char buf[4096]; + + va_list ap; + va_start(ap, format); + fflush(stdout); + vsnprintf(buf, sizeof buf, format, ap); + va_end(ap); + + OutputDebugStringA(buf); + + /* + * Also write the message to stderr, when a debugger is not present (to + * avoid duplicate messages in command line debuggers). + */ +#if _WIN32_WINNT > 0x0400 + if (!IsDebuggerPresent()) { + fflush(stdout); + fputs(buf, stderr); + fflush(stderr); + } +#endif +} + +long long GetTime(void) +{ + static LARGE_INTEGER frequency; + LARGE_INTEGER counter; + if (!frequency.QuadPart) + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&counter); + return counter.QuadPart*1000000LL/frequency.QuadPart; +} + +void +Abort(void) +{ +#ifndef NDEBUG + DebugBreak(); +#else + ExitProcess(0); +#endif +} + + +static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL; +static void (*gCallback)(void) = NULL; + +static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo) +{ + if (gCallback) { + gCallback(); + } + + if (prevExceptionFilter) { + return prevExceptionFilter(pExceptionInfo); + } else { + return EXCEPTION_CONTINUE_SEARCH; + } +} + +void +SetExceptionCallback(void (*callback)(void)) +{ + assert(!gCallback); + + if (!gCallback) { + gCallback = callback; + + assert(!prevExceptionFilter); + prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter); + } +} + +void +ResetExceptionCallback(void) +{ + gCallback = NULL; +} + + +} /* namespace OS */ diff --git a/common/trace_file.cpp b/common/trace_file.cpp new file mode 100644 index 0000000..f48c1aa --- /dev/null +++ b/common/trace_file.cpp @@ -0,0 +1,180 @@ +/************************************************************************** + * + * Copyright 2011 Zack Rusin + * 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_file.hpp" + +#include "trace_snappyfile.hpp" + +#include +#include + +#include + +#include "os.hpp" + +#include + +using namespace Trace; + + +File::File(const std::string &filename, + File::Mode mode) + : m_mode(mode), + m_isOpened(false) +{ + if (!filename.empty()) { + open(filename, m_mode); + } +} + +File::~File() +{ + close(); +} + + +void File::setCurrentOffset(const File::Offset &offset) +{ + assert(0); +} + +bool File::isZLibCompressed(const std::string &filename) +{ + std::fstream stream(filename.c_str(), + std::fstream::binary | std::fstream::in); + if (!stream.is_open()) + return false; + + unsigned char byte1, byte2; + stream >> byte1; + stream >> byte2; + stream.close(); + + return (byte1 == 0x1f && byte2 == 0x8b); +} + + +bool File::isSnappyCompressed(const std::string &filename) +{ + std::fstream stream(filename.c_str(), + std::fstream::binary | std::fstream::in); + if (!stream.is_open()) + return false; + + unsigned char byte1, byte2; + stream >> byte1; + stream >> byte2; + stream.close(); + + return (byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2); +} + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ +} gz_dummy_stream; + +ZLibFile::ZLibFile(const std::string &filename, + File::Mode mode) + : File(filename, mode), + m_gzFile(NULL) +{ +} + +ZLibFile::~ZLibFile() +{ +} + +bool ZLibFile::rawOpen(const std::string &filename, File::Mode mode) +{ + m_gzFile = gzopen(filename.c_str(), + (mode == File::Write) ? "wb" : "rb"); + + if (mode == File::Read && m_gzFile) { + //XXX: unfortunately zlib doesn't support + // SEEK_END or we could've done: + //m_endOffset = gzseek(m_gzFile, 0, SEEK_END); + //gzrewind(m_gzFile); + gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile; + long loc = ftell(stream->file); + fseek(stream->file,0,SEEK_END); + m_endOffset = ftell(stream->file); + fseek(stream->file, loc, SEEK_SET); + } + + return m_gzFile != NULL; +} + +bool ZLibFile::rawWrite(const void *buffer, size_t length) +{ + return gzwrite(m_gzFile, buffer, length) != -1; +} + +bool ZLibFile::rawRead(void *buffer, size_t length) +{ + return gzread(m_gzFile, buffer, length) != -1; +} + +int ZLibFile::rawGetc() +{ + return gzgetc(m_gzFile); +} + +void ZLibFile::rawClose() +{ + if (m_gzFile) { + gzclose(m_gzFile); + m_gzFile = NULL; + } +} + +void ZLibFile::rawFlush() +{ + gzflush(m_gzFile, Z_SYNC_FLUSH); +} + +File::Offset ZLibFile::currentOffset() +{ + return File::Offset(gztell(m_gzFile)); +} + +bool ZLibFile::supportsOffsets() const +{ + return false; +} + +bool ZLibFile::rawSkip(size_t) +{ + return false; +} + +int ZLibFile::rawPercentRead() +{ + gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile; + return 100 * (ftell(stream->file) / m_endOffset); +} diff --git a/common/trace_file.hpp b/common/trace_file.hpp new file mode 100644 index 0000000..4b1b70d --- /dev/null +++ b/common/trace_file.hpp @@ -0,0 +1,224 @@ +/************************************************************************** + * + * Copyright 2011 Zack Rusin + * 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_FILE_HPP +#define TRACE_FILE_HPP + +#include +#include +#include + +namespace Trace { + +class File { +public: + enum Mode { + Read, + Write + }; + struct Offset { + Offset(uint64_t _chunk = 0, uint32_t _offsetInChunk = 0) + : chunk(_chunk), + offsetInChunk(_offsetInChunk) + {} + uint64_t chunk; + uint32_t offsetInChunk; + }; + +public: + static bool isZLibCompressed(const std::string &filename); + static bool isSnappyCompressed(const std::string &filename); +public: + File(const std::string &filename = std::string(), + File::Mode mode = File::Read); + virtual ~File(); + + bool isOpened() const; + File::Mode mode() const; + + bool open(const std::string &filename, File::Mode mode); + bool write(const void *buffer, size_t length); + bool read(void *buffer, size_t length); + void close(); + void flush(void); + int getc(); + bool skip(size_t length); + int percentRead(); + + virtual bool supportsOffsets() const = 0; + virtual File::Offset currentOffset() = 0; + virtual void setCurrentOffset(const File::Offset &offset); +protected: + virtual bool rawOpen(const std::string &filename, File::Mode mode) = 0; + virtual bool rawWrite(const void *buffer, size_t length) = 0; + virtual bool rawRead(void *buffer, size_t length) = 0; + virtual int rawGetc() = 0; + virtual void rawClose() = 0; + virtual void rawFlush() = 0; + virtual bool rawSkip(size_t length) = 0; + virtual int rawPercentRead() = 0; + +protected: + File::Mode m_mode; + bool m_isOpened; +}; + +inline bool File::isOpened() const +{ + return m_isOpened; +} + +inline File::Mode File::mode() const +{ + return m_mode; +} + +inline bool File::open(const std::string &filename, File::Mode mode) +{ + if (m_isOpened) { + close(); + } + m_isOpened = rawOpen(filename, mode); + m_mode = mode; + + return m_isOpened; +} + +inline bool File::write(const void *buffer, size_t length) +{ + if (!m_isOpened || m_mode != File::Write) { + return false; + } + return rawWrite(buffer, length); +} + +inline bool File::read(void *buffer, size_t length) +{ + if (!m_isOpened || m_mode != File::Read) { + return false; + } + return rawRead(buffer, length); +} + +inline int File::percentRead() +{ + if (!m_isOpened || m_mode != File::Read) { + return 0; + } + return rawPercentRead(); +} + +inline void File::close() +{ + if (m_isOpened) { + rawClose(); + m_isOpened = false; + } +} + +inline void File::flush(void) +{ + if (m_mode == File::Write) { + rawFlush(); + } +} + +inline int File::getc() +{ + if (!m_isOpened || m_mode != File::Read) { + return -1; + } + return rawGetc(); +} + +inline bool File::skip(size_t length) +{ + if (!m_isOpened || m_mode != File::Read) { + return false; + } + return rawSkip(length); +} + +class ZLibFile : public File { +public: + ZLibFile(const std::string &filename = std::string(), + File::Mode mode = File::Read); + virtual ~ZLibFile(); + + + virtual bool supportsOffsets() const; + virtual File::Offset currentOffset(); +protected: + virtual bool rawOpen(const std::string &filename, File::Mode mode); + virtual bool rawWrite(const void *buffer, size_t length); + virtual bool rawRead(void *buffer, size_t length); + virtual int rawGetc(); + virtual void rawClose(); + virtual void rawFlush(); + virtual bool rawSkip(size_t length); + virtual int rawPercentRead(); +private: + void *m_gzFile; + double m_endOffset; +}; + +inline bool +operator<(const File::Offset &one, const File::Offset &two) +{ + return one.chunk < two.chunk || + (one.chunk == two.chunk && one.offsetInChunk < two.offsetInChunk); +} + +inline bool +operator==(const File::Offset &one, const File::Offset &two) +{ + return one.chunk == two.chunk && + one.offsetInChunk == two.offsetInChunk; +} + +inline bool +operator>=(const File::Offset &one, const File::Offset &two) +{ + return one.chunk > two.chunk || + (one.chunk == two.chunk && one.offsetInChunk >= two.offsetInChunk); +} + +inline bool +operator>(const File::Offset &one, const File::Offset &two) +{ + return two < one; +} + +inline bool +operator<=(const File::Offset &one, const File::Offset &two) +{ + return two >= one; +} + + +} + +#endif diff --git a/common/trace_format.hpp b/common/trace_format.hpp new file mode 100644 index 0000000..a8ee5eb --- /dev/null +++ b/common/trace_format.hpp @@ -0,0 +1,109 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +/* + * Trace binary format. + * + * Grammar: + * + * trace = event* EOF + * + * event = EVENT_ENTER call_sig call_detail+ + * | EVENT_LEAVE call_no call_detail+ + * + * call_sig = sig_id ( name arg_names )? + * + * call_detail = ARG index value + * | RET value + * | END + * + * value = NULL + * | FALSE + * | TRUE + * | SINT int + * | UINT int + * | FLOAT float + * | DOUBLE double + * | STRING string + * | BLOB string + * | ENUM enum_sig + * | BITMASK bitmask_sig value + * | ARRAY length value+ + * | STRUCT struct_sig value+ + * | OPAQUE int + * + * call_sig = id name arg_name* + * | id + * + * enum_sig = id name value + * | id + * + * bitmask_sig = id count (name value)+ + * | id + * + * string = length (BYTE)* + * + */ + +#ifndef _TRACE_FORMAT_HPP_ +#define _TRACE_FORMAT_HPP_ + +namespace Trace { + +#define TRACE_VERSION 1 + +enum Event { + EVENT_ENTER = 0, + EVENT_LEAVE, +}; + +enum CallDetail { + CALL_END = 0, + CALL_ARG, + CALL_RET, + CALL_THREAD, +}; + +enum Type { + TYPE_NULL = 0, + TYPE_FALSE, + TYPE_TRUE, + TYPE_SINT, + TYPE_UINT, + TYPE_FLOAT, + TYPE_DOUBLE, + TYPE_STRING, // Null terminated, human readible string + TYPE_BLOB, // Block of bytes + TYPE_ENUM, + TYPE_BITMASK, + TYPE_ARRAY, + TYPE_STRUCT, + TYPE_OPAQUE, +}; + + +} /* namespace Trace */ + +#endif /* _TRACE_FORMAT_HPP_ */ diff --git a/common/trace_loader.cpp b/common/trace_loader.cpp new file mode 100644 index 0000000..c14d815 --- /dev/null +++ b/common/trace_loader.cpp @@ -0,0 +1,139 @@ +#include "trace_loader.hpp" + + +using namespace Trace; + +Loader::Loader() + : m_frameMarker(FrameMarker_SwapBuffers) +{ +} + +Loader::~Loader() +{ + close(); +} + +Loader::FrameMarker Loader::frameMarker() const +{ + return m_frameMarker; +} + +void Loader::setFrameMarker(Loader::FrameMarker marker) +{ + m_frameMarker = marker; +} + +int Loader::numberOfFrames() const +{ + return m_frameBookmarks.size(); +} + +int Loader::numberOfCallsInFrame(int frameIdx) const +{ + if (frameIdx > m_frameBookmarks.size()) { + return 0; + } + FrameBookmarks::const_iterator itr = + m_frameBookmarks.find(frameIdx); + return itr->second.numberOfCalls; +} + +bool Loader::open(const char *filename) +{ + if (!m_parser.open(filename)) { + std::cerr << "error: failed to open " << filename << "\n"; + return false; + } + if (!m_parser.supportsOffsets()) { + std::cerr << "error: " <= 5) { + std::cerr << "\tPercent scanned = " + << m_parser.percentRead() + << "..."<dump(std::cout, color); + delete call; + } + return true; +} + +void Loader::close() +{ + m_parser.close(); +} + +bool Loader::isCallAFrameMarker(const Trace::Call *call) const +{ + std::string name = call->name(); + + switch (m_frameMarker) { + case FrameMarker_SwapBuffers: + return name.find("SwapBuffers") != std::string::npos || + name == "CGLFlushDrawable" || + name == "glFrameTerminatorGREMEDY"; + break; + case FrameMarker_Flush: + return name == "glFlush"; + break; + case FrameMarker_Finish: + return name == "glFinish"; + break; + case FrameMarker_Clear: + return name == "glClear"; + break; + } + return false; +} + +std::vector Loader::frame(int idx) +{ + int numOfCalls = numberOfCallsInFrame(idx); + if (numOfCalls) { + const FrameBookmark &frameBookmark = m_frameBookmarks[idx]; + std::vector calls(numOfCalls); + m_parser.setBookmark(frameBookmark.start); + + Trace::Call *call; + int parsedCalls = 0; + while ((call = m_parser.parse_call())) { + + calls[parsedCalls] = call; + ++parsedCalls; + + if (isCallAFrameMarker(call)) { + break; + } + + } + assert(parsedCalls == numOfCalls); + return calls; + } + return std::vector(); +} diff --git a/common/trace_loader.hpp b/common/trace_loader.hpp new file mode 100644 index 0000000..9f74a9b --- /dev/null +++ b/common/trace_loader.hpp @@ -0,0 +1,65 @@ +#ifndef TRACE_LOADER_HPP +#define TRACE_LOADER_HPP + +#include "trace_file.hpp" +#include "trace_parser.hpp" + +#include +#include +#include +#include + +namespace Trace { + +class Frame; + +class Loader +{ +public: + enum FrameMarker { + FrameMarker_SwapBuffers, + FrameMarker_Flush, + FrameMarker_Finish, + FrameMarker_Clear + }; +public: + Loader(); + ~Loader(); + + Loader::FrameMarker frameMarker() const; + void setFrameMarker(Loader::FrameMarker marker); + + int numberOfFrames() const; + int numberOfCallsInFrame(int frameIdx) const; + + bool open(const char *filename); + void close(); + + std::vector frame(int idx); + +private: + struct FrameBookmark { + FrameBookmark() + : numberOfCalls(0) + {} + FrameBookmark(const ParseBookmark &s) + : start(s), + numberOfCalls(0) + {} + + ParseBookmark start; + int numberOfCalls; + }; + bool isCallAFrameMarker(const Trace::Call *call) const; + +private: + Trace::Parser m_parser; + FrameMarker m_frameMarker; + + typedef std::map FrameBookmarks; + FrameBookmarks m_frameBookmarks; +}; + +} + +#endif // TRACE_LOADER_HPP diff --git a/common/trace_local_writer.cpp b/common/trace_local_writer.cpp new file mode 100644 index 0000000..ea6c111 --- /dev/null +++ b/common/trace_local_writer.cpp @@ -0,0 +1,156 @@ +/************************************************************************** + * + * Copyright 2007-2011 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 +#include +#include +#include +#include + +#include "os.hpp" +#include "trace_file.hpp" +#include "trace_writer.hpp" +#include "trace_format.hpp" + + +namespace Trace { + + +static void exceptionCallback(void) +{ + OS::DebugMessage("apitrace: flushing trace due to an exception\n"); + localWriter.flush(); +} + + +LocalWriter::LocalWriter() : + acquired(0) +{} + +LocalWriter::~LocalWriter() +{ + OS::ResetExceptionCallback(); +} + +void +LocalWriter::open(void) { + + static unsigned dwCounter = 0; + + const char *szExtension = "trace"; + char szFileName[PATH_MAX]; + const char *lpFileName; + + lpFileName = getenv("TRACE_FILE"); + if (lpFileName) { + strncpy(szFileName, lpFileName, PATH_MAX); + } + else { + char szProcessName[PATH_MAX]; + char szCurrentDir[PATH_MAX]; + OS::GetProcessName(szProcessName, PATH_MAX); + OS::GetCurrentDir(szCurrentDir, PATH_MAX); + + for (;;) { + FILE *file; + + if (dwCounter) + snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension); + else + snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension); + + file = fopen(szFileName, "rb"); + if (file == NULL) + break; + + fclose(file); + + ++dwCounter; + } + } + + OS::DebugMessage("apitrace: tracing to %s\n", szFileName); + + Writer::open(szFileName); + + OS::SetExceptionCallback(exceptionCallback); + +#if 0 + // For debugging the exception handler + *((int *)0) = 0; +#endif +} + +unsigned LocalWriter::beginEnter(const FunctionSig *sig) { + OS::AcquireMutex(); + ++acquired; + + if (!m_file->isOpened()) { + open(); + } + + return Writer::beginEnter(sig); +} + +void LocalWriter::endEnter(void) { + Writer::endEnter(); + --acquired; + OS::ReleaseMutex(); +} + +void LocalWriter::beginLeave(unsigned call) { + OS::AcquireMutex(); + ++acquired; + Writer::beginLeave(call); +} + +void LocalWriter::endLeave(void) { + Writer::endLeave(); + --acquired; + OS::ReleaseMutex(); +} + +void LocalWriter::flush(void) { + /* + * Do nothing if the mutex is already acquired (e.g., if a segfault happen + * while writing the file) to prevent dead-lock. + */ + + if (!acquired) { + OS::AcquireMutex(); + if (m_file->isOpened()) { + m_file->flush(); + } + OS::ReleaseMutex(); + } +} + + +LocalWriter localWriter; + + +} /* namespace Trace */ + diff --git a/common/trace_model.cpp b/common/trace_model.cpp new file mode 100644 index 0000000..306b9e7 --- /dev/null +++ b/common/trace_model.cpp @@ -0,0 +1,379 @@ +/************************************************************************** + * + * 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 "formatter.hpp" +#include "trace_model.hpp" + + +namespace Trace { + + +Call::~Call() { + for (unsigned i = 0; i < args.size(); ++i) { + delete args[i]; + } + + if (ret) { + delete ret; + } +} + + +String::~String() { + delete [] value; +} + + +Struct::~Struct() { + for (std::vector::iterator it = members.begin(); it != members.end(); ++it) { + delete *it; + } +} + + +Array::~Array() { + for (std::vector::iterator it = values.begin(); it != values.end(); ++it) { + delete *it; + } +} + +Blob::~Blob() { + // Blobs are often bound and referred during many calls, so we can't delete + // them here in that case. + // + // Once bound there is no way to know when they were unbound, which + // effectively means we have to leak them. A better solution would be to + // keep a list of bound pointers, and defer the destruction to when the + // trace in question has been fully processed. + if (!bound) { + delete [] buf; + } +} + + +// bool cast +bool Null ::toBool(void) const { return false; } +bool Bool ::toBool(void) const { return value; } +bool SInt ::toBool(void) const { return value != 0; } +bool UInt ::toBool(void) const { return value != 0; } +bool Float ::toBool(void) const { return value != 0; } +bool String ::toBool(void) const { return true; } +bool Enum ::toBool(void) const { return sig->value != 0; } +bool Struct ::toBool(void) const { return true; } +bool Array ::toBool(void) const { return true; } +bool Blob ::toBool(void) const { return true; } +bool Pointer::toBool(void) const { return value != 0; } + + +// signed integer cast +signed long long Value ::toSInt(void) const { assert(0); return 0; } +signed long long Null ::toSInt(void) const { return 0; } +signed long long Bool ::toSInt(void) const { return static_cast(value); } +signed long long SInt ::toSInt(void) const { return value; } +signed long long UInt ::toSInt(void) const { assert(static_cast(value) >= 0); return static_cast(value); } +signed long long Float ::toSInt(void) const { return static_cast(value); } +signed long long Enum ::toSInt(void) const { return sig->value; } + + +// unsigned integer cast +unsigned long long Value ::toUInt(void) const { assert(0); return 0; } +unsigned long long Null ::toUInt(void) const { return 0; } +unsigned long long Bool ::toUInt(void) const { return static_cast(value); } +unsigned long long SInt ::toUInt(void) const { assert(value >= 0); return static_cast(value); } +unsigned long long UInt ::toUInt(void) const { return value; } +unsigned long long Float ::toUInt(void) const { return static_cast(value); } +unsigned long long Enum ::toUInt(void) const { assert(sig->value >= 0); return sig->value; } + + +// floating point cast +float Value ::toFloat(void) const { assert(0); return 0; } +float Null ::toFloat(void) const { return 0; } +float Bool ::toFloat(void) const { return static_cast(value); } +float SInt ::toFloat(void) const { return static_cast(value); } +float UInt ::toFloat(void) const { return static_cast(value); } +float Float ::toFloat(void) const { return value; } +float Enum ::toFloat(void) const { return static_cast(sig->value); } + + +// floating point cast +double Value ::toDouble(void) const { assert(0); return 0; } +double Null ::toDouble(void) const { return 0; } +double Bool ::toDouble(void) const { return static_cast(value); } +double SInt ::toDouble(void) const { return static_cast(value); } +double UInt ::toDouble(void) const { return static_cast(value); } +double Float ::toDouble(void) const { return value; } +double Enum ::toDouble(void) const { return static_cast(sig->value); } + + +// pointer cast +void * Value ::toPointer(void) const { assert(0); return NULL; } +void * Null ::toPointer(void) const { return NULL; } +void * Blob ::toPointer(void) const { return buf; } +void * Pointer::toPointer(void) const { return (void *)value; } + +void * Value ::toPointer(bool bind) { assert(0); return NULL; } +void * Null ::toPointer(bool bind) { return NULL; } +void * Blob ::toPointer(bool bind) { if (bind) bound = true; return buf; } +void * Pointer::toPointer(bool bind) { return (void *)value; } + + +// pointer cast +unsigned long long Value ::toUIntPtr(void) const { assert(0); return 0; } +unsigned long long Null ::toUIntPtr(void) const { return 0; } +unsigned long long Pointer::toUIntPtr(void) const { return value; } + + +// string cast +const char * Value ::toString(void) const { assert(0); return NULL; } +const char * Null ::toString(void) const { return NULL; } +const char * String::toString(void) const { return value; } + + +// virtual Value::visit() +void Null ::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 Enum ::visit(Visitor &visitor) { visitor.visit(this); } +void Bitmask::visit(Visitor &visitor) { visitor.visit(this); } +void Struct ::visit(Visitor &visitor) { visitor.visit(this); } +void Array ::visit(Visitor &visitor) { visitor.visit(this); } +void Blob ::visit(Visitor &visitor) { visitor.visit(this); } +void Pointer::visit(Visitor &visitor) { visitor.visit(this); } + + +void Visitor::visit(Null *) { assert(0); } +void Visitor::visit(Bool *) { assert(0); } +void Visitor::visit(SInt *) { assert(0); } +void Visitor::visit(UInt *) { assert(0); } +void Visitor::visit(Float *) { assert(0); } +void Visitor::visit(String *) { assert(0); } +void Visitor::visit(Enum *node) { assert(0); } +void Visitor::visit(Bitmask *node) { visit(static_cast(node)); } +void Visitor::visit(Struct *) { assert(0); } +void Visitor::visit(Array *) { assert(0); } +void Visitor::visit(Blob *) { assert(0); } +void Visitor::visit(Pointer *) { assert(0); } + + +class Dumper : public Visitor +{ +protected: + std::ostream &os; + Formatter::Formatter *formatter; + Formatter::Attribute *normal; + Formatter::Attribute *bold; + Formatter::Attribute *italic; + Formatter::Attribute *red; + Formatter::Attribute *pointer; + Formatter::Attribute *literal; + +public: + Dumper(std::ostream &_os, bool color) : os(_os) { + formatter = Formatter::defaultFormatter(color); + normal = formatter->normal(); + bold = formatter->bold(); + italic = formatter->italic(); + red = formatter->color(Formatter::RED); + pointer = formatter->color(Formatter::GREEN); + literal = formatter->color(Formatter::BLUE); + } + + ~Dumper() { + delete normal; + delete bold; + delete italic; + delete red; + delete pointer; + delete literal; + delete formatter; + } + + void visit(Null *) { + os << "NULL"; + } + + void visit(Bool *node) { + os << literal << (node->value ? "true" : "false") << normal; + } + + void visit(SInt *node) { + os << literal << node->value << normal; + } + + void visit(UInt *node) { + os << literal << node->value << normal; + } + + void visit(Float *node) { + os << literal << node->value << normal; + } + + void visit(String *node) { + os << literal << "\""; + for (const char *it = node->value; *it; ++it) { + unsigned char c = (unsigned char) *it; + if (c == '\"') + os << "\\\""; + else if (c == '\\') + os << "\\\\"; + else if (c >= 0x20 && c <= 0x7e) + os << c; + else if (c == '\t') { + os << "\t"; + } else if (c == '\r') { + // Ignore carriage-return + } else if (c == '\n') { + // Reset formatting so that it looks correct with 'less -R' + os << normal << '\n' << literal; + } else { + unsigned octal0 = c & 0x7; + unsigned octal1 = (c >> 3) & 0x7; + unsigned octal2 = (c >> 3) & 0x7; + os << "\\"; + if (octal2) + os << octal2; + if (octal1) + os << octal1; + os << octal0; + } + } + os << "\"" << normal; + } + + void visit(Enum *node) { + os << literal << node->sig->name << normal; + } + + void visit(Bitmask *bitmask) { + unsigned long long value = bitmask->value; + const BitmaskSig *sig = bitmask->sig; + bool first = true; + for (const BitmaskFlag *it = sig->flags; value != 0 && it != sig->flags + sig->num_flags; ++it) { + if ((it->value && (value & it->value) == it->value) || + (!it->value && value == 0)) { + if (!first) { + os << " | "; + } + os << literal << it->name << normal; + value &= ~it->value; + first = false; + } + } + if (value || first) { + if (!first) { + os << " | "; + } + os << literal << "0x" << std::hex << value << std::dec << normal; + } + } + + void visit(Struct *s) { + const char *sep = ""; + os << "{"; + for (unsigned i = 0; i < s->members.size(); ++i) { + os << sep << italic << s->sig->member_names[i] << normal << " = "; + _visit(s->members[i]); + sep = ", "; + } + os << "}"; + } + + void visit(Array *array) { + if (array->values.size() == 1) { + os << "&"; + _visit(array->values[0]); + } + else { + const char *sep = ""; + os << "{"; + for (std::vector::iterator it = array->values.begin(); it != array->values.end(); ++it) { + os << sep; + _visit(*it); + sep = ", "; + } + os << "}"; + } + } + + void visit(Blob *blob) { + os << pointer << "blob(" << blob->size << ")" << normal; + } + + void visit(Pointer *p) { + os << pointer << "0x" << std::hex << p->value << std::dec << normal; + } + + void visit(Call *call) { + const char *sep = ""; + os << bold << call->sig->name << normal << "("; + for (unsigned i = 0; i < call->args.size(); ++i) { + os << sep << italic << call->sig->arg_names[i] << normal << " = "; + if (call->args[i]) { + _visit(call->args[i]); + } else { + os << "?"; + } + sep = ", "; + } + os << ")"; + if (call->ret) { + os << " = "; + _visit(call->ret); + } + os << "\n"; + } +}; + + +void Value::dump(std::ostream &os, bool color) { + Dumper d(os, color); + visit(d); +} + + +static Null null; + +const Value & Value::operator[](size_t index) const { + const Array *array = dynamic_cast(this); + if (array) { + if (index < array->values.size()) { + return *array->values[index]; + } + } + return null; +} + +void Call::dump(std::ostream &os, bool color) { + Dumper d(os, color); + os << no << " "; + d.visit(this); +} + + +} /* namespace Trace */ diff --git a/common/trace_model.hpp b/common/trace_model.hpp new file mode 100644 index 0000000..a74508e --- /dev/null +++ b/common/trace_model.hpp @@ -0,0 +1,357 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +/* + * Object hierarchy for describing the traces in memory. + */ + +#ifndef _TRACE_MODEL_HPP_ +#define _TRACE_MODEL_HPP_ + + +#include + +#include +#include +#include + + +namespace Trace { + + +typedef unsigned Id; + + +struct FunctionSig { + Id id; + const char *name; + unsigned num_args; + const char **arg_names; +}; + + +struct StructSig { + Id id; + const char *name; + unsigned num_members; + const char **member_names; +}; + + +struct EnumSig { + Id id; + const char *name; + signed long long value; +}; + + +struct BitmaskFlag { + const char *name; + unsigned long long value; +}; + + +struct BitmaskSig { + Id id; + unsigned num_flags; + const BitmaskFlag *flags; +}; + + +class Visitor; + + +class Value +{ +public: + virtual ~Value() {} + virtual void visit(Visitor &visitor) = 0; + + virtual bool toBool(void) const = 0; + virtual signed long long toSInt(void) const; + virtual unsigned long long toUInt(void) const; + virtual float toFloat(void) const; + virtual double toDouble(void) const; + + virtual void *toPointer(void) const; + virtual void *toPointer(bool bind); + virtual unsigned long long toUIntPtr(void) const; + virtual const char *toString(void) const; + + const Value & operator[](size_t index) const; + + void dump(std::ostream &os, bool color=true); +}; + + +class Null : public Value +{ +public: + bool toBool(void) const; + signed long long toSInt(void) const; + unsigned long long toUInt(void) const; + virtual float toFloat(void) const; + virtual double toDouble(void) const; + void *toPointer(void) const; + void *toPointer(bool bind); + unsigned long long toUIntPtr(void) const; + const char *toString(void) const; + void visit(Visitor &visitor); +}; + + +class Bool : public Value +{ +public: + Bool(bool _value) : value(_value) {} + + bool toBool(void) const; + signed long long toSInt(void) const; + unsigned long long toUInt(void) const; + virtual float toFloat(void) const; + virtual double toDouble(void) const; + void visit(Visitor &visitor); + + bool value; +}; + + +class SInt : public Value +{ +public: + SInt(signed long long _value) : value(_value) {} + + bool toBool(void) const; + signed long long toSInt(void) const; + unsigned long long toUInt(void) const; + virtual float toFloat(void) const; + virtual double toDouble(void) const; + void visit(Visitor &visitor); + + signed long long value; +}; + + +class UInt : public Value +{ +public: + UInt(unsigned long long _value) : value(_value) {} + + bool toBool(void) const; + signed long long toSInt(void) const; + unsigned long long toUInt(void) const; + virtual float toFloat(void) const; + virtual double toDouble(void) const; + void visit(Visitor &visitor); + + unsigned long long value; +}; + + +class Float : public Value +{ +public: + Float(double _value) : value(_value) {} + + bool toBool(void) const; + signed long long toSInt(void) const; + unsigned long long toUInt(void) const; + virtual float toFloat(void) const; + virtual double toDouble(void) const; + void visit(Visitor &visitor); + + double value; +}; + + +class String : public Value +{ +public: + String(const char * _value) : value(_value) {} + ~String(); + + bool toBool(void) const; + const char *toString(void) const; + void visit(Visitor &visitor); + + const char * value; +}; + + +class Enum : public Value +{ +public: + Enum(const EnumSig *_sig) : sig(_sig) {} + + bool toBool(void) const; + signed long long toSInt(void) const; + unsigned long long toUInt(void) const; + virtual float toFloat(void) const; + virtual double toDouble(void) const; + void visit(Visitor &visitor); + + const EnumSig *sig; +}; + + +class Bitmask : public UInt +{ +public: + Bitmask(const BitmaskSig *_sig, unsigned long long _value) : UInt(_value), sig(_sig) {} + + void visit(Visitor &visitor); + + const BitmaskSig *sig; +}; + + +class Struct : public Value +{ +public: + Struct(StructSig *_sig) : sig(_sig), members(_sig->num_members) { } + ~Struct(); + + bool toBool(void) const; + void visit(Visitor &visitor); + + const StructSig *sig; + std::vector members; +}; + + +class Array : public Value +{ +public: + Array(size_t len) : values(len) {} + ~Array(); + + bool toBool(void) const; + void visit(Visitor &visitor); + + std::vector values; +}; + + +class Blob : public Value +{ +public: + Blob(size_t _size) { + size = _size; + buf = new char[_size]; + bound = false; + } + + ~Blob(); + + bool toBool(void) const; + void *toPointer(void) const; + void *toPointer(bool bind); + void visit(Visitor &visitor); + + size_t size; + char *buf; + bool bound; +}; + + +class Pointer : public UInt +{ +public: + Pointer(unsigned long long value) : UInt(value) {} + + bool toBool(void) const; + void *toPointer(void) const; + void *toPointer(bool bind); + unsigned long long toUIntPtr(void) const; + void visit(Visitor &visitor); +}; + + +class Visitor +{ +public: + virtual void visit(Null *); + virtual void visit(Bool *); + virtual void visit(SInt *); + virtual void visit(UInt *); + virtual void visit(Float *); + virtual void visit(String *); + virtual void visit(Enum *); + virtual void visit(Bitmask *); + virtual void visit(Struct *); + virtual void visit(Array *); + virtual void visit(Blob *); + virtual void visit(Pointer *); + +protected: + inline void _visit(Value *value) { + if (value) { + value->visit(*this); + } + } +}; + + +inline std::ostream & operator <<(std::ostream &os, Value *value) { + if (value) { + value->dump(os); + } + return os; +} + + +class Call +{ +public: + unsigned no; + const FunctionSig *sig; + std::vector args; + Value *ret; + + Call(FunctionSig *_sig) : sig(_sig), args(_sig->num_args), ret(0) { } + ~Call(); + + inline const char * name(void) const { + return sig->name; + } + + inline Value & arg(unsigned index) { + assert(index < args.size()); + return *(args[index]); + } + + void dump(std::ostream &os, bool color=true); +}; + + +inline std::ostream & operator <<(std::ostream &os, Call &call) { + call.dump(os); + return os; +} + + +} /* namespace Trace */ + +#endif /* _TRACE_MODEL_HPP_ */ diff --git a/common/trace_model_writer.cpp b/common/trace_model_writer.cpp new file mode 100644 index 0000000..dcfcf86 --- /dev/null +++ b/common/trace_model_writer.cpp @@ -0,0 +1,127 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * 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_writer.hpp" + + +namespace Trace { + + +class ModelWriter : public Visitor +{ +protected: + Writer &writer; + +public: + ModelWriter(Writer &_writer) : + writer(_writer) { + } + + void visit(Null *) { + writer.writeNull(); + } + + void visit(Bool *node) { + writer.writeBool(node->value); + } + + void visit(SInt *node) { + writer.writeSInt(node->value); + } + + void visit(UInt *node) { + writer.writeUInt(node->value); + } + + void visit(Float *node) { + writer.writeFloat(node->value); + } + + void visit(String *node) { + writer.writeString(node->value); + } + + void visit(Enum *node) { + writer.writeEnum(node->sig); + } + + void visit(Bitmask *node) { + writer.writeBitmask(node->sig, node->value); + } + + void visit(Struct *node) { + writer.beginStruct(node->sig); + for (unsigned i = 0; i < node->sig->num_members; ++i) { + _visit(node->members[i]); + } + writer.endStruct(); + } + + void visit(Array *node) { + writer.beginArray(node->values.size()); + for (std::vector::iterator it = node->values.begin(); it != node->values.end(); ++it) { + _visit(*it); + } + writer.endArray(); + } + + void visit(Blob *node) { + writer.writeBlob(node->buf, node->size); + } + + void visit(Pointer *node) { + writer.writeOpaque((const void *) (size_t) node->value); + } + + void visit(Call *call) { + unsigned call_no = writer.beginEnter(call->sig); + for (unsigned i = 0; i < call->args.size(); ++i) { + if (call->args[i]) { + writer.beginArg(i); + _visit(call->args[i]); + writer.endArg(); + } + } + writer.endEnter(); + writer.beginLeave(call_no); + if (call->ret) { + writer.beginReturn(); + _visit(call->ret); + writer.endReturn(); + } + writer.endLeave(); + } +}; + + +void Writer::writeCall(Call *call) { + ModelWriter visitor(*this); + visitor.visit(call); +} + + +} /* namespace Trace */ + diff --git a/common/trace_parser.cpp b/common/trace_parser.cpp new file mode 100644 index 0000000..d7b20d2 --- /dev/null +++ b/common/trace_parser.cpp @@ -0,0 +1,731 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * 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 +#include + +#include "trace_file.hpp" +#include "trace_snappyfile.hpp" +#include "trace_parser.hpp" + + +#define TRACE_VERBOSE 0 + + +namespace Trace { + + +Parser::Parser() { + file = NULL; + next_call_no = 0; + version = 0; +} + + +Parser::~Parser() { + close(); +} + + +bool Parser::open(const char *filename) { + assert(!file); + if (File::isZLibCompressed(filename)) { + file = new ZLibFile; + } else { + file = new SnappyFile; + } + + if (!file->open(filename, File::Read)) { + return false; + } + + version = read_uint(); + if (version > TRACE_VERSION) { + std::cerr << "error: unsupported trace format version " << version << "\n"; + return false; + } + + return true; +} + +template +inline void +deleteAll(Iter begin, Iter end) +{ + while (begin != end) { + delete *begin; + ++begin; + } +} + +template +inline void +deleteAll(Container &c) +{ + deleteAll(c.begin(), c.end()); + c.clear(); +} + +void Parser::close(void) { + if (file) { + file->close(); + delete file; + file = NULL; + } + + deleteAll(calls); + + // Delete all signature data. Signatures are mere structures which don't + // own their own memory, so we need to destroy all data we created here. + + for (FunctionMap::iterator it = functions.begin(); it != functions.end(); ++it) { + FunctionSigState *sig = *it; + if (sig) { + delete [] sig->name; + for (unsigned arg = 0; arg < sig->num_args; ++arg) { + delete [] sig->arg_names[arg]; + } + delete [] sig->arg_names; + delete sig; + } + } + functions.clear(); + + for (StructMap::iterator it = structs.begin(); it != structs.end(); ++it) { + StructSigState *sig = *it; + if (sig) { + delete [] sig->name; + for (unsigned member = 0; member < sig->num_members; ++member) { + delete [] sig->member_names[member]; + } + delete [] sig->member_names; + delete sig; + } + } + structs.clear(); + + for (EnumMap::iterator it = enums.begin(); it != enums.end(); ++it) { + EnumSigState *sig = *it; + if (sig) { + delete [] sig->name; + delete sig; + } + } + enums.clear(); + + for (BitmaskMap::iterator it = bitmasks.begin(); it != bitmasks.end(); ++it) { + BitmaskSigState *sig = *it; + if (sig) { + for (unsigned flag = 0; flag < sig->num_flags; ++flag) { + delete [] sig->flags[flag].name; + } + delete [] sig->flags; + delete sig; + } + } + bitmasks.clear(); +} + + +void Parser::getBookmark(ParseBookmark &bookmark) { + bookmark.offset = file->currentOffset(); + bookmark.next_call_no = next_call_no; +} + + +void Parser::setBookmark(const ParseBookmark &bookmark) { + file->setCurrentOffset(bookmark.offset); + next_call_no = bookmark.next_call_no; + + // Simply ignore all pending calls + deleteAll(calls); +} + + +Call *Parser::parse_call(Mode mode) { + do { + int c = read_byte(); + switch(c) { + case Trace::EVENT_ENTER: + parse_enter(mode); + break; + case Trace::EVENT_LEAVE: + return parse_leave(mode); + default: + std::cerr << "error: unknown event " << c << "\n"; + exit(1); + case -1: + for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) { + std::cerr << "warning: incomplete call " << (*it)->name() << "\n"; + std::cerr << **it << "\n"; + } + return NULL; + } + } while(true); +} + + +/** + * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit. + */ +template +T *lookup(std::vector &map, size_t index) { + if (index >= map.size()) { + map.resize(index + 1); + return NULL; + } else { + return map[index]; + } +} + + +FunctionSig *Parser::parse_function_sig(void) { + size_t id = read_uint(); + + FunctionSigState *sig = lookup(functions, id); + + if (!sig) { + /* parse the signature */ + sig = new FunctionSigState; + sig->id = id; + sig->name = read_string(); + sig->num_args = read_uint(); + const char **arg_names = new const char *[sig->num_args]; + for (unsigned i = 0; i < sig->num_args; ++i) { + arg_names[i] = read_string(); + } + sig->arg_names = arg_names; + sig->offset = file->currentOffset(); + functions[id] = sig; + } else if (file->currentOffset() < sig->offset) { + /* skip over the signature */ + skip_string(); /* name */ + int num_args = read_uint(); + for (unsigned i = 0; i < num_args; ++i) { + skip_string(); /*arg_name*/ + } + } + + assert(sig); + return sig; +} + + +StructSig *Parser::parse_struct_sig() { + size_t id = read_uint(); + + StructSigState *sig = lookup(structs, id); + + if (!sig) { + /* parse the signature */ + sig = new StructSigState; + sig->id = id; + sig->name = read_string(); + sig->num_members = read_uint(); + const char **member_names = new const char *[sig->num_members]; + for (unsigned i = 0; i < sig->num_members; ++i) { + member_names[i] = read_string(); + } + sig->member_names = member_names; + sig->offset = file->currentOffset(); + structs[id] = sig; + } else if (file->currentOffset() < sig->offset) { + /* skip over the signature */ + skip_string(); /* name */ + unsigned num_members = read_uint(); + for (unsigned i = 0; i < num_members; ++i) { + skip_string(); /* member_name */ + } + } + + assert(sig); + return sig; +} + + +EnumSig *Parser::parse_enum_sig() { + size_t id = read_uint(); + + EnumSigState *sig = lookup(enums, id); + + if (!sig) { + /* parse the signature */ + sig = new EnumSigState; + sig->id = id; + sig->name = read_string(); + Value *value = parse_value(); + sig->value = value->toSInt(); + delete value; + sig->offset = file->currentOffset(); + enums[id] = sig; + } else if (file->currentOffset() < sig->offset) { + /* skip over the signature */ + skip_string(); /*name*/ + scan_value(); + } + + assert(sig); + return sig; +} + + +BitmaskSig *Parser::parse_bitmask_sig() { + size_t id = read_uint(); + + BitmaskSigState *sig = lookup(bitmasks, id); + + if (!sig) { + /* parse the signature */ + sig = new BitmaskSigState; + sig->id = id; + sig->num_flags = read_uint(); + BitmaskFlag *flags = new BitmaskFlag[sig->num_flags]; + for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) { + it->name = read_string(); + it->value = read_uint(); + if (it->value == 0 && it != flags) { + std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n"; + } + } + sig->flags = flags; + sig->offset = file->currentOffset(); + bitmasks[id] = sig; + } else if (file->currentOffset() < sig->offset) { + /* skip over the signature */ + int num_flags = read_uint(); + for (int i = 0; i < num_flags; ++i) { + skip_string(); /*name */ + skip_uint(); /* value */ + } + } + + assert(sig); + return sig; +} + + +void Parser::parse_enter(Mode mode) { + FunctionSig *sig = parse_function_sig(); + + Call *call = new Call(sig); + + call->no = next_call_no++; + + if (parse_call_details(call, mode)) { + calls.push_back(call); + } else { + delete call; + } +} + + +Call *Parser::parse_leave(Mode mode) { + unsigned call_no = read_uint(); + Call *call = NULL; + for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) { + if ((*it)->no == call_no) { + call = *it; + calls.erase(it); + break; + } + } + if (!call) { + return NULL; + } + + if (parse_call_details(call, mode)) { + return call; + } else { + delete call; + return NULL; + } +} + + +bool Parser::parse_call_details(Call *call, Mode mode) { + do { + int c = read_byte(); + switch(c) { + case Trace::CALL_END: + return true; + case Trace::CALL_ARG: + parse_arg(call, mode); + break; + case Trace::CALL_RET: + call->ret = parse_value(mode); + break; + default: + std::cerr << "error: ("<name()<< ") unknown call detail " + << c << "\n"; + exit(1); + case -1: + return false; + } + } while(true); +} + + +void Parser::parse_arg(Call *call, Mode mode) { + unsigned index = read_uint(); + Value *value = parse_value(mode); + if (value) { + if (index >= call->args.size()) { + call->args.resize(index + 1); + } + call->args[index] = value; + } +} + + +Value *Parser::parse_value(void) { + int c; + Value *value; + c = read_byte(); + switch(c) { + case Trace::TYPE_NULL: + value = new Null; + break; + case Trace::TYPE_FALSE: + value = new Bool(false); + break; + case Trace::TYPE_TRUE: + value = new Bool(true); + break; + case Trace::TYPE_SINT: + value = parse_sint(); + break; + case Trace::TYPE_UINT: + value = parse_uint(); + break; + case Trace::TYPE_FLOAT: + value = parse_float(); + break; + case Trace::TYPE_DOUBLE: + value = parse_double(); + break; + case Trace::TYPE_STRING: + value = parse_string(); + break; + case Trace::TYPE_ENUM: + value = parse_enum(); + break; + case Trace::TYPE_BITMASK: + value = parse_bitmask(); + break; + case Trace::TYPE_ARRAY: + value = parse_array(); + break; + case Trace::TYPE_STRUCT: + value = parse_struct(); + break; + case Trace::TYPE_BLOB: + value = parse_blob(); + break; + case Trace::TYPE_OPAQUE: + value = parse_opaque(); + break; + default: + std::cerr << "error: unknown type " << c << "\n"; + exit(1); + case -1: + value = NULL; + break; + } +#if TRACE_VERBOSE + if (value) { + std::cerr << "\tVALUE " << value << "\n"; + } +#endif + return value; +} + + +void Parser::scan_value(void) { + int c = read_byte(); + switch(c) { + case Trace::TYPE_NULL: + case Trace::TYPE_FALSE: + case Trace::TYPE_TRUE: + break; + case Trace::TYPE_SINT: + scan_sint(); + break; + case Trace::TYPE_UINT: + scan_uint(); + break; + case Trace::TYPE_FLOAT: + scan_float(); + break; + case Trace::TYPE_DOUBLE: + scan_double(); + break; + case Trace::TYPE_STRING: + scan_string(); + break; + case Trace::TYPE_ENUM: + scan_enum(); + break; + case Trace::TYPE_BITMASK: + scan_bitmask(); + break; + case Trace::TYPE_ARRAY: + scan_array(); + break; + case Trace::TYPE_STRUCT: + scan_struct(); + break; + case Trace::TYPE_BLOB: + scan_blob(); + break; + case Trace::TYPE_OPAQUE: + scan_opaque(); + break; + default: + std::cerr << "error: unknown type " << c << "\n"; + exit(1); + case -1: + break; + } +} + + +Value *Parser::parse_sint() { + return new SInt(-(signed long long)read_uint()); +} + + +void Parser::scan_sint() { + skip_uint(); +} + + +Value *Parser::parse_uint() { + return new UInt(read_uint()); +} + + +void Parser::scan_uint() { + skip_uint(); +} + + +Value *Parser::parse_float() { + float value; + file->read(&value, sizeof value); + return new Float(value); +} + + +void Parser::scan_float() { + file->skip(sizeof(float)); +} + + +Value *Parser::parse_double() { + double value; + file->read(&value, sizeof value); + return new Float(value); +} + + +void Parser::scan_double() { + file->skip(sizeof(double)); +} + + +Value *Parser::parse_string() { + return new String(read_string()); +} + + +void Parser::scan_string() { + skip_string(); +} + + +Value *Parser::parse_enum() { + EnumSig *sig = parse_enum_sig(); + return new Enum(sig); +} + + +void Parser::scan_enum() { + parse_enum_sig(); +} + + +Value *Parser::parse_bitmask() { + BitmaskSig *sig = parse_bitmask_sig(); + + unsigned long long value = read_uint(); + + return new Bitmask(sig, value); +} + + +void Parser::scan_bitmask() { + parse_bitmask_sig(); + skip_uint(); /* value */ +} + + +Value *Parser::parse_array(void) { + 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; +} + + +void Parser::scan_array(void) { + size_t len = read_uint(); + for (size_t i = 0; i < len; ++i) { + scan_value(); + } +} + + +Value *Parser::parse_blob(void) { + size_t size = read_uint(); + Blob *blob = new Blob(size); + if (size) { + file->read(blob->buf, (unsigned)size); + } + return blob; +} + + +void Parser::scan_blob(void) { + size_t size = read_uint(); + if (size) { + file->skip(size); + } +} + + +Value *Parser::parse_struct() { + StructSig *sig = parse_struct_sig(); + Struct *value = new Struct(sig); + + for (size_t i = 0; i < sig->num_members; ++i) { + value->members[i] = parse_value(); + } + + return value; +} + + +void Parser::scan_struct() { + StructSig *sig = parse_struct_sig(); + for (size_t i = 0; i < sig->num_members; ++i) { + scan_value(); + } +} + + +Value *Parser::parse_opaque() { + unsigned long long addr; + addr = read_uint(); + return new Pointer(addr); +} + + +void Parser::scan_opaque() { + skip_uint(); +} + + +const char * Parser::read_string(void) { + size_t len = read_uint(); + char * value = new char[len + 1]; + if (len) { + file->read(value, (unsigned)len); + } + value[len] = 0; +#if TRACE_VERBOSE + std::cerr << "\tSTRING \"" << value << "\"\n"; +#endif + return value; +} + + +void Parser::skip_string(void) { + size_t len = read_uint(); + file->skip(len); +} + + +unsigned long long Parser::read_uint(void) { + unsigned long long value = 0; + int c; + unsigned shift = 0; + do { + c = file->getc(); + if (c == -1) { + break; + } + value |= (unsigned long long)(c & 0x7f) << shift; + shift += 7; + } while(c & 0x80); +#if TRACE_VERBOSE + std::cerr << "\tUINT " << value << "\n"; +#endif + return value; +} + + +void Parser::skip_uint(void) { + int c; + do { + c = file->getc(); + if (c == -1) { + break; + } + } while(c & 0x80); +} + + +inline int Parser::read_byte(void) { + int c = file->getc(); +#if TRACE_VERBOSE + if (c < 0) + std::cerr << "\tEOF" << "\n"; + else + std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n"; +#endif + return c; +} + + +inline void Parser::skip_byte(void) { + file->skip(1); +} + + +} /* namespace Trace */ diff --git a/common/trace_parser.hpp b/common/trace_parser.hpp new file mode 100644 index 0000000..3aaa6d3 --- /dev/null +++ b/common/trace_parser.hpp @@ -0,0 +1,197 @@ +/************************************************************************** + * + * 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 "trace_file.hpp" +#include "trace_format.hpp" +#include "trace_model.hpp" + + +namespace Trace { + + +struct ParseBookmark +{ + File::Offset offset; + unsigned next_call_no; +}; + + +class Parser +{ +protected: + File *file; + + enum Mode { + FULL = 0, + SCAN, + SKIP + }; + + typedef std::list CallList; + CallList calls; + + // Helper template that extends a base signature structure, with additional + // parsing information. + template< class T > + struct SigState : public T { + // Offset in the file of where signature was defined. It is used when + // reparsing to determine whether the signature definition is to be + // expected next or not. + File::Offset offset; + }; + + typedef SigState FunctionSigState; + typedef SigState StructSigState; + typedef SigState EnumSigState; + typedef SigState BitmaskSigState; + + typedef std::vector FunctionMap; + typedef std::vector StructMap; + typedef std::vector EnumMap; + typedef std::vector BitmaskMap; + + FunctionMap functions; + StructMap structs; + EnumMap enums; + BitmaskMap bitmasks; + + unsigned next_call_no; + +public: + unsigned long long version; + + Parser(); + + ~Parser(); + + bool open(const char *filename); + + void close(void); + + Call *parse_call(void) { + return parse_call(FULL); + } + + bool supportsOffsets() const + { + return file->supportsOffsets(); + } + + void getBookmark(ParseBookmark &bookmark); + + void setBookmark(const ParseBookmark &bookmark); + + int percentRead() + { + return file->percentRead(); + } + + Call *scan_call() { + return parse_call(SCAN); + } + +protected: + Call *parse_call(Mode mode); + + FunctionSig *parse_function_sig(void); + StructSig *parse_struct_sig(); + EnumSig *parse_enum_sig(); + BitmaskSig *parse_bitmask_sig(); + + Call *parse_Call(Mode mode); + + void parse_enter(Mode mode); + + Call *parse_leave(Mode mode); + + bool parse_call_details(Call *call, Mode mode); + + void parse_arg(Call *call, Mode mode); + + Value *parse_value(void); + void scan_value(void); + inline Value *parse_value(Mode mode) { + if (mode == FULL) { + return parse_value(); + } else { + scan_value(); + return NULL; + } + } + + Value *parse_sint(); + void scan_sint(); + + Value *parse_uint(); + void scan_uint(); + + Value *parse_float(); + void scan_float(); + + Value *parse_double(); + void scan_double(); + + Value *parse_string(); + void scan_string(); + + Value *parse_enum(); + void scan_enum(); + + Value *parse_bitmask(); + void scan_bitmask(); + + Value *parse_array(void); + void scan_array(void); + + Value *parse_blob(void); + void scan_blob(void); + + Value *parse_struct(); + void scan_struct(); + + Value *parse_opaque(); + void scan_opaque(); + + const char * read_string(void); + void skip_string(void); + + unsigned long long read_uint(void); + void skip_uint(void); + + inline int read_byte(void); + inline void skip_byte(void); +}; + + +} /* namespace Trace */ + +#endif /* _TRACE_PARSER_HPP_ */ diff --git a/common/trace_snappyfile.cpp b/common/trace_snappyfile.cpp new file mode 100644 index 0000000..4dbe42d --- /dev/null +++ b/common/trace_snappyfile.cpp @@ -0,0 +1,338 @@ +/************************************************************************** + * + * Copyright 2011 Zack Rusin + * 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_snappyfile.hpp" + +#include + +#include + +#include +#include + +using namespace Trace; + +/* + * Snappy file format. + * ------------------- + * + * Snappy at its core is just a compressoin algorithm so we're + * creating a new file format which uses snappy compression + * to hold the trace data. + * + * The file is composed of a number of chunks, they are: + * chunk { + * uint32 - specifying the length of the compressed data + * compressed data, in little endian + * } + * File can contain any number of such chunks. + * The default size of an uncompressed chunk is specified in + * SNAPPY_CHUNK_SIZE. + * + * Note: + * Currently the default size for a a to-be-compressed data is + * 1mb, meaning that the compressed data will be <= 1mb. + * The reason it's 1mb is because it seems + * to offer a pretty good compression/disk io speed ratio + * but that might change. + * + */ + +SnappyFile::SnappyFile(const std::string &filename, + File::Mode mode) + : File(), + m_cache(0), + m_cachePtr(0), + m_cacheSize(0) +{ + size_t maxCompressedLength = + snappy::MaxCompressedLength(SNAPPY_CHUNK_SIZE); + m_compressedCache = new char[maxCompressedLength]; +} + +SnappyFile::~SnappyFile() +{ + delete [] m_compressedCache; + delete [] m_cache; +} + +bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode) +{ + std::ios_base::openmode fmode = std::fstream::binary; + if (mode == File::Write) { + fmode |= (std::fstream::out | std::fstream::trunc); + createCache(SNAPPY_CHUNK_SIZE); + } else if (mode == File::Read) { + fmode |= std::fstream::in; + } + + m_stream.open(filename.c_str(), fmode); + + //read in the initial buffer if we're reading + if (m_stream.is_open() && mode == File::Read) { + m_stream.seekg(0, std::ios::end); + m_endPos = m_stream.tellg(); + m_stream.seekg(0, std::ios::beg); + + // read the snappy file identifier + unsigned char byte1, byte2; + m_stream >> byte1; + m_stream >> byte2; + assert(byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2); + + flushReadCache(); + } else if (m_stream.is_open() && mode == File::Write) { + // write the snappy file identifier + m_stream << SNAPPY_BYTE1; + m_stream << SNAPPY_BYTE2; + } + return m_stream.is_open(); +} + +bool SnappyFile::rawWrite(const void *buffer, size_t length) +{ + if (freeCacheSize() > length) { + memcpy(m_cachePtr, buffer, length); + m_cachePtr += length; + } else if (freeCacheSize() == length) { + memcpy(m_cachePtr, buffer, length); + m_cachePtr += length; + flushWriteCache(); + } else { + int sizeToWrite = length; + + while (sizeToWrite >= freeCacheSize()) { + int endSize = freeCacheSize(); + int offset = length - sizeToWrite; + memcpy(m_cachePtr, (const char*)buffer + offset, endSize); + sizeToWrite -= endSize; + m_cachePtr += endSize; + flushWriteCache(); + } + if (sizeToWrite) { + int offset = length - sizeToWrite; + memcpy(m_cachePtr, (const char*)buffer + offset, sizeToWrite); + m_cachePtr += sizeToWrite; + } + } + + return true; +} + +bool SnappyFile::rawRead(void *buffer, size_t length) +{ + if (endOfData()) { + return false; + } + + if (freeCacheSize() >= length) { + memcpy(buffer, m_cachePtr, length); + m_cachePtr += length; + } else { + size_t sizeToRead = length; + size_t offset = 0; + while (sizeToRead) { + size_t chunkSize = std::min(freeCacheSize(), sizeToRead); + offset = length - sizeToRead; + memcpy((char*)buffer + offset, m_cachePtr, chunkSize); + m_cachePtr += chunkSize; + sizeToRead -= chunkSize; + if (sizeToRead > 0) { + flushReadCache(); + } + if (!m_cacheSize) { + break; + } + } + } + + return true; +} + +int SnappyFile::rawGetc() +{ + int c = 0; + if (!rawRead(&c, 1)) + return -1; + return c; +} + +void SnappyFile::rawClose() +{ + if (m_mode == File::Write) { + flushWriteCache(); + } + m_stream.close(); + delete [] m_cache; + m_cache = NULL; + m_cachePtr = NULL; +} + +void SnappyFile::rawFlush() +{ + assert(m_mode == File::Write); + flushWriteCache(); + m_stream.flush(); +} + +void SnappyFile::flushWriteCache() +{ + size_t inputLength = usedCacheSize(); + + if (inputLength) { + size_t compressedLength; + + ::snappy::RawCompress(m_cache, inputLength, + m_compressedCache, &compressedLength); + + writeCompressedLength(compressedLength); + m_stream.write(m_compressedCache, compressedLength); + m_cachePtr = m_cache; + } + assert(m_cachePtr == m_cache); +} + +void SnappyFile::flushReadCache(size_t skipLength) +{ + //assert(m_cachePtr == m_cache + m_cacheSize); + m_currentOffset.chunk = m_stream.tellg(); + size_t compressedLength; + compressedLength = readCompressedLength(); + + if (compressedLength) { + m_stream.read((char*)m_compressedCache, compressedLength); + ::snappy::GetUncompressedLength(m_compressedCache, compressedLength, + &m_cacheSize); + createCache(m_cacheSize); + if (skipLength < m_cacheSize) { + ::snappy::RawUncompress(m_compressedCache, compressedLength, + m_cache); + } + } else { + createCache(0); + } +} + +void SnappyFile::createCache(size_t size) +{ + // TODO: only re-allocate if the current buffer is not big enough + + if (m_cache) { + delete [] m_cache; + } + + if (size) { + m_cache = new char[size]; + } else { + m_cache = NULL; + } + + m_cachePtr = m_cache; + m_cacheSize = size; +} + +void SnappyFile::writeCompressedLength(size_t length) +{ + unsigned char buf[4]; + buf[0] = length & 0xff; length >>= 8; + buf[1] = length & 0xff; length >>= 8; + buf[2] = length & 0xff; length >>= 8; + buf[3] = length & 0xff; length >>= 8; + assert(length == 0); + m_stream.write((const char *)buf, sizeof buf); +} + +size_t SnappyFile::readCompressedLength() +{ + unsigned char buf[4]; + size_t length; + m_stream.read((char *)buf, sizeof buf); + if (m_stream.fail()) { + length = 0; + } else { + length = (size_t)buf[0]; + length |= ((size_t)buf[1] << 8); + length |= ((size_t)buf[2] << 16); + length |= ((size_t)buf[3] << 24); + } + return length; +} + +bool SnappyFile::supportsOffsets() const +{ + return true; +} + +File::Offset SnappyFile::currentOffset() +{ + m_currentOffset.offsetInChunk = m_cachePtr - m_cache; + return m_currentOffset; +} + +void SnappyFile::setCurrentOffset(const File::Offset &offset) +{ + // to remove eof bit + m_stream.clear(); + // seek to the start of a chunk + m_stream.seekg(offset.chunk, std::ios::beg); + // load the chunk + flushReadCache(); + assert(m_cacheSize >= offset.offsetInChunk); + // seek within our cache to the correct location within the chunk + m_cachePtr = m_cache + offset.offsetInChunk; + +} + +bool SnappyFile::rawSkip(size_t length) +{ + if (endOfData()) { + return false; + } + + if (freeCacheSize() >= length) { + m_cachePtr += length; + } else { + size_t sizeToRead = length; + while (sizeToRead) { + size_t chunkSize = std::min(freeCacheSize(), sizeToRead); + m_cachePtr += chunkSize; + sizeToRead -= chunkSize; + if (sizeToRead > 0) { + flushReadCache(sizeToRead); + } + if (!m_cacheSize) { + break; + } + } + } + + return true; +} + +int SnappyFile::rawPercentRead() +{ + return 100 * (double(m_stream.tellg()) / double(m_endPos)); +} diff --git a/common/trace_snappyfile.hpp b/common/trace_snappyfile.hpp new file mode 100644 index 0000000..33159ec --- /dev/null +++ b/common/trace_snappyfile.hpp @@ -0,0 +1,106 @@ +/************************************************************************** + * + * Copyright 2011 Zack Rusin + * 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_SNAPPYFILE_HPP +#define TRACE_SNAPPYFILE_HPP + +#include + +#include "trace_file.hpp" + +#include +#include + +namespace snappy { + class File; +} + +namespace Trace { + +#define SNAPPY_CHUNK_SIZE (1 * 1024 * 1024) + +#define SNAPPY_BYTE1 'a' +#define SNAPPY_BYTE2 't' + + +class SnappyFile : public File { +public: + SnappyFile(const std::string &filename = std::string(), + File::Mode mode = File::Read); + virtual ~SnappyFile(); + + virtual bool supportsOffsets() const; + virtual File::Offset currentOffset(); + virtual void setCurrentOffset(const File::Offset &offset); +protected: + virtual bool rawOpen(const std::string &filename, File::Mode mode); + virtual bool rawWrite(const void *buffer, size_t length); + virtual bool rawRead(void *buffer, size_t length); + virtual int rawGetc(); + virtual void rawClose(); + virtual void rawFlush(); + virtual bool rawSkip(size_t length); + virtual int rawPercentRead(); + +private: + inline size_t usedCacheSize() const + { + assert(m_cachePtr >= m_cache); + return m_cachePtr - m_cache; + } + inline size_t freeCacheSize() const + { + assert(m_cacheSize >= usedCacheSize()); + if (m_cacheSize > 0) { + return m_cacheSize - usedCacheSize(); + } else { + return 0; + } + } + inline bool endOfData() const + { + return m_stream.eof() && freeCacheSize() == 0; + } + void flushWriteCache(); + void flushReadCache(size_t skipLength = 0); + void createCache(size_t size); + void writeCompressedLength(size_t length); + size_t readCompressedLength(); +private: + std::fstream m_stream; + char *m_cache; + char *m_cachePtr; + size_t m_cacheSize; + + char *m_compressedCache; + + File::Offset m_currentOffset; + std::streampos m_endPos; +}; + +} + +#endif // TRACE_SNAPPYFILE_HPP diff --git a/common/trace_writer.cpp b/common/trace_writer.cpp new file mode 100644 index 0000000..5a5f1f7 --- /dev/null +++ b/common/trace_writer.cpp @@ -0,0 +1,303 @@ +/************************************************************************** + * + * Copyright 2007-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. + * + **************************************************************************/ + + +#include +#include +#include +#include +#include + +#include "os.hpp" +#include "trace_writer.hpp" +#include "trace_snappyfile.hpp" +#include "trace_format.hpp" + + +namespace Trace { + + +Writer::Writer() : + call_no(0) +{ + m_file = new Trace::SnappyFile; + close(); +} + +Writer::~Writer() +{ + close(); + delete m_file; + m_file = NULL; +} + +void +Writer::close(void) { + m_file->close(); +} + +bool +Writer::open(const char *filename) { + close(); + + if (!m_file->open(filename, File::Write)) { + return false; + } + + call_no = 0; + functions.clear(); + structs.clear(); + enums.clear(); + bitmasks.clear(); + + _writeUInt(TRACE_VERSION); + + return true; +} + +void inline +Writer::_write(const void *sBuffer, size_t dwBytesToWrite) { + m_file->write(sBuffer, dwBytesToWrite); +} + +void inline +Writer::_writeByte(char c) { + _write(&c, 1); +} + +void inline +Writer::_writeUInt(unsigned long long value) { + char buf[2 * sizeof value]; + unsigned len; + + len = 0; + do { + assert(len < sizeof buf); + buf[len] = 0x80 | (value & 0x7f); + value >>= 7; + ++len; + } while (value); + + assert(len); + buf[len - 1] &= 0x7f; + + _write(buf, len); +} + +void inline +Writer::_writeFloat(float value) { + assert(sizeof value == 4); + _write((const char *)&value, sizeof value); +} + +void inline +Writer::_writeDouble(double value) { + assert(sizeof value == 8); + _write((const char *)&value, sizeof value); +} + +void inline +Writer::_writeString(const char *str) { + size_t len = strlen(str); + _writeUInt(len); + _write(str, len); +} + +inline bool lookup(std::vector &map, size_t index) { + if (index >= map.size()) { + map.resize(index + 1); + return false; + } else { + return map[index]; + } +} + +unsigned Writer::beginEnter(const FunctionSig *sig) { + _writeByte(Trace::EVENT_ENTER); + _writeUInt(sig->id); + if (!lookup(functions, sig->id)) { + _writeString(sig->name); + _writeUInt(sig->num_args); + for (unsigned i = 0; i < sig->num_args; ++i) { + _writeString(sig->arg_names[i]); + } + functions[sig->id] = true; + } + + return call_no++; +} + +void Writer::endEnter(void) { + _writeByte(Trace::CALL_END); +} + +void Writer::beginLeave(unsigned call) { + _writeByte(Trace::EVENT_LEAVE); + _writeUInt(call); +} + +void Writer::endLeave(void) { + _writeByte(Trace::CALL_END); +} + +void Writer::beginArg(unsigned index) { + _writeByte(Trace::CALL_ARG); + _writeUInt(index); +} + +void Writer::beginReturn(void) { + _writeByte(Trace::CALL_RET); +} + +void Writer::beginArray(size_t length) { + _writeByte(Trace::TYPE_ARRAY); + _writeUInt(length); +} + +void Writer::beginStruct(const StructSig *sig) { + _writeByte(Trace::TYPE_STRUCT); + _writeUInt(sig->id); + if (!lookup(structs, sig->id)) { + _writeString(sig->name); + _writeUInt(sig->num_members); + for (unsigned i = 0; i < sig->num_members; ++i) { + _writeString(sig->member_names[i]); + } + structs[sig->id] = true; + } +} + +void Writer::writeBool(bool value) { + _writeByte(value ? Trace::TYPE_TRUE : Trace::TYPE_FALSE); +} + +void Writer::writeSInt(signed long long value) { + if (value < 0) { + _writeByte(Trace::TYPE_SINT); + _writeUInt(-value); + } else { + _writeByte(Trace::TYPE_UINT); + _writeUInt(value); + } +} + +void Writer::writeUInt(unsigned long long value) { + _writeByte(Trace::TYPE_UINT); + _writeUInt(value); +} + +void Writer::writeFloat(float value) { + _writeByte(Trace::TYPE_FLOAT); + _writeFloat(value); +} + +void Writer::writeDouble(double value) { + _writeByte(Trace::TYPE_DOUBLE); + _writeDouble(value); +} + +void Writer::writeString(const char *str) { + if (!str) { + Writer::writeNull(); + return; + } + _writeByte(Trace::TYPE_STRING); + _writeString(str); +} + +void Writer::writeString(const char *str, size_t len) { + if (!str) { + Writer::writeNull(); + return; + } + _writeByte(Trace::TYPE_STRING); + _writeUInt(len); + _write(str, len); +} + +void Writer::writeWString(const wchar_t *str) { + if (!str) { + Writer::writeNull(); + return; + } + _writeByte(Trace::TYPE_STRING); + _writeString(""); +} + +void Writer::writeBlob(const void *data, size_t size) { + if (!data) { + Writer::writeNull(); + return; + } + _writeByte(Trace::TYPE_BLOB); + _writeUInt(size); + if (size) { + _write(data, size); + } +} + +void Writer::writeEnum(const EnumSig *sig) { + _writeByte(Trace::TYPE_ENUM); + _writeUInt(sig->id); + if (!lookup(enums, sig->id)) { + _writeString(sig->name); + Writer::writeSInt(sig->value); + enums[sig->id] = true; + } +} + +void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) { + _writeByte(Trace::TYPE_BITMASK); + _writeUInt(sig->id); + if (!lookup(bitmasks, sig->id)) { + _writeUInt(sig->num_flags); + for (unsigned i = 0; i < sig->num_flags; ++i) { + if (i != 0 && sig->flags[i].value == 0) { + OS::DebugMessage("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name); + } + _writeString(sig->flags[i].name); + _writeUInt(sig->flags[i].value); + } + bitmasks[sig->id] = true; + } + _writeUInt(value); +} + +void Writer::writeNull(void) { + _writeByte(Trace::TYPE_NULL); +} + +void Writer::writeOpaque(const void *addr) { + if (!addr) { + Writer::writeNull(); + return; + } + _writeByte(Trace::TYPE_OPAQUE); + _writeUInt((size_t)addr); +} + + +} /* namespace Trace */ + diff --git a/common/trace_writer.hpp b/common/trace_writer.hpp new file mode 100644 index 0000000..dfb76b2 --- /dev/null +++ b/common/trace_writer.hpp @@ -0,0 +1,145 @@ +/************************************************************************** + * + * Copyright 2007-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. + * + **************************************************************************/ + +/* + * Trace writing functions. + */ + +#ifndef _TRACE_WRITER_HPP_ +#define _TRACE_WRITER_HPP_ + + +#include + +#include + +#include "trace_model.hpp" + + +namespace Trace { + class File; + + class Writer { + protected: + File *m_file; + unsigned call_no; + + std::vector functions; + std::vector structs; + std::vector enums; + std::vector bitmasks; + + public: + Writer(); + ~Writer(); + + bool open(const char *filename); + void close(void); + + unsigned beginEnter(const FunctionSig *sig); + void endEnter(void); + + void beginLeave(unsigned call); + void endLeave(void); + + void beginArg(unsigned index); + inline void endArg(void) {} + + void beginReturn(void); + inline void endReturn(void) {} + + void beginArray(size_t length); + inline void endArray(void) {} + + inline void beginElement(void) {} + inline void endElement(void) {} + + void beginStruct(const StructSig *sig); + inline void endStruct(void) {} + + void writeBool(bool value); + void writeSInt(signed long long value); + void writeUInt(unsigned long long value); + void writeFloat(float value); + void writeDouble(double value); + void writeString(const char *str); + void writeString(const char *str, size_t size); + void writeWString(const wchar_t *str); + void writeBlob(const void *data, size_t size); + void writeEnum(const EnumSig *sig); + void writeBitmask(const BitmaskSig *sig, unsigned long long value); + void writeNull(void); + void writeOpaque(const void *ptr); + + void writeCall(Call *call); + + protected: + void inline _write(const void *sBuffer, size_t dwBytesToWrite); + void inline _writeByte(char c); + void inline _writeUInt(unsigned long long value); + void inline _writeFloat(float value); + void inline _writeDouble(double value); + void inline _writeString(const char *str); + + }; + + /** + * A specialized Writer class, mean to trace the current process. + * + * In particular: + * - it creates a trace file based on the current process name + * - uses mutexes to allow tracing from multiple threades + * - flushes the output to ensure the last call is traced in event of + * abnormal termination + */ + class LocalWriter : public Writer { + protected: + int acquired; + + public: + /** + * Should never called directly -- use localWriter singleton below instead. + */ + LocalWriter(); + ~LocalWriter(); + + void open(void); + + unsigned beginEnter(const FunctionSig *sig); + void endEnter(void); + + void beginLeave(unsigned call); + void endLeave(void); + + void flush(void); + }; + + /** + * Singleton. + */ + extern LocalWriter localWriter; +} + +#endif /* _TRACE_WRITER_HPP_ */ diff --git a/formatter.hpp b/formatter.hpp deleted file mode 100644 index 181e2d1..0000000 --- a/formatter.hpp +++ /dev/null @@ -1,174 +0,0 @@ -/************************************************************************** - * - * 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. - * - **************************************************************************/ - -/* - * Helpers for coloring output. - */ - -#ifndef _FORMATTER_HPP_ -#define _FORMATTER_HPP_ - - -#include - - -namespace Formatter { - -/* - * See also http://bytes.com/topic/c/answers/63822-design-question-little-c-header-colorizing-text-linux-comments-ideas - */ - -class Attribute { -public: - virtual ~Attribute() {} - - virtual void apply(std::ostream &) const {} -}; - - -enum Color { - RED, - GREEN, - BLUE, -}; - - -class Formatter { -public: - virtual ~Formatter() {} - - virtual Attribute *normal(void) const { return new Attribute; } - virtual Attribute *bold(void) const { return new Attribute; } - virtual Attribute *italic(void) const { return new Attribute; } - virtual Attribute *color(Color) const { return new Attribute; } -}; - - -class AnsiAttribute : public Attribute { -protected: - const char *escape; -public: - AnsiAttribute(const char *_escape) : escape(_escape) {} - void apply(std::ostream& os) const { - os << "\33[" << escape; - } -}; - - -/** - * Formatter for plain-text files which outputs ANSI escape codes. See - * http://en.wikipedia.org/wiki/ANSI_escape_code for more information - * concerning ANSI escape codes. - */ -class AnsiFormatter : public Formatter { -protected: -public: - virtual Attribute *normal(void) const { return new AnsiAttribute("0m"); } - virtual Attribute *bold(void) const { return new AnsiAttribute("1m"); } - virtual Attribute *italic(void) const { return new AnsiAttribute("3m"); } - virtual Attribute *color(Color c) const { - static const char *color_escapes[] = { - "31m", /* red */ - "32m", /* green */ - "34m", /* blue */ - }; - return new AnsiAttribute(color_escapes[c]); - } -}; - - -inline std::ostream& operator<<(std::ostream& os, const Attribute *attr) { - attr->apply(os); - return os; -} - - -#ifdef _WIN32 - -#include - -class WindowsAttribute : public Attribute { -protected: - WORD wAttributes; -public: - WindowsAttribute(WORD _wAttributes) : wAttributes(_wAttributes) {} - void apply(std::ostream& os) const { - DWORD nStdHandleOutput; - if (os == std::cout) { - nStdHandleOutput = STD_OUTPUT_HANDLE; - } else if (os == std::cerr) { - nStdHandleOutput = STD_ERROR_HANDLE; - } else { - return; - } - HANDLE hConsoleOutput = GetStdHandle(nStdHandleOutput); - if (hConsoleOutput == INVALID_HANDLE_VALUE) { - return; - } - - SetConsoleTextAttribute(hConsoleOutput, wAttributes); - } -}; - - -/** - * Formatter for the Windows Console. - */ -class WindowsFormatter : public Formatter { -protected: -public: - virtual Attribute *normal(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); } - virtual Attribute *bold(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); } - virtual Attribute *italic(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); } - virtual Attribute *color(Color c) const { - static const WORD color_escapes[] = { - FOREGROUND_RED | FOREGROUND_INTENSITY, - FOREGROUND_GREEN | FOREGROUND_INTENSITY, - FOREGROUND_BLUE | FOREGROUND_INTENSITY, - }; - return new WindowsAttribute(color_escapes[c]); - } -}; - -#endif - - -inline Formatter *defaultFormatter(bool color = true) { - if (color) { -#ifdef _WIN32 - return new WindowsFormatter; -#else - return new AnsiFormatter; -#endif - } else { - return new Formatter; - } -} - - -} /* namespace Formatter */ - - -#endif /* _FORMATTER_HPP_ */ diff --git a/image.cpp b/image.cpp deleted file mode 100644 index 4da9c13..0000000 --- a/image.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Jose Fonseca - * Copyright 2008-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 -#include - -#include "image.hpp" - - -namespace Image { - - -double Image::compare(Image &ref) -{ - if (width != ref.width || - height != ref.height || - channels != ref.channels) { - return 0.0; - } - - const unsigned char *pSrc = start(); - const unsigned char *pRef = ref.start(); - - assert(channels >= 3); - - unsigned long long error = 0; - for (unsigned y = 0; y < height; ++y) { - for (unsigned x = 0; x < width; ++x) { - // FIXME: Ignore alpha channel until we are able to pick a visual - // that matches the traces - for (unsigned c = 0; c < 3; ++c) { - int delta = pSrc[x*channels + c] - pRef[x*channels + c]; - error += delta*delta; - } - } - - pSrc += stride(); - pRef += ref.stride(); - } - - double numerator = error*2 + 1; - double denominator = height*width*3ULL*255ULL*255ULL*2; - double quotient = numerator/denominator; - - // Precision in bits - double precision = -log(quotient)/log(2.0); - - return precision; -} - - -} /* namespace Image */ diff --git a/image.hpp b/image.hpp deleted file mode 100644 index dc53ec9..0000000 --- a/image.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/************************************************************************** - * - * Copyright 2008-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. - * - **************************************************************************/ - -/* - * Image I/O. - */ - -#ifndef _IMAGE_HPP_ -#define _IMAGE_HPP_ - - -#include - - -namespace Image { - - -class Image { -public: - unsigned width; - unsigned height; - unsigned channels; - - // Flipped vertically or not - bool flipped; - - // Pixels in RGBA format - unsigned char *pixels; - - inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) : - width(w), - height(h), - channels(c), - flipped(f), - pixels(new unsigned char[h*w*c]) - {} - - inline ~Image() { - delete [] pixels; - } - - inline unsigned char *start(void) { - return flipped ? pixels + (height - 1)*width*channels : pixels; - } - - inline const unsigned char *start(void) const { - return flipped ? pixels + (height - 1)*width*channels : pixels; - } - - inline unsigned char *end(void) { - return flipped ? pixels - width*channels : pixels + height*width*channels; - } - - inline const unsigned char *end(void) const { - return flipped ? pixels - width*channels : pixels + height*width*channels; - } - - inline signed stride(void) const { - return flipped ? -width*channels : width*channels; - } - - bool writeBMP(const char *filename) const; - - void writePNM(std::ostream &os, const char *comment = NULL) const; - - inline bool writePNM(const char *filename, const char *comment = NULL) const { - std::ofstream os(filename, std::ofstream::binary); - if (!os) { - return false; - } - writePNM(os, comment); - return true; - } - - bool writePNG(const char *filename) const; - - double compare(Image &ref); -}; - -bool writePixelsToBuffer(unsigned char *pixels, - unsigned w, unsigned h, unsigned numChannels, - bool flipped, - char **buffer, - int *size); - -Image * -readPNG(const char *filename); - - -} /* namespace Image */ - - -#endif /* _IMAGE_HPP_ */ diff --git a/image_bmp.cpp b/image_bmp.cpp deleted file mode 100644 index 346f39a..0000000 --- a/image_bmp.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Jose Fonseca - * Copyright 2008-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 -#include - -#include "image.hpp" - - -namespace Image { - - -#pragma pack(push,2) -struct FileHeader { - uint16_t bfType; - uint32_t bfSize; - uint16_t bfReserved1; - uint16_t bfReserved2; - uint32_t bfOffBits; -}; -#pragma pack(pop) - -struct InfoHeader { - uint32_t biSize; - int32_t biWidth; - int32_t biHeight; - uint16_t biPlanes; - uint16_t biBitCount; - uint32_t biCompression; - uint32_t biSizeImage; - int32_t biXPelsPerMeter; - int32_t biYPelsPerMeter; - uint32_t biClrUsed; - uint32_t biClrImportant; -}; - -struct Pixel { - uint8_t rgbBlue; - uint8_t rgbGreen; - uint8_t rgbRed; - uint8_t rgbAlpha; -}; - - -bool -Image::writeBMP(const char *filename) const { - assert(channels == 4); - - struct FileHeader bmfh; - struct InfoHeader bmih; - unsigned x, y; - - bmfh.bfType = 0x4d42; - bmfh.bfSize = 14 + 40 + height*width*4; - bmfh.bfReserved1 = 0; - bmfh.bfReserved2 = 0; - bmfh.bfOffBits = 14 + 40; - - bmih.biSize = 40; - bmih.biWidth = width; - bmih.biHeight = height; - bmih.biPlanes = 1; - bmih.biBitCount = 32; - bmih.biCompression = 0; - bmih.biSizeImage = height*width*4; - bmih.biXPelsPerMeter = 0; - bmih.biYPelsPerMeter = 0; - bmih.biClrUsed = 0; - bmih.biClrImportant = 0; - - std::ofstream stream(filename, std::ofstream::binary); - - if (!stream) { - return false; - } - - stream.write((const char *)&bmfh, 14); - stream.write((const char *)&bmih, 40); - - unsigned stride = width*4; - - if (flipped) { - for (y = 0; y < height; ++y) { - const unsigned char *ptr = pixels + y * stride; - for (x = 0; x < width; ++x) { - struct Pixel pixel; - pixel.rgbRed = ptr[x*4 + 0]; - pixel.rgbGreen = ptr[x*4 + 1]; - pixel.rgbBlue = ptr[x*4 + 2]; - pixel.rgbAlpha = ptr[x*4 + 3]; - stream.write((const char *)&pixel, 4); - } - } - } else { - y = height; - while (y--) { - const unsigned char *ptr = pixels + y * stride; - for (x = 0; x < width; ++x) { - struct Pixel pixel; - pixel.rgbRed = ptr[x*4 + 0]; - pixel.rgbGreen = ptr[x*4 + 1]; - pixel.rgbBlue = ptr[x*4 + 2]; - pixel.rgbAlpha = ptr[x*4 + 3]; - stream.write((const char *)&pixel, 4); - } - } - } - - stream.close(); - - return true; -} - - -} /* namespace Image */ diff --git a/image_png.cpp b/image_png.cpp deleted file mode 100644 index fd22213..0000000 --- a/image_png.cpp +++ /dev/null @@ -1,312 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Jose Fonseca - * Copyright 2008-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 -#include - -#include -#include -#include - -#include - -#include "image.hpp" - - -namespace Image { - - -bool -Image::writePNG(const char *filename) const { - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - - fp = fopen(filename, "wb"); - if (!fp) - goto no_fp; - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) - goto no_png; - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr, NULL); - goto no_png; - } - - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_write_struct(&png_ptr, &info_ptr); - goto no_png; - } - - png_init_io(png_ptr, fp); - - int color_type; - switch (channels) { - case 4: - color_type = PNG_COLOR_TYPE_RGB_ALPHA; - break; - case 3: - color_type = PNG_COLOR_TYPE_RGB; - break; - case 2: - color_type = PNG_COLOR_TYPE_GRAY_ALPHA; - break; - case 1: - color_type = PNG_COLOR_TYPE_GRAY; - break; - default: - assert(0); - return false; - } - - png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); - - png_write_info(png_ptr, info_ptr); - - if (!flipped) { - for (unsigned y = 0; y < height; ++y) { - png_bytep row = (png_bytep)(pixels + y*width*channels); - png_write_rows(png_ptr, &row, 1); - } - } else { - unsigned y = height; - while (y--) { - png_bytep row = (png_bytep)(pixels + y*width*channels); - png_write_rows(png_ptr, &row, 1); - } - } - - png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, &info_ptr); - - fclose(fp); - return true; - -no_png: - fclose(fp); -no_fp: - return false; -} - - -Image * -readPNG(const char *filename) -{ - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - png_infop end_info; - Image *image; - - fp = fopen(filename, "rb"); - if (!fp) - goto no_fp; - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) - goto no_png; - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, NULL, NULL); - goto no_png; - } - - end_info = png_create_info_struct(png_ptr); - if (!end_info) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - goto no_png; - } - - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - goto no_png; - } - - png_init_io(png_ptr, fp); - - png_read_info(png_ptr, info_ptr); - - png_uint_32 width, height; - int bit_depth, color_type, interlace_type, compression_type, filter_method; - - png_get_IHDR(png_ptr, info_ptr, - &width, &height, - &bit_depth, &color_type, &interlace_type, - &compression_type, &filter_method); - - image = new Image(width, height); - if (!image) - goto no_image; - - /* Convert to RGBA8 */ - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand_gray_1_2_4_to_8(png_ptr); - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(png_ptr); - if (bit_depth == 16) - png_set_strip_16(png_ptr); - - for (unsigned y = 0; y < height; ++y) { - png_bytep row = (png_bytep)(image->pixels + y*width*4); - png_read_row(png_ptr, row, NULL); - } - - png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - fclose(fp); - return image; - -no_image: - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); -no_png: - fclose(fp); -no_fp: - return NULL; -} - - -struct png_tmp_buffer -{ - char *buffer; - size_t size; -}; - -static void -pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) -{ - struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_get_io_ptr(png_ptr); - size_t nsize = buf->size + length; - - /* allocate or grow buffer */ - if (buf->buffer) - buf->buffer = (char*)realloc(buf->buffer, nsize); - else - buf->buffer = (char*)malloc(nsize); - - if (!buf->buffer) - png_error(png_ptr, "Buffer allocation error"); - - memcpy(buf->buffer + buf->size, data, length); - buf->size += length; -} - -bool writePixelsToBuffer(unsigned char *pixels, - unsigned width, unsigned height, unsigned numChannels, - bool flipped, - char **buffer, - int *size) -{ - struct png_tmp_buffer png_mem; - png_structp png_ptr; - png_infop info_ptr; - int type; - - png_mem.buffer = NULL; - png_mem.size = 0; - - switch (numChannels) { - case 4: - type = PNG_COLOR_TYPE_RGB_ALPHA; - break; - case 3: - type = PNG_COLOR_TYPE_RGB; - break; - case 2: - type = PNG_COLOR_TYPE_GRAY_ALPHA; - break; - case 1: - type = PNG_COLOR_TYPE_GRAY; - break; - default: - goto no_png; - } - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) - goto no_png; - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr, NULL); - goto no_png; - } - - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_write_struct(&png_ptr, &info_ptr); - goto no_png; - } - - png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL); - - png_set_IHDR(png_ptr, info_ptr, width, height, 8, - type, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); - - png_write_info(png_ptr, info_ptr); - - if (!flipped) { - for (unsigned y = 0; y < height; ++y) { - png_bytep row = (png_bytep)(pixels + y*width*numChannels); - png_write_rows(png_ptr, &row, 1); - } - } else { - unsigned y = height; - while (y--) { - png_bytep row = (png_bytep)(pixels + y*width*numChannels); - png_write_rows(png_ptr, &row, 1); - } - } - - png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, &info_ptr); - - *buffer = png_mem.buffer; - *size = png_mem.size; - - return true; - -no_png: - *buffer = NULL; - *size = 0; - - if (png_mem.buffer) - free(png_mem.buffer); - return false; -} - -} /* namespace Image */ diff --git a/image_pnm.cpp b/image_pnm.cpp deleted file mode 100644 index 5397a1a..0000000 --- a/image_pnm.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Jose Fonseca - * Copyright 2008-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 -#include -#include - -#include "image.hpp" - - -namespace Image { - -/** - * http://en.wikipedia.org/wiki/Netpbm_format - * http://netpbm.sourceforge.net/doc/ppm.html - */ -void -Image::writePNM(std::ostream &os, const char *comment) const { - assert(channels == 1 || channels >= 3); - - os << (channels == 1 ? "P5" : "P6") << "\n"; - if (comment) { - os << "#" << comment << "\n"; - } - os << width << " " << height << "\n"; - os << "255" << "\n"; - - const unsigned char *row; - - if (channels == 1 || channels == 3) { - for (row = start(); row != end(); row += stride()) { - os.write((const char *)row, width*channels); - } - } else { - unsigned char *tmp = new unsigned char[width*3]; - if (channels == 4) { - for (row = start(); row != end(); row += stride()) { - const uint32_t *src = (const uint32_t *)row; - uint32_t *dst = (uint32_t *)tmp; - unsigned x; - for (x = 0; x + 4 <= width; x += 4) { - /* - * It's much faster to access dwords than bytes. - * - * FIXME: Big-endian version. - */ - - uint32_t rgba0 = *src++ & 0xffffff; - uint32_t rgba1 = *src++ & 0xffffff; - uint32_t rgba2 = *src++ & 0xffffff; - uint32_t rgba3 = *src++ & 0xffffff; - uint32_t rgb0 = rgba0 - | (rgba1 << 24); - uint32_t rgb1 = (rgba1 >> 8) - | (rgba2 << 16); - uint32_t rgb2 = (rgba2 >> 16) - | (rgba3 << 8); - *dst++ = rgb0; - *dst++ = rgb1; - *dst++ = rgb2; - } - for (; x < width; ++x) { - tmp[x*3 + 0] = row[x*4 + 0]; - tmp[x*3 + 1] = row[x*4 + 1]; - tmp[x*3 + 2] = row[x*4 + 2]; - } - os.write((const char *)tmp, width*3); - } - } else if (channels == 2) { - for (row = start(); row != end(); row += stride()) { - const unsigned char *src = row; - unsigned char *dst = tmp; - for (unsigned x = 0; x < width; ++x) { - *dst++ = *src++; - *dst++ = *src++; - *dst++ = 0; - } - os.write((const char *)tmp, width*3); - } - } else { - assert(0); - } - delete [] tmp; - } -} - - -} /* namespace Image */ diff --git a/json.hpp b/json.hpp deleted file mode 100644 index 9e6b960..0000000 --- a/json.hpp +++ /dev/null @@ -1,337 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Jose Fonseca - * 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. - * - **************************************************************************/ - -/* - * Trace writing functions. - */ - -#ifndef _JSON_HPP_ -#define _JSON_HPP_ - -#include -#include -#include - -#include -#include -#include - - -class JSONWriter -{ -private: - std::ostream &os; - - int level; - bool value; - char space; - - void newline(void) { - os << "\n"; - for (int i = 0; i < level; ++i) - os << " "; - } - - void separator(void) { - if (value) { - os << ","; - switch (space) { - case '\0': - break; - case '\n': - newline(); - break; - default: - os << space; - break; - } - } else { - if (space == '\n') { - newline(); - } - } - } - - void escapeAsciiString(const char *str) { - os << "\""; - - const unsigned char *src = (const unsigned char *)str; - unsigned char c; - while ((c = *src++)) { - if ((c == '\"') || - (c == '\\')) { - // escape character - os << '\\' << (unsigned char)c; - } else if ((c >= 0x20 && c <= 0x7e) || - c == '\t' || - c == '\r' || - c == '\n') { - // pass-through character - os << (unsigned char)c; - } else { - assert(0); - os << "?"; - } - } - - os << "\""; - } - - void escapeUnicodeString(const char *str) { - os << "\""; - - const char *locale = setlocale(LC_CTYPE, ""); - const char *src = str; - mbstate_t state; - - memset(&state, 0, sizeof state); - - do { - // Convert characters one at a time in order to recover from - // conversion errors - wchar_t c; - size_t written = mbsrtowcs(&c, &src, 1, &state); - if (written == 0) { - // completed - break; - } if (written == (size_t)-1) { - // conversion error -- skip - os << "?"; - do { - ++src; - } while (*src & 0x80); - } else if ((c == '\"') || - (c == '\\')) { - // escape character - os << '\\' << (unsigned char)c; - } else if ((c >= 0x20 && c <= 0x7e) || - c == '\t' || - c == '\r' || - c == '\n') { - // pass-through character - os << (unsigned char)c; - } else { - // unicode - os << "\\u" << std::setfill('0') << std::hex << std::setw(4) << (unsigned)c; - os << std::dec; - } - } while (src); - - setlocale(LC_CTYPE, locale); - - os << "\""; - } - - void encodeBase64String(const unsigned char *bytes, size_t size) { - const char *table64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - unsigned char c0, c1, c2, c3; - char buf[4]; - unsigned written; - - os << "\""; - - written = 0; - while (size >= 3) { - c0 = bytes[0] >> 2; - c1 = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xf0) >> 4); - c2 = ((bytes[1] & 0x0f) << 2) | ((bytes[2] & 0xc0) >> 6); - c3 = bytes[2] & 0x3f; - - buf[0] = table64[c0]; - buf[1] = table64[c1]; - buf[2] = table64[c2]; - buf[3] = table64[c3]; - - os.write(buf, 4); - - bytes += 3; - size -= 3; - ++written; - - if (written >= 76/4 && size) { - os << "\n"; - written = 0; - } - } - - if (size > 0) { - c0 = bytes[0] >> 2; - c1 = ((bytes[0] & 0x03) << 4); - buf[2] = '='; - buf[3] = '='; - - if (size > 1) { - c1 |= ((bytes[1] & 0xf0) >> 4); - c2 = ((bytes[1] & 0x0f) << 2); - if (size > 2) { - c2 |= ((bytes[2] & 0xc0) >> 6); - c3 = bytes[2] & 0x3f; - buf[3] = table64[c3]; - } - buf[2] = table64[c2]; - } - buf[1] = table64[c1]; - buf[0] = table64[c0]; - - os.write(buf, 4); - } - - os << "\""; - } - -public: - JSONWriter(std::ostream &_os) : - os(_os), - level(0), - value(false), - space(0) - { - beginObject(); - } - - ~JSONWriter() { - endObject(); - newline(); - } - - inline void beginObject() { - separator(); - os << "{"; - ++level; - value = false; - } - - inline void endObject() { - --level; - if (value) - newline(); - os << "}"; - value = true; - space = '\n'; - } - - inline void beginMember(const char * name) { - space = 0; - separator(); - newline(); - escapeAsciiString(name); - os << ": "; - value = false; - } - - inline void beginMember(const std::string &name) { - beginMember(name.c_str()); - } - - inline void endMember(void) { - assert(value); - value = true; - space = 0; - } - - inline void beginArray() { - separator(); - os << "["; - ++level; - value = false; - space = 0; - } - - inline void endArray(void) { - --level; - if (space == '\n') { - newline(); - } - os << "]"; - value = true; - space = '\n'; - } - - inline void writeString(const char *s) { - separator(); - escapeUnicodeString(s); - value = true; - space = ' '; - } - - inline void writeString(const std::string &s) { - writeString(s.c_str()); - } - - inline void writeBase64(const void *bytes, size_t size) { - separator(); - encodeBase64String((const unsigned char *)bytes, size); - value = true; - space = ' '; - } - - inline void writeNull(void) { - separator(); - os << "null"; - value = true; - space = ' '; - } - - inline void writeBool(bool b) { - separator(); - os << (b ? "true" : "false"); - value = true; - space = ' '; - } - - template - inline void writeNumber(T n) { - if (n != n) { - // NaN - writeNull(); - } else { - separator(); - os << std::dec << std::setprecision(9) << n; - value = true; - space = ' '; - } - } - - inline void writeStringMember(const char *name, const char *s) { - beginMember(name); - writeString(s); - endMember(); - } - - inline void writeBoolMember(const char *name, bool b) { - beginMember(name); - writeBool(b); - endMember(); - } - - template - inline void writeNumberMember(const char *name, T n) { - beginMember(name); - writeNumber(n); - endMember(); - } -}; - -#endif /* _JSON_HPP_ */ diff --git a/os.hpp b/os.hpp deleted file mode 100644 index 8e487b5..0000000 --- a/os.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/************************************************************************** - * - * 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. - * - **************************************************************************/ - -/* - * Simple OS abstraction layer. - */ - -#ifndef _OS_HPP_ -#define _OS_HPP_ - -#include -#include -#include - -#ifdef _WIN32 -#ifndef snprintf -#define snprintf _snprintf -#endif -#ifndef vsnprintf -#define vsnprintf _vsnprintf -#endif -#define PATH_SEP '\\' -#else /* !_WIN32 */ -#define PATH_SEP '/' -#endif /* !_WIN32 */ - -#ifndef PATH_MAX -#define PATH_MAX 1024 -#endif - -namespace OS { - -void AcquireMutex(void); - -void ReleaseMutex(void); - -bool GetProcessName(char *str, size_t size); -bool GetCurrentDir(char *str, size_t size); - -void DebugMessage(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))) -#endif -; - -#if defined _WIN32 || defined __CYGWIN__ - /* We always use .def files on windows for now */ - #if 0 - #define PUBLIC __declspec(dllexport) - #else - #define PUBLIC - #endif - #define PRIVATE -#else - #if __GNUC__ >= 4 - #define PUBLIC __attribute__ ((visibility("default"))) - #define PRIVATE __attribute__ ((visibility("hidden"))) - #else - #define PUBLIC - #define PRIVATE - #endif -#endif - -/** - * Get the current time in microseconds from an unknown base. - */ -long long GetTime(void); - -void Abort(void); - -void SetExceptionCallback(void (*callback)(void)); -void ResetExceptionCallback(void); - -} /* namespace OS */ - -#endif /* _OS_HPP_ */ diff --git a/os_posix.cpp b/os_posix.cpp deleted file mode 100644 index 98a790b..0000000 --- a/os_posix.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/************************************************************************** - * - * Copyright 2010-2011 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 -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef __APPLE__ -#include -#endif - -#include "os.hpp" - - -namespace OS { - - -static pthread_mutex_t -mutex = PTHREAD_MUTEX_INITIALIZER; - - -void -AcquireMutex(void) -{ - pthread_mutex_lock(&mutex); -} - - -void -ReleaseMutex(void) -{ - pthread_mutex_unlock(&mutex); -} - - -bool -GetProcessName(char *str, size_t size) -{ - char szProcessPath[PATH_MAX + 1]; - char *lpProcessName; - - // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe -#ifdef __APPLE__ - uint32_t len = sizeof szProcessPath; - if (_NSGetExecutablePath(szProcessPath, &len) != 0) { - *str = 0; - return false; - } -#else - ssize_t len; - len = readlink("/proc/self/exe", szProcessPath, sizeof(szProcessPath) - 1); - if (len == -1) { - // /proc/self/exe is not available on setuid processes, so fallback to - // /proc/self/cmdline. - int fd = open("/proc/self/cmdline", O_RDONLY); - if (fd >= 0) { - len = read(fd, szProcessPath, sizeof(szProcessPath) - 1); - close(fd); - } - } - if (len <= 0) { - snprintf(str, size, "%i", (int)getpid()); - return true; - } -#endif - szProcessPath[len] = 0; - - lpProcessName = strrchr(szProcessPath, '/'); - lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath; - - strncpy(str, lpProcessName, size); - if (size) - str[size - 1] = 0; - - return true; -} - -bool -GetCurrentDir(char *str, size_t size) -{ - char *ret; - ret = getcwd(str, size); - str[size - 1] = 0; - return ret ? true : false; -} - -void -DebugMessage(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - fflush(stdout); - vfprintf(stderr, format, ap); - va_end(ap); -} - -long long GetTime(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_usec + tv.tv_sec*1000000LL; -} - -void -Abort(void) -{ - exit(0); -} - - -static void (*gCallback)(void) = NULL; - -#define NUM_SIGNALS 16 - -struct sigaction old_actions[NUM_SIGNALS]; - - -/* - * See also: - * - http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c - * - http://ggi.cvs.sourceforge.net/viewvc/ggi/ggi-core/libgg/gg/cleanup.c?view=markup - */ -static void signal_handler(int sig, siginfo_t *info, void *context) -{ - static int recursion_count = 0; - - fprintf(stderr, "signal_handler: sig = %i\n", sig); - - if (recursion_count) { - fprintf(stderr, "recursion with sig %i\n", sig); - } else { - if (gCallback) { - ++recursion_count; - gCallback(); - --recursion_count; - } - } - - struct sigaction *old_action; - if (sig >= NUM_SIGNALS) { - /* This should never happen */ - fprintf(stderr, "Unexpected signal %i\n", sig); - raise(SIGKILL); - } - old_action = &old_actions[sig]; - - if (old_action->sa_flags & SA_SIGINFO) { - // Handler is in sa_sigaction - old_action->sa_sigaction(sig, info, context); - } else { - if (old_action->sa_handler == SIG_DFL) { - fprintf(stderr, "taking default action for signal %i\n", sig); - -#if 1 - struct sigaction dfl_action; - dfl_action.sa_handler = SIG_DFL; - sigemptyset (&dfl_action.sa_mask); - dfl_action.sa_flags = 0; - sigaction(sig, &dfl_action, NULL); - - raise(sig); -#else - raise(SIGKILL); -#endif - } else if (old_action->sa_handler == SIG_IGN) { - /* ignore */ - } else { - /* dispatch to handler */ - old_action->sa_handler(sig); - } - } -} - -void -SetExceptionCallback(void (*callback)(void)) -{ - assert(!gCallback); - if (!gCallback) { - gCallback = callback; - - struct sigaction new_action; - new_action.sa_sigaction = signal_handler; - sigemptyset(&new_action.sa_mask); - new_action.sa_flags = SA_SIGINFO | SA_RESTART; - - - for (int sig = 1; sig < NUM_SIGNALS; ++sig) { - // SIGKILL and SIGSTOP can't be handled - if (sig != SIGKILL && sig != SIGSTOP) { - if (sigaction(sig, NULL, &old_actions[sig]) >= 0) { - sigaction(sig, &new_action, NULL); - } - } - } - } -} - -void -ResetExceptionCallback(void) -{ - gCallback = NULL; -} - -} /* namespace OS */ - diff --git a/os_win32.cpp b/os_win32.cpp deleted file mode 100644 index 587503c..0000000 --- a/os_win32.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/************************************************************************** - * - * 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 -#include -#include -#include -#include - -#include "os.hpp" - - -namespace OS { - - -/* - * Trick from http://locklessinc.com/articles/pthreads_on_windows/ - */ -static CRITICAL_SECTION -CriticalSection = { - (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0 -}; - - -void -AcquireMutex(void) -{ - EnterCriticalSection(&CriticalSection); -} - - -void -ReleaseMutex(void) -{ - LeaveCriticalSection(&CriticalSection); -} - - -bool -GetProcessName(char *str, size_t size) -{ - char szProcessPath[PATH_MAX]; - char *lpProcessName; - char *lpProcessExt; - - GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0])); - - lpProcessName = strrchr(szProcessPath, '\\'); - lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath; - - lpProcessExt = strrchr(lpProcessName, '.'); - if (lpProcessExt) { - *lpProcessExt = '\0'; - } - - strncpy(str, lpProcessName, size); - - return true; -} - -bool -GetCurrentDir(char *str, size_t size) -{ - DWORD ret; - ret = GetCurrentDirectoryA(size, str); - str[size - 1] = 0; - return ret == 0 ? false : true; -} - -void -DebugMessage(const char *format, ...) -{ - char buf[4096]; - - va_list ap; - va_start(ap, format); - fflush(stdout); - vsnprintf(buf, sizeof buf, format, ap); - va_end(ap); - - OutputDebugStringA(buf); - - /* - * Also write the message to stderr, when a debugger is not present (to - * avoid duplicate messages in command line debuggers). - */ -#if _WIN32_WINNT > 0x0400 - if (!IsDebuggerPresent()) { - fflush(stdout); - fputs(buf, stderr); - fflush(stderr); - } -#endif -} - -long long GetTime(void) -{ - static LARGE_INTEGER frequency; - LARGE_INTEGER counter; - if (!frequency.QuadPart) - QueryPerformanceFrequency(&frequency); - QueryPerformanceCounter(&counter); - return counter.QuadPart*1000000LL/frequency.QuadPart; -} - -void -Abort(void) -{ -#ifndef NDEBUG - DebugBreak(); -#else - ExitProcess(0); -#endif -} - - -static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL; -static void (*gCallback)(void) = NULL; - -static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo) -{ - if (gCallback) { - gCallback(); - } - - if (prevExceptionFilter) { - return prevExceptionFilter(pExceptionInfo); - } else { - return EXCEPTION_CONTINUE_SEARCH; - } -} - -void -SetExceptionCallback(void (*callback)(void)) -{ - assert(!gCallback); - - if (!gCallback) { - gCallback = callback; - - assert(!prevExceptionFilter); - prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter); - } -} - -void -ResetExceptionCallback(void) -{ - gCallback = NULL; -} - - -} /* namespace OS */ diff --git a/trace_file.cpp b/trace_file.cpp deleted file mode 100644 index f48c1aa..0000000 --- a/trace_file.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Zack Rusin - * 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_file.hpp" - -#include "trace_snappyfile.hpp" - -#include -#include - -#include - -#include "os.hpp" - -#include - -using namespace Trace; - - -File::File(const std::string &filename, - File::Mode mode) - : m_mode(mode), - m_isOpened(false) -{ - if (!filename.empty()) { - open(filename, m_mode); - } -} - -File::~File() -{ - close(); -} - - -void File::setCurrentOffset(const File::Offset &offset) -{ - assert(0); -} - -bool File::isZLibCompressed(const std::string &filename) -{ - std::fstream stream(filename.c_str(), - std::fstream::binary | std::fstream::in); - if (!stream.is_open()) - return false; - - unsigned char byte1, byte2; - stream >> byte1; - stream >> byte2; - stream.close(); - - return (byte1 == 0x1f && byte2 == 0x8b); -} - - -bool File::isSnappyCompressed(const std::string &filename) -{ - std::fstream stream(filename.c_str(), - std::fstream::binary | std::fstream::in); - if (!stream.is_open()) - return false; - - unsigned char byte1, byte2; - stream >> byte1; - stream >> byte2; - stream.close(); - - return (byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2); -} - -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ -} gz_dummy_stream; - -ZLibFile::ZLibFile(const std::string &filename, - File::Mode mode) - : File(filename, mode), - m_gzFile(NULL) -{ -} - -ZLibFile::~ZLibFile() -{ -} - -bool ZLibFile::rawOpen(const std::string &filename, File::Mode mode) -{ - m_gzFile = gzopen(filename.c_str(), - (mode == File::Write) ? "wb" : "rb"); - - if (mode == File::Read && m_gzFile) { - //XXX: unfortunately zlib doesn't support - // SEEK_END or we could've done: - //m_endOffset = gzseek(m_gzFile, 0, SEEK_END); - //gzrewind(m_gzFile); - gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile; - long loc = ftell(stream->file); - fseek(stream->file,0,SEEK_END); - m_endOffset = ftell(stream->file); - fseek(stream->file, loc, SEEK_SET); - } - - return m_gzFile != NULL; -} - -bool ZLibFile::rawWrite(const void *buffer, size_t length) -{ - return gzwrite(m_gzFile, buffer, length) != -1; -} - -bool ZLibFile::rawRead(void *buffer, size_t length) -{ - return gzread(m_gzFile, buffer, length) != -1; -} - -int ZLibFile::rawGetc() -{ - return gzgetc(m_gzFile); -} - -void ZLibFile::rawClose() -{ - if (m_gzFile) { - gzclose(m_gzFile); - m_gzFile = NULL; - } -} - -void ZLibFile::rawFlush() -{ - gzflush(m_gzFile, Z_SYNC_FLUSH); -} - -File::Offset ZLibFile::currentOffset() -{ - return File::Offset(gztell(m_gzFile)); -} - -bool ZLibFile::supportsOffsets() const -{ - return false; -} - -bool ZLibFile::rawSkip(size_t) -{ - return false; -} - -int ZLibFile::rawPercentRead() -{ - gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile; - return 100 * (ftell(stream->file) / m_endOffset); -} diff --git a/trace_file.hpp b/trace_file.hpp deleted file mode 100644 index 4b1b70d..0000000 --- a/trace_file.hpp +++ /dev/null @@ -1,224 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Zack Rusin - * 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_FILE_HPP -#define TRACE_FILE_HPP - -#include -#include -#include - -namespace Trace { - -class File { -public: - enum Mode { - Read, - Write - }; - struct Offset { - Offset(uint64_t _chunk = 0, uint32_t _offsetInChunk = 0) - : chunk(_chunk), - offsetInChunk(_offsetInChunk) - {} - uint64_t chunk; - uint32_t offsetInChunk; - }; - -public: - static bool isZLibCompressed(const std::string &filename); - static bool isSnappyCompressed(const std::string &filename); -public: - File(const std::string &filename = std::string(), - File::Mode mode = File::Read); - virtual ~File(); - - bool isOpened() const; - File::Mode mode() const; - - bool open(const std::string &filename, File::Mode mode); - bool write(const void *buffer, size_t length); - bool read(void *buffer, size_t length); - void close(); - void flush(void); - int getc(); - bool skip(size_t length); - int percentRead(); - - virtual bool supportsOffsets() const = 0; - virtual File::Offset currentOffset() = 0; - virtual void setCurrentOffset(const File::Offset &offset); -protected: - virtual bool rawOpen(const std::string &filename, File::Mode mode) = 0; - virtual bool rawWrite(const void *buffer, size_t length) = 0; - virtual bool rawRead(void *buffer, size_t length) = 0; - virtual int rawGetc() = 0; - virtual void rawClose() = 0; - virtual void rawFlush() = 0; - virtual bool rawSkip(size_t length) = 0; - virtual int rawPercentRead() = 0; - -protected: - File::Mode m_mode; - bool m_isOpened; -}; - -inline bool File::isOpened() const -{ - return m_isOpened; -} - -inline File::Mode File::mode() const -{ - return m_mode; -} - -inline bool File::open(const std::string &filename, File::Mode mode) -{ - if (m_isOpened) { - close(); - } - m_isOpened = rawOpen(filename, mode); - m_mode = mode; - - return m_isOpened; -} - -inline bool File::write(const void *buffer, size_t length) -{ - if (!m_isOpened || m_mode != File::Write) { - return false; - } - return rawWrite(buffer, length); -} - -inline bool File::read(void *buffer, size_t length) -{ - if (!m_isOpened || m_mode != File::Read) { - return false; - } - return rawRead(buffer, length); -} - -inline int File::percentRead() -{ - if (!m_isOpened || m_mode != File::Read) { - return 0; - } - return rawPercentRead(); -} - -inline void File::close() -{ - if (m_isOpened) { - rawClose(); - m_isOpened = false; - } -} - -inline void File::flush(void) -{ - if (m_mode == File::Write) { - rawFlush(); - } -} - -inline int File::getc() -{ - if (!m_isOpened || m_mode != File::Read) { - return -1; - } - return rawGetc(); -} - -inline bool File::skip(size_t length) -{ - if (!m_isOpened || m_mode != File::Read) { - return false; - } - return rawSkip(length); -} - -class ZLibFile : public File { -public: - ZLibFile(const std::string &filename = std::string(), - File::Mode mode = File::Read); - virtual ~ZLibFile(); - - - virtual bool supportsOffsets() const; - virtual File::Offset currentOffset(); -protected: - virtual bool rawOpen(const std::string &filename, File::Mode mode); - virtual bool rawWrite(const void *buffer, size_t length); - virtual bool rawRead(void *buffer, size_t length); - virtual int rawGetc(); - virtual void rawClose(); - virtual void rawFlush(); - virtual bool rawSkip(size_t length); - virtual int rawPercentRead(); -private: - void *m_gzFile; - double m_endOffset; -}; - -inline bool -operator<(const File::Offset &one, const File::Offset &two) -{ - return one.chunk < two.chunk || - (one.chunk == two.chunk && one.offsetInChunk < two.offsetInChunk); -} - -inline bool -operator==(const File::Offset &one, const File::Offset &two) -{ - return one.chunk == two.chunk && - one.offsetInChunk == two.offsetInChunk; -} - -inline bool -operator>=(const File::Offset &one, const File::Offset &two) -{ - return one.chunk > two.chunk || - (one.chunk == two.chunk && one.offsetInChunk >= two.offsetInChunk); -} - -inline bool -operator>(const File::Offset &one, const File::Offset &two) -{ - return two < one; -} - -inline bool -operator<=(const File::Offset &one, const File::Offset &two) -{ - return two >= one; -} - - -} - -#endif diff --git a/trace_format.hpp b/trace_format.hpp deleted file mode 100644 index a8ee5eb..0000000 --- a/trace_format.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/************************************************************************** - * - * 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. - * - **************************************************************************/ - -/* - * Trace binary format. - * - * Grammar: - * - * trace = event* EOF - * - * event = EVENT_ENTER call_sig call_detail+ - * | EVENT_LEAVE call_no call_detail+ - * - * call_sig = sig_id ( name arg_names )? - * - * call_detail = ARG index value - * | RET value - * | END - * - * value = NULL - * | FALSE - * | TRUE - * | SINT int - * | UINT int - * | FLOAT float - * | DOUBLE double - * | STRING string - * | BLOB string - * | ENUM enum_sig - * | BITMASK bitmask_sig value - * | ARRAY length value+ - * | STRUCT struct_sig value+ - * | OPAQUE int - * - * call_sig = id name arg_name* - * | id - * - * enum_sig = id name value - * | id - * - * bitmask_sig = id count (name value)+ - * | id - * - * string = length (BYTE)* - * - */ - -#ifndef _TRACE_FORMAT_HPP_ -#define _TRACE_FORMAT_HPP_ - -namespace Trace { - -#define TRACE_VERSION 1 - -enum Event { - EVENT_ENTER = 0, - EVENT_LEAVE, -}; - -enum CallDetail { - CALL_END = 0, - CALL_ARG, - CALL_RET, - CALL_THREAD, -}; - -enum Type { - TYPE_NULL = 0, - TYPE_FALSE, - TYPE_TRUE, - TYPE_SINT, - TYPE_UINT, - TYPE_FLOAT, - TYPE_DOUBLE, - TYPE_STRING, // Null terminated, human readible string - TYPE_BLOB, // Block of bytes - TYPE_ENUM, - TYPE_BITMASK, - TYPE_ARRAY, - TYPE_STRUCT, - TYPE_OPAQUE, -}; - - -} /* namespace Trace */ - -#endif /* _TRACE_FORMAT_HPP_ */ diff --git a/trace_loader.cpp b/trace_loader.cpp deleted file mode 100644 index c14d815..0000000 --- a/trace_loader.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "trace_loader.hpp" - - -using namespace Trace; - -Loader::Loader() - : m_frameMarker(FrameMarker_SwapBuffers) -{ -} - -Loader::~Loader() -{ - close(); -} - -Loader::FrameMarker Loader::frameMarker() const -{ - return m_frameMarker; -} - -void Loader::setFrameMarker(Loader::FrameMarker marker) -{ - m_frameMarker = marker; -} - -int Loader::numberOfFrames() const -{ - return m_frameBookmarks.size(); -} - -int Loader::numberOfCallsInFrame(int frameIdx) const -{ - if (frameIdx > m_frameBookmarks.size()) { - return 0; - } - FrameBookmarks::const_iterator itr = - m_frameBookmarks.find(frameIdx); - return itr->second.numberOfCalls; -} - -bool Loader::open(const char *filename) -{ - if (!m_parser.open(filename)) { - std::cerr << "error: failed to open " << filename << "\n"; - return false; - } - if (!m_parser.supportsOffsets()) { - std::cerr << "error: " <= 5) { - std::cerr << "\tPercent scanned = " - << m_parser.percentRead() - << "..."<dump(std::cout, color); - delete call; - } - return true; -} - -void Loader::close() -{ - m_parser.close(); -} - -bool Loader::isCallAFrameMarker(const Trace::Call *call) const -{ - std::string name = call->name(); - - switch (m_frameMarker) { - case FrameMarker_SwapBuffers: - return name.find("SwapBuffers") != std::string::npos || - name == "CGLFlushDrawable" || - name == "glFrameTerminatorGREMEDY"; - break; - case FrameMarker_Flush: - return name == "glFlush"; - break; - case FrameMarker_Finish: - return name == "glFinish"; - break; - case FrameMarker_Clear: - return name == "glClear"; - break; - } - return false; -} - -std::vector Loader::frame(int idx) -{ - int numOfCalls = numberOfCallsInFrame(idx); - if (numOfCalls) { - const FrameBookmark &frameBookmark = m_frameBookmarks[idx]; - std::vector calls(numOfCalls); - m_parser.setBookmark(frameBookmark.start); - - Trace::Call *call; - int parsedCalls = 0; - while ((call = m_parser.parse_call())) { - - calls[parsedCalls] = call; - ++parsedCalls; - - if (isCallAFrameMarker(call)) { - break; - } - - } - assert(parsedCalls == numOfCalls); - return calls; - } - return std::vector(); -} diff --git a/trace_loader.hpp b/trace_loader.hpp deleted file mode 100644 index 9f74a9b..0000000 --- a/trace_loader.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef TRACE_LOADER_HPP -#define TRACE_LOADER_HPP - -#include "trace_file.hpp" -#include "trace_parser.hpp" - -#include -#include -#include -#include - -namespace Trace { - -class Frame; - -class Loader -{ -public: - enum FrameMarker { - FrameMarker_SwapBuffers, - FrameMarker_Flush, - FrameMarker_Finish, - FrameMarker_Clear - }; -public: - Loader(); - ~Loader(); - - Loader::FrameMarker frameMarker() const; - void setFrameMarker(Loader::FrameMarker marker); - - int numberOfFrames() const; - int numberOfCallsInFrame(int frameIdx) const; - - bool open(const char *filename); - void close(); - - std::vector frame(int idx); - -private: - struct FrameBookmark { - FrameBookmark() - : numberOfCalls(0) - {} - FrameBookmark(const ParseBookmark &s) - : start(s), - numberOfCalls(0) - {} - - ParseBookmark start; - int numberOfCalls; - }; - bool isCallAFrameMarker(const Trace::Call *call) const; - -private: - Trace::Parser m_parser; - FrameMarker m_frameMarker; - - typedef std::map FrameBookmarks; - FrameBookmarks m_frameBookmarks; -}; - -} - -#endif // TRACE_LOADER_HPP diff --git a/trace_local_writer.cpp b/trace_local_writer.cpp deleted file mode 100644 index ea6c111..0000000 --- a/trace_local_writer.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/************************************************************************** - * - * Copyright 2007-2011 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 -#include -#include -#include -#include - -#include "os.hpp" -#include "trace_file.hpp" -#include "trace_writer.hpp" -#include "trace_format.hpp" - - -namespace Trace { - - -static void exceptionCallback(void) -{ - OS::DebugMessage("apitrace: flushing trace due to an exception\n"); - localWriter.flush(); -} - - -LocalWriter::LocalWriter() : - acquired(0) -{} - -LocalWriter::~LocalWriter() -{ - OS::ResetExceptionCallback(); -} - -void -LocalWriter::open(void) { - - static unsigned dwCounter = 0; - - const char *szExtension = "trace"; - char szFileName[PATH_MAX]; - const char *lpFileName; - - lpFileName = getenv("TRACE_FILE"); - if (lpFileName) { - strncpy(szFileName, lpFileName, PATH_MAX); - } - else { - char szProcessName[PATH_MAX]; - char szCurrentDir[PATH_MAX]; - OS::GetProcessName(szProcessName, PATH_MAX); - OS::GetCurrentDir(szCurrentDir, PATH_MAX); - - for (;;) { - FILE *file; - - if (dwCounter) - snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension); - else - snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension); - - file = fopen(szFileName, "rb"); - if (file == NULL) - break; - - fclose(file); - - ++dwCounter; - } - } - - OS::DebugMessage("apitrace: tracing to %s\n", szFileName); - - Writer::open(szFileName); - - OS::SetExceptionCallback(exceptionCallback); - -#if 0 - // For debugging the exception handler - *((int *)0) = 0; -#endif -} - -unsigned LocalWriter::beginEnter(const FunctionSig *sig) { - OS::AcquireMutex(); - ++acquired; - - if (!m_file->isOpened()) { - open(); - } - - return Writer::beginEnter(sig); -} - -void LocalWriter::endEnter(void) { - Writer::endEnter(); - --acquired; - OS::ReleaseMutex(); -} - -void LocalWriter::beginLeave(unsigned call) { - OS::AcquireMutex(); - ++acquired; - Writer::beginLeave(call); -} - -void LocalWriter::endLeave(void) { - Writer::endLeave(); - --acquired; - OS::ReleaseMutex(); -} - -void LocalWriter::flush(void) { - /* - * Do nothing if the mutex is already acquired (e.g., if a segfault happen - * while writing the file) to prevent dead-lock. - */ - - if (!acquired) { - OS::AcquireMutex(); - if (m_file->isOpened()) { - m_file->flush(); - } - OS::ReleaseMutex(); - } -} - - -LocalWriter localWriter; - - -} /* namespace Trace */ - diff --git a/trace_model.cpp b/trace_model.cpp deleted file mode 100644 index 306b9e7..0000000 --- a/trace_model.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/************************************************************************** - * - * 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 "formatter.hpp" -#include "trace_model.hpp" - - -namespace Trace { - - -Call::~Call() { - for (unsigned i = 0; i < args.size(); ++i) { - delete args[i]; - } - - if (ret) { - delete ret; - } -} - - -String::~String() { - delete [] value; -} - - -Struct::~Struct() { - for (std::vector::iterator it = members.begin(); it != members.end(); ++it) { - delete *it; - } -} - - -Array::~Array() { - for (std::vector::iterator it = values.begin(); it != values.end(); ++it) { - delete *it; - } -} - -Blob::~Blob() { - // Blobs are often bound and referred during many calls, so we can't delete - // them here in that case. - // - // Once bound there is no way to know when they were unbound, which - // effectively means we have to leak them. A better solution would be to - // keep a list of bound pointers, and defer the destruction to when the - // trace in question has been fully processed. - if (!bound) { - delete [] buf; - } -} - - -// bool cast -bool Null ::toBool(void) const { return false; } -bool Bool ::toBool(void) const { return value; } -bool SInt ::toBool(void) const { return value != 0; } -bool UInt ::toBool(void) const { return value != 0; } -bool Float ::toBool(void) const { return value != 0; } -bool String ::toBool(void) const { return true; } -bool Enum ::toBool(void) const { return sig->value != 0; } -bool Struct ::toBool(void) const { return true; } -bool Array ::toBool(void) const { return true; } -bool Blob ::toBool(void) const { return true; } -bool Pointer::toBool(void) const { return value != 0; } - - -// signed integer cast -signed long long Value ::toSInt(void) const { assert(0); return 0; } -signed long long Null ::toSInt(void) const { return 0; } -signed long long Bool ::toSInt(void) const { return static_cast(value); } -signed long long SInt ::toSInt(void) const { return value; } -signed long long UInt ::toSInt(void) const { assert(static_cast(value) >= 0); return static_cast(value); } -signed long long Float ::toSInt(void) const { return static_cast(value); } -signed long long Enum ::toSInt(void) const { return sig->value; } - - -// unsigned integer cast -unsigned long long Value ::toUInt(void) const { assert(0); return 0; } -unsigned long long Null ::toUInt(void) const { return 0; } -unsigned long long Bool ::toUInt(void) const { return static_cast(value); } -unsigned long long SInt ::toUInt(void) const { assert(value >= 0); return static_cast(value); } -unsigned long long UInt ::toUInt(void) const { return value; } -unsigned long long Float ::toUInt(void) const { return static_cast(value); } -unsigned long long Enum ::toUInt(void) const { assert(sig->value >= 0); return sig->value; } - - -// floating point cast -float Value ::toFloat(void) const { assert(0); return 0; } -float Null ::toFloat(void) const { return 0; } -float Bool ::toFloat(void) const { return static_cast(value); } -float SInt ::toFloat(void) const { return static_cast(value); } -float UInt ::toFloat(void) const { return static_cast(value); } -float Float ::toFloat(void) const { return value; } -float Enum ::toFloat(void) const { return static_cast(sig->value); } - - -// floating point cast -double Value ::toDouble(void) const { assert(0); return 0; } -double Null ::toDouble(void) const { return 0; } -double Bool ::toDouble(void) const { return static_cast(value); } -double SInt ::toDouble(void) const { return static_cast(value); } -double UInt ::toDouble(void) const { return static_cast(value); } -double Float ::toDouble(void) const { return value; } -double Enum ::toDouble(void) const { return static_cast(sig->value); } - - -// pointer cast -void * Value ::toPointer(void) const { assert(0); return NULL; } -void * Null ::toPointer(void) const { return NULL; } -void * Blob ::toPointer(void) const { return buf; } -void * Pointer::toPointer(void) const { return (void *)value; } - -void * Value ::toPointer(bool bind) { assert(0); return NULL; } -void * Null ::toPointer(bool bind) { return NULL; } -void * Blob ::toPointer(bool bind) { if (bind) bound = true; return buf; } -void * Pointer::toPointer(bool bind) { return (void *)value; } - - -// pointer cast -unsigned long long Value ::toUIntPtr(void) const { assert(0); return 0; } -unsigned long long Null ::toUIntPtr(void) const { return 0; } -unsigned long long Pointer::toUIntPtr(void) const { return value; } - - -// string cast -const char * Value ::toString(void) const { assert(0); return NULL; } -const char * Null ::toString(void) const { return NULL; } -const char * String::toString(void) const { return value; } - - -// virtual Value::visit() -void Null ::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 Enum ::visit(Visitor &visitor) { visitor.visit(this); } -void Bitmask::visit(Visitor &visitor) { visitor.visit(this); } -void Struct ::visit(Visitor &visitor) { visitor.visit(this); } -void Array ::visit(Visitor &visitor) { visitor.visit(this); } -void Blob ::visit(Visitor &visitor) { visitor.visit(this); } -void Pointer::visit(Visitor &visitor) { visitor.visit(this); } - - -void Visitor::visit(Null *) { assert(0); } -void Visitor::visit(Bool *) { assert(0); } -void Visitor::visit(SInt *) { assert(0); } -void Visitor::visit(UInt *) { assert(0); } -void Visitor::visit(Float *) { assert(0); } -void Visitor::visit(String *) { assert(0); } -void Visitor::visit(Enum *node) { assert(0); } -void Visitor::visit(Bitmask *node) { visit(static_cast(node)); } -void Visitor::visit(Struct *) { assert(0); } -void Visitor::visit(Array *) { assert(0); } -void Visitor::visit(Blob *) { assert(0); } -void Visitor::visit(Pointer *) { assert(0); } - - -class Dumper : public Visitor -{ -protected: - std::ostream &os; - Formatter::Formatter *formatter; - Formatter::Attribute *normal; - Formatter::Attribute *bold; - Formatter::Attribute *italic; - Formatter::Attribute *red; - Formatter::Attribute *pointer; - Formatter::Attribute *literal; - -public: - Dumper(std::ostream &_os, bool color) : os(_os) { - formatter = Formatter::defaultFormatter(color); - normal = formatter->normal(); - bold = formatter->bold(); - italic = formatter->italic(); - red = formatter->color(Formatter::RED); - pointer = formatter->color(Formatter::GREEN); - literal = formatter->color(Formatter::BLUE); - } - - ~Dumper() { - delete normal; - delete bold; - delete italic; - delete red; - delete pointer; - delete literal; - delete formatter; - } - - void visit(Null *) { - os << "NULL"; - } - - void visit(Bool *node) { - os << literal << (node->value ? "true" : "false") << normal; - } - - void visit(SInt *node) { - os << literal << node->value << normal; - } - - void visit(UInt *node) { - os << literal << node->value << normal; - } - - void visit(Float *node) { - os << literal << node->value << normal; - } - - void visit(String *node) { - os << literal << "\""; - for (const char *it = node->value; *it; ++it) { - unsigned char c = (unsigned char) *it; - if (c == '\"') - os << "\\\""; - else if (c == '\\') - os << "\\\\"; - else if (c >= 0x20 && c <= 0x7e) - os << c; - else if (c == '\t') { - os << "\t"; - } else if (c == '\r') { - // Ignore carriage-return - } else if (c == '\n') { - // Reset formatting so that it looks correct with 'less -R' - os << normal << '\n' << literal; - } else { - unsigned octal0 = c & 0x7; - unsigned octal1 = (c >> 3) & 0x7; - unsigned octal2 = (c >> 3) & 0x7; - os << "\\"; - if (octal2) - os << octal2; - if (octal1) - os << octal1; - os << octal0; - } - } - os << "\"" << normal; - } - - void visit(Enum *node) { - os << literal << node->sig->name << normal; - } - - void visit(Bitmask *bitmask) { - unsigned long long value = bitmask->value; - const BitmaskSig *sig = bitmask->sig; - bool first = true; - for (const BitmaskFlag *it = sig->flags; value != 0 && it != sig->flags + sig->num_flags; ++it) { - if ((it->value && (value & it->value) == it->value) || - (!it->value && value == 0)) { - if (!first) { - os << " | "; - } - os << literal << it->name << normal; - value &= ~it->value; - first = false; - } - } - if (value || first) { - if (!first) { - os << " | "; - } - os << literal << "0x" << std::hex << value << std::dec << normal; - } - } - - void visit(Struct *s) { - const char *sep = ""; - os << "{"; - for (unsigned i = 0; i < s->members.size(); ++i) { - os << sep << italic << s->sig->member_names[i] << normal << " = "; - _visit(s->members[i]); - sep = ", "; - } - os << "}"; - } - - void visit(Array *array) { - if (array->values.size() == 1) { - os << "&"; - _visit(array->values[0]); - } - else { - const char *sep = ""; - os << "{"; - for (std::vector::iterator it = array->values.begin(); it != array->values.end(); ++it) { - os << sep; - _visit(*it); - sep = ", "; - } - os << "}"; - } - } - - void visit(Blob *blob) { - os << pointer << "blob(" << blob->size << ")" << normal; - } - - void visit(Pointer *p) { - os << pointer << "0x" << std::hex << p->value << std::dec << normal; - } - - void visit(Call *call) { - const char *sep = ""; - os << bold << call->sig->name << normal << "("; - for (unsigned i = 0; i < call->args.size(); ++i) { - os << sep << italic << call->sig->arg_names[i] << normal << " = "; - if (call->args[i]) { - _visit(call->args[i]); - } else { - os << "?"; - } - sep = ", "; - } - os << ")"; - if (call->ret) { - os << " = "; - _visit(call->ret); - } - os << "\n"; - } -}; - - -void Value::dump(std::ostream &os, bool color) { - Dumper d(os, color); - visit(d); -} - - -static Null null; - -const Value & Value::operator[](size_t index) const { - const Array *array = dynamic_cast(this); - if (array) { - if (index < array->values.size()) { - return *array->values[index]; - } - } - return null; -} - -void Call::dump(std::ostream &os, bool color) { - Dumper d(os, color); - os << no << " "; - d.visit(this); -} - - -} /* namespace Trace */ diff --git a/trace_model.hpp b/trace_model.hpp deleted file mode 100644 index a74508e..0000000 --- a/trace_model.hpp +++ /dev/null @@ -1,357 +0,0 @@ -/************************************************************************** - * - * 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. - * - **************************************************************************/ - -/* - * Object hierarchy for describing the traces in memory. - */ - -#ifndef _TRACE_MODEL_HPP_ -#define _TRACE_MODEL_HPP_ - - -#include - -#include -#include -#include - - -namespace Trace { - - -typedef unsigned Id; - - -struct FunctionSig { - Id id; - const char *name; - unsigned num_args; - const char **arg_names; -}; - - -struct StructSig { - Id id; - const char *name; - unsigned num_members; - const char **member_names; -}; - - -struct EnumSig { - Id id; - const char *name; - signed long long value; -}; - - -struct BitmaskFlag { - const char *name; - unsigned long long value; -}; - - -struct BitmaskSig { - Id id; - unsigned num_flags; - const BitmaskFlag *flags; -}; - - -class Visitor; - - -class Value -{ -public: - virtual ~Value() {} - virtual void visit(Visitor &visitor) = 0; - - virtual bool toBool(void) const = 0; - virtual signed long long toSInt(void) const; - virtual unsigned long long toUInt(void) const; - virtual float toFloat(void) const; - virtual double toDouble(void) const; - - virtual void *toPointer(void) const; - virtual void *toPointer(bool bind); - virtual unsigned long long toUIntPtr(void) const; - virtual const char *toString(void) const; - - const Value & operator[](size_t index) const; - - void dump(std::ostream &os, bool color=true); -}; - - -class Null : public Value -{ -public: - bool toBool(void) const; - signed long long toSInt(void) const; - unsigned long long toUInt(void) const; - virtual float toFloat(void) const; - virtual double toDouble(void) const; - void *toPointer(void) const; - void *toPointer(bool bind); - unsigned long long toUIntPtr(void) const; - const char *toString(void) const; - void visit(Visitor &visitor); -}; - - -class Bool : public Value -{ -public: - Bool(bool _value) : value(_value) {} - - bool toBool(void) const; - signed long long toSInt(void) const; - unsigned long long toUInt(void) const; - virtual float toFloat(void) const; - virtual double toDouble(void) const; - void visit(Visitor &visitor); - - bool value; -}; - - -class SInt : public Value -{ -public: - SInt(signed long long _value) : value(_value) {} - - bool toBool(void) const; - signed long long toSInt(void) const; - unsigned long long toUInt(void) const; - virtual float toFloat(void) const; - virtual double toDouble(void) const; - void visit(Visitor &visitor); - - signed long long value; -}; - - -class UInt : public Value -{ -public: - UInt(unsigned long long _value) : value(_value) {} - - bool toBool(void) const; - signed long long toSInt(void) const; - unsigned long long toUInt(void) const; - virtual float toFloat(void) const; - virtual double toDouble(void) const; - void visit(Visitor &visitor); - - unsigned long long value; -}; - - -class Float : public Value -{ -public: - Float(double _value) : value(_value) {} - - bool toBool(void) const; - signed long long toSInt(void) const; - unsigned long long toUInt(void) const; - virtual float toFloat(void) const; - virtual double toDouble(void) const; - void visit(Visitor &visitor); - - double value; -}; - - -class String : public Value -{ -public: - String(const char * _value) : value(_value) {} - ~String(); - - bool toBool(void) const; - const char *toString(void) const; - void visit(Visitor &visitor); - - const char * value; -}; - - -class Enum : public Value -{ -public: - Enum(const EnumSig *_sig) : sig(_sig) {} - - bool toBool(void) const; - signed long long toSInt(void) const; - unsigned long long toUInt(void) const; - virtual float toFloat(void) const; - virtual double toDouble(void) const; - void visit(Visitor &visitor); - - const EnumSig *sig; -}; - - -class Bitmask : public UInt -{ -public: - Bitmask(const BitmaskSig *_sig, unsigned long long _value) : UInt(_value), sig(_sig) {} - - void visit(Visitor &visitor); - - const BitmaskSig *sig; -}; - - -class Struct : public Value -{ -public: - Struct(StructSig *_sig) : sig(_sig), members(_sig->num_members) { } - ~Struct(); - - bool toBool(void) const; - void visit(Visitor &visitor); - - const StructSig *sig; - std::vector members; -}; - - -class Array : public Value -{ -public: - Array(size_t len) : values(len) {} - ~Array(); - - bool toBool(void) const; - void visit(Visitor &visitor); - - std::vector values; -}; - - -class Blob : public Value -{ -public: - Blob(size_t _size) { - size = _size; - buf = new char[_size]; - bound = false; - } - - ~Blob(); - - bool toBool(void) const; - void *toPointer(void) const; - void *toPointer(bool bind); - void visit(Visitor &visitor); - - size_t size; - char *buf; - bool bound; -}; - - -class Pointer : public UInt -{ -public: - Pointer(unsigned long long value) : UInt(value) {} - - bool toBool(void) const; - void *toPointer(void) const; - void *toPointer(bool bind); - unsigned long long toUIntPtr(void) const; - void visit(Visitor &visitor); -}; - - -class Visitor -{ -public: - virtual void visit(Null *); - virtual void visit(Bool *); - virtual void visit(SInt *); - virtual void visit(UInt *); - virtual void visit(Float *); - virtual void visit(String *); - virtual void visit(Enum *); - virtual void visit(Bitmask *); - virtual void visit(Struct *); - virtual void visit(Array *); - virtual void visit(Blob *); - virtual void visit(Pointer *); - -protected: - inline void _visit(Value *value) { - if (value) { - value->visit(*this); - } - } -}; - - -inline std::ostream & operator <<(std::ostream &os, Value *value) { - if (value) { - value->dump(os); - } - return os; -} - - -class Call -{ -public: - unsigned no; - const FunctionSig *sig; - std::vector args; - Value *ret; - - Call(FunctionSig *_sig) : sig(_sig), args(_sig->num_args), ret(0) { } - ~Call(); - - inline const char * name(void) const { - return sig->name; - } - - inline Value & arg(unsigned index) { - assert(index < args.size()); - return *(args[index]); - } - - void dump(std::ostream &os, bool color=true); -}; - - -inline std::ostream & operator <<(std::ostream &os, Call &call) { - call.dump(os); - return os; -} - - -} /* namespace Trace */ - -#endif /* _TRACE_MODEL_HPP_ */ diff --git a/trace_model_writer.cpp b/trace_model_writer.cpp deleted file mode 100644 index dcfcf86..0000000 --- a/trace_model_writer.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Jose Fonseca - * 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_writer.hpp" - - -namespace Trace { - - -class ModelWriter : public Visitor -{ -protected: - Writer &writer; - -public: - ModelWriter(Writer &_writer) : - writer(_writer) { - } - - void visit(Null *) { - writer.writeNull(); - } - - void visit(Bool *node) { - writer.writeBool(node->value); - } - - void visit(SInt *node) { - writer.writeSInt(node->value); - } - - void visit(UInt *node) { - writer.writeUInt(node->value); - } - - void visit(Float *node) { - writer.writeFloat(node->value); - } - - void visit(String *node) { - writer.writeString(node->value); - } - - void visit(Enum *node) { - writer.writeEnum(node->sig); - } - - void visit(Bitmask *node) { - writer.writeBitmask(node->sig, node->value); - } - - void visit(Struct *node) { - writer.beginStruct(node->sig); - for (unsigned i = 0; i < node->sig->num_members; ++i) { - _visit(node->members[i]); - } - writer.endStruct(); - } - - void visit(Array *node) { - writer.beginArray(node->values.size()); - for (std::vector::iterator it = node->values.begin(); it != node->values.end(); ++it) { - _visit(*it); - } - writer.endArray(); - } - - void visit(Blob *node) { - writer.writeBlob(node->buf, node->size); - } - - void visit(Pointer *node) { - writer.writeOpaque((const void *) (size_t) node->value); - } - - void visit(Call *call) { - unsigned call_no = writer.beginEnter(call->sig); - for (unsigned i = 0; i < call->args.size(); ++i) { - if (call->args[i]) { - writer.beginArg(i); - _visit(call->args[i]); - writer.endArg(); - } - } - writer.endEnter(); - writer.beginLeave(call_no); - if (call->ret) { - writer.beginReturn(); - _visit(call->ret); - writer.endReturn(); - } - writer.endLeave(); - } -}; - - -void Writer::writeCall(Call *call) { - ModelWriter visitor(*this); - visitor.visit(call); -} - - -} /* namespace Trace */ - diff --git a/trace_parser.cpp b/trace_parser.cpp deleted file mode 100644 index d7b20d2..0000000 --- a/trace_parser.cpp +++ /dev/null @@ -1,731 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Jose Fonseca - * 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 -#include - -#include "trace_file.hpp" -#include "trace_snappyfile.hpp" -#include "trace_parser.hpp" - - -#define TRACE_VERBOSE 0 - - -namespace Trace { - - -Parser::Parser() { - file = NULL; - next_call_no = 0; - version = 0; -} - - -Parser::~Parser() { - close(); -} - - -bool Parser::open(const char *filename) { - assert(!file); - if (File::isZLibCompressed(filename)) { - file = new ZLibFile; - } else { - file = new SnappyFile; - } - - if (!file->open(filename, File::Read)) { - return false; - } - - version = read_uint(); - if (version > TRACE_VERSION) { - std::cerr << "error: unsupported trace format version " << version << "\n"; - return false; - } - - return true; -} - -template -inline void -deleteAll(Iter begin, Iter end) -{ - while (begin != end) { - delete *begin; - ++begin; - } -} - -template -inline void -deleteAll(Container &c) -{ - deleteAll(c.begin(), c.end()); - c.clear(); -} - -void Parser::close(void) { - if (file) { - file->close(); - delete file; - file = NULL; - } - - deleteAll(calls); - - // Delete all signature data. Signatures are mere structures which don't - // own their own memory, so we need to destroy all data we created here. - - for (FunctionMap::iterator it = functions.begin(); it != functions.end(); ++it) { - FunctionSigState *sig = *it; - if (sig) { - delete [] sig->name; - for (unsigned arg = 0; arg < sig->num_args; ++arg) { - delete [] sig->arg_names[arg]; - } - delete [] sig->arg_names; - delete sig; - } - } - functions.clear(); - - for (StructMap::iterator it = structs.begin(); it != structs.end(); ++it) { - StructSigState *sig = *it; - if (sig) { - delete [] sig->name; - for (unsigned member = 0; member < sig->num_members; ++member) { - delete [] sig->member_names[member]; - } - delete [] sig->member_names; - delete sig; - } - } - structs.clear(); - - for (EnumMap::iterator it = enums.begin(); it != enums.end(); ++it) { - EnumSigState *sig = *it; - if (sig) { - delete [] sig->name; - delete sig; - } - } - enums.clear(); - - for (BitmaskMap::iterator it = bitmasks.begin(); it != bitmasks.end(); ++it) { - BitmaskSigState *sig = *it; - if (sig) { - for (unsigned flag = 0; flag < sig->num_flags; ++flag) { - delete [] sig->flags[flag].name; - } - delete [] sig->flags; - delete sig; - } - } - bitmasks.clear(); -} - - -void Parser::getBookmark(ParseBookmark &bookmark) { - bookmark.offset = file->currentOffset(); - bookmark.next_call_no = next_call_no; -} - - -void Parser::setBookmark(const ParseBookmark &bookmark) { - file->setCurrentOffset(bookmark.offset); - next_call_no = bookmark.next_call_no; - - // Simply ignore all pending calls - deleteAll(calls); -} - - -Call *Parser::parse_call(Mode mode) { - do { - int c = read_byte(); - switch(c) { - case Trace::EVENT_ENTER: - parse_enter(mode); - break; - case Trace::EVENT_LEAVE: - return parse_leave(mode); - default: - std::cerr << "error: unknown event " << c << "\n"; - exit(1); - case -1: - for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) { - std::cerr << "warning: incomplete call " << (*it)->name() << "\n"; - std::cerr << **it << "\n"; - } - return NULL; - } - } while(true); -} - - -/** - * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit. - */ -template -T *lookup(std::vector &map, size_t index) { - if (index >= map.size()) { - map.resize(index + 1); - return NULL; - } else { - return map[index]; - } -} - - -FunctionSig *Parser::parse_function_sig(void) { - size_t id = read_uint(); - - FunctionSigState *sig = lookup(functions, id); - - if (!sig) { - /* parse the signature */ - sig = new FunctionSigState; - sig->id = id; - sig->name = read_string(); - sig->num_args = read_uint(); - const char **arg_names = new const char *[sig->num_args]; - for (unsigned i = 0; i < sig->num_args; ++i) { - arg_names[i] = read_string(); - } - sig->arg_names = arg_names; - sig->offset = file->currentOffset(); - functions[id] = sig; - } else if (file->currentOffset() < sig->offset) { - /* skip over the signature */ - skip_string(); /* name */ - int num_args = read_uint(); - for (unsigned i = 0; i < num_args; ++i) { - skip_string(); /*arg_name*/ - } - } - - assert(sig); - return sig; -} - - -StructSig *Parser::parse_struct_sig() { - size_t id = read_uint(); - - StructSigState *sig = lookup(structs, id); - - if (!sig) { - /* parse the signature */ - sig = new StructSigState; - sig->id = id; - sig->name = read_string(); - sig->num_members = read_uint(); - const char **member_names = new const char *[sig->num_members]; - for (unsigned i = 0; i < sig->num_members; ++i) { - member_names[i] = read_string(); - } - sig->member_names = member_names; - sig->offset = file->currentOffset(); - structs[id] = sig; - } else if (file->currentOffset() < sig->offset) { - /* skip over the signature */ - skip_string(); /* name */ - unsigned num_members = read_uint(); - for (unsigned i = 0; i < num_members; ++i) { - skip_string(); /* member_name */ - } - } - - assert(sig); - return sig; -} - - -EnumSig *Parser::parse_enum_sig() { - size_t id = read_uint(); - - EnumSigState *sig = lookup(enums, id); - - if (!sig) { - /* parse the signature */ - sig = new EnumSigState; - sig->id = id; - sig->name = read_string(); - Value *value = parse_value(); - sig->value = value->toSInt(); - delete value; - sig->offset = file->currentOffset(); - enums[id] = sig; - } else if (file->currentOffset() < sig->offset) { - /* skip over the signature */ - skip_string(); /*name*/ - scan_value(); - } - - assert(sig); - return sig; -} - - -BitmaskSig *Parser::parse_bitmask_sig() { - size_t id = read_uint(); - - BitmaskSigState *sig = lookup(bitmasks, id); - - if (!sig) { - /* parse the signature */ - sig = new BitmaskSigState; - sig->id = id; - sig->num_flags = read_uint(); - BitmaskFlag *flags = new BitmaskFlag[sig->num_flags]; - for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) { - it->name = read_string(); - it->value = read_uint(); - if (it->value == 0 && it != flags) { - std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n"; - } - } - sig->flags = flags; - sig->offset = file->currentOffset(); - bitmasks[id] = sig; - } else if (file->currentOffset() < sig->offset) { - /* skip over the signature */ - int num_flags = read_uint(); - for (int i = 0; i < num_flags; ++i) { - skip_string(); /*name */ - skip_uint(); /* value */ - } - } - - assert(sig); - return sig; -} - - -void Parser::parse_enter(Mode mode) { - FunctionSig *sig = parse_function_sig(); - - Call *call = new Call(sig); - - call->no = next_call_no++; - - if (parse_call_details(call, mode)) { - calls.push_back(call); - } else { - delete call; - } -} - - -Call *Parser::parse_leave(Mode mode) { - unsigned call_no = read_uint(); - Call *call = NULL; - for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) { - if ((*it)->no == call_no) { - call = *it; - calls.erase(it); - break; - } - } - if (!call) { - return NULL; - } - - if (parse_call_details(call, mode)) { - return call; - } else { - delete call; - return NULL; - } -} - - -bool Parser::parse_call_details(Call *call, Mode mode) { - do { - int c = read_byte(); - switch(c) { - case Trace::CALL_END: - return true; - case Trace::CALL_ARG: - parse_arg(call, mode); - break; - case Trace::CALL_RET: - call->ret = parse_value(mode); - break; - default: - std::cerr << "error: ("<name()<< ") unknown call detail " - << c << "\n"; - exit(1); - case -1: - return false; - } - } while(true); -} - - -void Parser::parse_arg(Call *call, Mode mode) { - unsigned index = read_uint(); - Value *value = parse_value(mode); - if (value) { - if (index >= call->args.size()) { - call->args.resize(index + 1); - } - call->args[index] = value; - } -} - - -Value *Parser::parse_value(void) { - int c; - Value *value; - c = read_byte(); - switch(c) { - case Trace::TYPE_NULL: - value = new Null; - break; - case Trace::TYPE_FALSE: - value = new Bool(false); - break; - case Trace::TYPE_TRUE: - value = new Bool(true); - break; - case Trace::TYPE_SINT: - value = parse_sint(); - break; - case Trace::TYPE_UINT: - value = parse_uint(); - break; - case Trace::TYPE_FLOAT: - value = parse_float(); - break; - case Trace::TYPE_DOUBLE: - value = parse_double(); - break; - case Trace::TYPE_STRING: - value = parse_string(); - break; - case Trace::TYPE_ENUM: - value = parse_enum(); - break; - case Trace::TYPE_BITMASK: - value = parse_bitmask(); - break; - case Trace::TYPE_ARRAY: - value = parse_array(); - break; - case Trace::TYPE_STRUCT: - value = parse_struct(); - break; - case Trace::TYPE_BLOB: - value = parse_blob(); - break; - case Trace::TYPE_OPAQUE: - value = parse_opaque(); - break; - default: - std::cerr << "error: unknown type " << c << "\n"; - exit(1); - case -1: - value = NULL; - break; - } -#if TRACE_VERBOSE - if (value) { - std::cerr << "\tVALUE " << value << "\n"; - } -#endif - return value; -} - - -void Parser::scan_value(void) { - int c = read_byte(); - switch(c) { - case Trace::TYPE_NULL: - case Trace::TYPE_FALSE: - case Trace::TYPE_TRUE: - break; - case Trace::TYPE_SINT: - scan_sint(); - break; - case Trace::TYPE_UINT: - scan_uint(); - break; - case Trace::TYPE_FLOAT: - scan_float(); - break; - case Trace::TYPE_DOUBLE: - scan_double(); - break; - case Trace::TYPE_STRING: - scan_string(); - break; - case Trace::TYPE_ENUM: - scan_enum(); - break; - case Trace::TYPE_BITMASK: - scan_bitmask(); - break; - case Trace::TYPE_ARRAY: - scan_array(); - break; - case Trace::TYPE_STRUCT: - scan_struct(); - break; - case Trace::TYPE_BLOB: - scan_blob(); - break; - case Trace::TYPE_OPAQUE: - scan_opaque(); - break; - default: - std::cerr << "error: unknown type " << c << "\n"; - exit(1); - case -1: - break; - } -} - - -Value *Parser::parse_sint() { - return new SInt(-(signed long long)read_uint()); -} - - -void Parser::scan_sint() { - skip_uint(); -} - - -Value *Parser::parse_uint() { - return new UInt(read_uint()); -} - - -void Parser::scan_uint() { - skip_uint(); -} - - -Value *Parser::parse_float() { - float value; - file->read(&value, sizeof value); - return new Float(value); -} - - -void Parser::scan_float() { - file->skip(sizeof(float)); -} - - -Value *Parser::parse_double() { - double value; - file->read(&value, sizeof value); - return new Float(value); -} - - -void Parser::scan_double() { - file->skip(sizeof(double)); -} - - -Value *Parser::parse_string() { - return new String(read_string()); -} - - -void Parser::scan_string() { - skip_string(); -} - - -Value *Parser::parse_enum() { - EnumSig *sig = parse_enum_sig(); - return new Enum(sig); -} - - -void Parser::scan_enum() { - parse_enum_sig(); -} - - -Value *Parser::parse_bitmask() { - BitmaskSig *sig = parse_bitmask_sig(); - - unsigned long long value = read_uint(); - - return new Bitmask(sig, value); -} - - -void Parser::scan_bitmask() { - parse_bitmask_sig(); - skip_uint(); /* value */ -} - - -Value *Parser::parse_array(void) { - 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; -} - - -void Parser::scan_array(void) { - size_t len = read_uint(); - for (size_t i = 0; i < len; ++i) { - scan_value(); - } -} - - -Value *Parser::parse_blob(void) { - size_t size = read_uint(); - Blob *blob = new Blob(size); - if (size) { - file->read(blob->buf, (unsigned)size); - } - return blob; -} - - -void Parser::scan_blob(void) { - size_t size = read_uint(); - if (size) { - file->skip(size); - } -} - - -Value *Parser::parse_struct() { - StructSig *sig = parse_struct_sig(); - Struct *value = new Struct(sig); - - for (size_t i = 0; i < sig->num_members; ++i) { - value->members[i] = parse_value(); - } - - return value; -} - - -void Parser::scan_struct() { - StructSig *sig = parse_struct_sig(); - for (size_t i = 0; i < sig->num_members; ++i) { - scan_value(); - } -} - - -Value *Parser::parse_opaque() { - unsigned long long addr; - addr = read_uint(); - return new Pointer(addr); -} - - -void Parser::scan_opaque() { - skip_uint(); -} - - -const char * Parser::read_string(void) { - size_t len = read_uint(); - char * value = new char[len + 1]; - if (len) { - file->read(value, (unsigned)len); - } - value[len] = 0; -#if TRACE_VERBOSE - std::cerr << "\tSTRING \"" << value << "\"\n"; -#endif - return value; -} - - -void Parser::skip_string(void) { - size_t len = read_uint(); - file->skip(len); -} - - -unsigned long long Parser::read_uint(void) { - unsigned long long value = 0; - int c; - unsigned shift = 0; - do { - c = file->getc(); - if (c == -1) { - break; - } - value |= (unsigned long long)(c & 0x7f) << shift; - shift += 7; - } while(c & 0x80); -#if TRACE_VERBOSE - std::cerr << "\tUINT " << value << "\n"; -#endif - return value; -} - - -void Parser::skip_uint(void) { - int c; - do { - c = file->getc(); - if (c == -1) { - break; - } - } while(c & 0x80); -} - - -inline int Parser::read_byte(void) { - int c = file->getc(); -#if TRACE_VERBOSE - if (c < 0) - std::cerr << "\tEOF" << "\n"; - else - std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n"; -#endif - return c; -} - - -inline void Parser::skip_byte(void) { - file->skip(1); -} - - -} /* namespace Trace */ diff --git a/trace_parser.hpp b/trace_parser.hpp deleted file mode 100644 index 3aaa6d3..0000000 --- a/trace_parser.hpp +++ /dev/null @@ -1,197 +0,0 @@ -/************************************************************************** - * - * 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 "trace_file.hpp" -#include "trace_format.hpp" -#include "trace_model.hpp" - - -namespace Trace { - - -struct ParseBookmark -{ - File::Offset offset; - unsigned next_call_no; -}; - - -class Parser -{ -protected: - File *file; - - enum Mode { - FULL = 0, - SCAN, - SKIP - }; - - typedef std::list CallList; - CallList calls; - - // Helper template that extends a base signature structure, with additional - // parsing information. - template< class T > - struct SigState : public T { - // Offset in the file of where signature was defined. It is used when - // reparsing to determine whether the signature definition is to be - // expected next or not. - File::Offset offset; - }; - - typedef SigState FunctionSigState; - typedef SigState StructSigState; - typedef SigState EnumSigState; - typedef SigState BitmaskSigState; - - typedef std::vector FunctionMap; - typedef std::vector StructMap; - typedef std::vector EnumMap; - typedef std::vector BitmaskMap; - - FunctionMap functions; - StructMap structs; - EnumMap enums; - BitmaskMap bitmasks; - - unsigned next_call_no; - -public: - unsigned long long version; - - Parser(); - - ~Parser(); - - bool open(const char *filename); - - void close(void); - - Call *parse_call(void) { - return parse_call(FULL); - } - - bool supportsOffsets() const - { - return file->supportsOffsets(); - } - - void getBookmark(ParseBookmark &bookmark); - - void setBookmark(const ParseBookmark &bookmark); - - int percentRead() - { - return file->percentRead(); - } - - Call *scan_call() { - return parse_call(SCAN); - } - -protected: - Call *parse_call(Mode mode); - - FunctionSig *parse_function_sig(void); - StructSig *parse_struct_sig(); - EnumSig *parse_enum_sig(); - BitmaskSig *parse_bitmask_sig(); - - Call *parse_Call(Mode mode); - - void parse_enter(Mode mode); - - Call *parse_leave(Mode mode); - - bool parse_call_details(Call *call, Mode mode); - - void parse_arg(Call *call, Mode mode); - - Value *parse_value(void); - void scan_value(void); - inline Value *parse_value(Mode mode) { - if (mode == FULL) { - return parse_value(); - } else { - scan_value(); - return NULL; - } - } - - Value *parse_sint(); - void scan_sint(); - - Value *parse_uint(); - void scan_uint(); - - Value *parse_float(); - void scan_float(); - - Value *parse_double(); - void scan_double(); - - Value *parse_string(); - void scan_string(); - - Value *parse_enum(); - void scan_enum(); - - Value *parse_bitmask(); - void scan_bitmask(); - - Value *parse_array(void); - void scan_array(void); - - Value *parse_blob(void); - void scan_blob(void); - - Value *parse_struct(); - void scan_struct(); - - Value *parse_opaque(); - void scan_opaque(); - - const char * read_string(void); - void skip_string(void); - - unsigned long long read_uint(void); - void skip_uint(void); - - inline int read_byte(void); - inline void skip_byte(void); -}; - - -} /* namespace Trace */ - -#endif /* _TRACE_PARSER_HPP_ */ diff --git a/trace_snappyfile.cpp b/trace_snappyfile.cpp deleted file mode 100644 index 4dbe42d..0000000 --- a/trace_snappyfile.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Zack Rusin - * 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_snappyfile.hpp" - -#include - -#include - -#include -#include - -using namespace Trace; - -/* - * Snappy file format. - * ------------------- - * - * Snappy at its core is just a compressoin algorithm so we're - * creating a new file format which uses snappy compression - * to hold the trace data. - * - * The file is composed of a number of chunks, they are: - * chunk { - * uint32 - specifying the length of the compressed data - * compressed data, in little endian - * } - * File can contain any number of such chunks. - * The default size of an uncompressed chunk is specified in - * SNAPPY_CHUNK_SIZE. - * - * Note: - * Currently the default size for a a to-be-compressed data is - * 1mb, meaning that the compressed data will be <= 1mb. - * The reason it's 1mb is because it seems - * to offer a pretty good compression/disk io speed ratio - * but that might change. - * - */ - -SnappyFile::SnappyFile(const std::string &filename, - File::Mode mode) - : File(), - m_cache(0), - m_cachePtr(0), - m_cacheSize(0) -{ - size_t maxCompressedLength = - snappy::MaxCompressedLength(SNAPPY_CHUNK_SIZE); - m_compressedCache = new char[maxCompressedLength]; -} - -SnappyFile::~SnappyFile() -{ - delete [] m_compressedCache; - delete [] m_cache; -} - -bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode) -{ - std::ios_base::openmode fmode = std::fstream::binary; - if (mode == File::Write) { - fmode |= (std::fstream::out | std::fstream::trunc); - createCache(SNAPPY_CHUNK_SIZE); - } else if (mode == File::Read) { - fmode |= std::fstream::in; - } - - m_stream.open(filename.c_str(), fmode); - - //read in the initial buffer if we're reading - if (m_stream.is_open() && mode == File::Read) { - m_stream.seekg(0, std::ios::end); - m_endPos = m_stream.tellg(); - m_stream.seekg(0, std::ios::beg); - - // read the snappy file identifier - unsigned char byte1, byte2; - m_stream >> byte1; - m_stream >> byte2; - assert(byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2); - - flushReadCache(); - } else if (m_stream.is_open() && mode == File::Write) { - // write the snappy file identifier - m_stream << SNAPPY_BYTE1; - m_stream << SNAPPY_BYTE2; - } - return m_stream.is_open(); -} - -bool SnappyFile::rawWrite(const void *buffer, size_t length) -{ - if (freeCacheSize() > length) { - memcpy(m_cachePtr, buffer, length); - m_cachePtr += length; - } else if (freeCacheSize() == length) { - memcpy(m_cachePtr, buffer, length); - m_cachePtr += length; - flushWriteCache(); - } else { - int sizeToWrite = length; - - while (sizeToWrite >= freeCacheSize()) { - int endSize = freeCacheSize(); - int offset = length - sizeToWrite; - memcpy(m_cachePtr, (const char*)buffer + offset, endSize); - sizeToWrite -= endSize; - m_cachePtr += endSize; - flushWriteCache(); - } - if (sizeToWrite) { - int offset = length - sizeToWrite; - memcpy(m_cachePtr, (const char*)buffer + offset, sizeToWrite); - m_cachePtr += sizeToWrite; - } - } - - return true; -} - -bool SnappyFile::rawRead(void *buffer, size_t length) -{ - if (endOfData()) { - return false; - } - - if (freeCacheSize() >= length) { - memcpy(buffer, m_cachePtr, length); - m_cachePtr += length; - } else { - size_t sizeToRead = length; - size_t offset = 0; - while (sizeToRead) { - size_t chunkSize = std::min(freeCacheSize(), sizeToRead); - offset = length - sizeToRead; - memcpy((char*)buffer + offset, m_cachePtr, chunkSize); - m_cachePtr += chunkSize; - sizeToRead -= chunkSize; - if (sizeToRead > 0) { - flushReadCache(); - } - if (!m_cacheSize) { - break; - } - } - } - - return true; -} - -int SnappyFile::rawGetc() -{ - int c = 0; - if (!rawRead(&c, 1)) - return -1; - return c; -} - -void SnappyFile::rawClose() -{ - if (m_mode == File::Write) { - flushWriteCache(); - } - m_stream.close(); - delete [] m_cache; - m_cache = NULL; - m_cachePtr = NULL; -} - -void SnappyFile::rawFlush() -{ - assert(m_mode == File::Write); - flushWriteCache(); - m_stream.flush(); -} - -void SnappyFile::flushWriteCache() -{ - size_t inputLength = usedCacheSize(); - - if (inputLength) { - size_t compressedLength; - - ::snappy::RawCompress(m_cache, inputLength, - m_compressedCache, &compressedLength); - - writeCompressedLength(compressedLength); - m_stream.write(m_compressedCache, compressedLength); - m_cachePtr = m_cache; - } - assert(m_cachePtr == m_cache); -} - -void SnappyFile::flushReadCache(size_t skipLength) -{ - //assert(m_cachePtr == m_cache + m_cacheSize); - m_currentOffset.chunk = m_stream.tellg(); - size_t compressedLength; - compressedLength = readCompressedLength(); - - if (compressedLength) { - m_stream.read((char*)m_compressedCache, compressedLength); - ::snappy::GetUncompressedLength(m_compressedCache, compressedLength, - &m_cacheSize); - createCache(m_cacheSize); - if (skipLength < m_cacheSize) { - ::snappy::RawUncompress(m_compressedCache, compressedLength, - m_cache); - } - } else { - createCache(0); - } -} - -void SnappyFile::createCache(size_t size) -{ - // TODO: only re-allocate if the current buffer is not big enough - - if (m_cache) { - delete [] m_cache; - } - - if (size) { - m_cache = new char[size]; - } else { - m_cache = NULL; - } - - m_cachePtr = m_cache; - m_cacheSize = size; -} - -void SnappyFile::writeCompressedLength(size_t length) -{ - unsigned char buf[4]; - buf[0] = length & 0xff; length >>= 8; - buf[1] = length & 0xff; length >>= 8; - buf[2] = length & 0xff; length >>= 8; - buf[3] = length & 0xff; length >>= 8; - assert(length == 0); - m_stream.write((const char *)buf, sizeof buf); -} - -size_t SnappyFile::readCompressedLength() -{ - unsigned char buf[4]; - size_t length; - m_stream.read((char *)buf, sizeof buf); - if (m_stream.fail()) { - length = 0; - } else { - length = (size_t)buf[0]; - length |= ((size_t)buf[1] << 8); - length |= ((size_t)buf[2] << 16); - length |= ((size_t)buf[3] << 24); - } - return length; -} - -bool SnappyFile::supportsOffsets() const -{ - return true; -} - -File::Offset SnappyFile::currentOffset() -{ - m_currentOffset.offsetInChunk = m_cachePtr - m_cache; - return m_currentOffset; -} - -void SnappyFile::setCurrentOffset(const File::Offset &offset) -{ - // to remove eof bit - m_stream.clear(); - // seek to the start of a chunk - m_stream.seekg(offset.chunk, std::ios::beg); - // load the chunk - flushReadCache(); - assert(m_cacheSize >= offset.offsetInChunk); - // seek within our cache to the correct location within the chunk - m_cachePtr = m_cache + offset.offsetInChunk; - -} - -bool SnappyFile::rawSkip(size_t length) -{ - if (endOfData()) { - return false; - } - - if (freeCacheSize() >= length) { - m_cachePtr += length; - } else { - size_t sizeToRead = length; - while (sizeToRead) { - size_t chunkSize = std::min(freeCacheSize(), sizeToRead); - m_cachePtr += chunkSize; - sizeToRead -= chunkSize; - if (sizeToRead > 0) { - flushReadCache(sizeToRead); - } - if (!m_cacheSize) { - break; - } - } - } - - return true; -} - -int SnappyFile::rawPercentRead() -{ - return 100 * (double(m_stream.tellg()) / double(m_endPos)); -} diff --git a/trace_snappyfile.hpp b/trace_snappyfile.hpp deleted file mode 100644 index 33159ec..0000000 --- a/trace_snappyfile.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/************************************************************************** - * - * Copyright 2011 Zack Rusin - * 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_SNAPPYFILE_HPP -#define TRACE_SNAPPYFILE_HPP - -#include - -#include "trace_file.hpp" - -#include -#include - -namespace snappy { - class File; -} - -namespace Trace { - -#define SNAPPY_CHUNK_SIZE (1 * 1024 * 1024) - -#define SNAPPY_BYTE1 'a' -#define SNAPPY_BYTE2 't' - - -class SnappyFile : public File { -public: - SnappyFile(const std::string &filename = std::string(), - File::Mode mode = File::Read); - virtual ~SnappyFile(); - - virtual bool supportsOffsets() const; - virtual File::Offset currentOffset(); - virtual void setCurrentOffset(const File::Offset &offset); -protected: - virtual bool rawOpen(const std::string &filename, File::Mode mode); - virtual bool rawWrite(const void *buffer, size_t length); - virtual bool rawRead(void *buffer, size_t length); - virtual int rawGetc(); - virtual void rawClose(); - virtual void rawFlush(); - virtual bool rawSkip(size_t length); - virtual int rawPercentRead(); - -private: - inline size_t usedCacheSize() const - { - assert(m_cachePtr >= m_cache); - return m_cachePtr - m_cache; - } - inline size_t freeCacheSize() const - { - assert(m_cacheSize >= usedCacheSize()); - if (m_cacheSize > 0) { - return m_cacheSize - usedCacheSize(); - } else { - return 0; - } - } - inline bool endOfData() const - { - return m_stream.eof() && freeCacheSize() == 0; - } - void flushWriteCache(); - void flushReadCache(size_t skipLength = 0); - void createCache(size_t size); - void writeCompressedLength(size_t length); - size_t readCompressedLength(); -private: - std::fstream m_stream; - char *m_cache; - char *m_cachePtr; - size_t m_cacheSize; - - char *m_compressedCache; - - File::Offset m_currentOffset; - std::streampos m_endPos; -}; - -} - -#endif // TRACE_SNAPPYFILE_HPP diff --git a/trace_writer.cpp b/trace_writer.cpp deleted file mode 100644 index 5a5f1f7..0000000 --- a/trace_writer.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/************************************************************************** - * - * Copyright 2007-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. - * - **************************************************************************/ - - -#include -#include -#include -#include -#include - -#include "os.hpp" -#include "trace_writer.hpp" -#include "trace_snappyfile.hpp" -#include "trace_format.hpp" - - -namespace Trace { - - -Writer::Writer() : - call_no(0) -{ - m_file = new Trace::SnappyFile; - close(); -} - -Writer::~Writer() -{ - close(); - delete m_file; - m_file = NULL; -} - -void -Writer::close(void) { - m_file->close(); -} - -bool -Writer::open(const char *filename) { - close(); - - if (!m_file->open(filename, File::Write)) { - return false; - } - - call_no = 0; - functions.clear(); - structs.clear(); - enums.clear(); - bitmasks.clear(); - - _writeUInt(TRACE_VERSION); - - return true; -} - -void inline -Writer::_write(const void *sBuffer, size_t dwBytesToWrite) { - m_file->write(sBuffer, dwBytesToWrite); -} - -void inline -Writer::_writeByte(char c) { - _write(&c, 1); -} - -void inline -Writer::_writeUInt(unsigned long long value) { - char buf[2 * sizeof value]; - unsigned len; - - len = 0; - do { - assert(len < sizeof buf); - buf[len] = 0x80 | (value & 0x7f); - value >>= 7; - ++len; - } while (value); - - assert(len); - buf[len - 1] &= 0x7f; - - _write(buf, len); -} - -void inline -Writer::_writeFloat(float value) { - assert(sizeof value == 4); - _write((const char *)&value, sizeof value); -} - -void inline -Writer::_writeDouble(double value) { - assert(sizeof value == 8); - _write((const char *)&value, sizeof value); -} - -void inline -Writer::_writeString(const char *str) { - size_t len = strlen(str); - _writeUInt(len); - _write(str, len); -} - -inline bool lookup(std::vector &map, size_t index) { - if (index >= map.size()) { - map.resize(index + 1); - return false; - } else { - return map[index]; - } -} - -unsigned Writer::beginEnter(const FunctionSig *sig) { - _writeByte(Trace::EVENT_ENTER); - _writeUInt(sig->id); - if (!lookup(functions, sig->id)) { - _writeString(sig->name); - _writeUInt(sig->num_args); - for (unsigned i = 0; i < sig->num_args; ++i) { - _writeString(sig->arg_names[i]); - } - functions[sig->id] = true; - } - - return call_no++; -} - -void Writer::endEnter(void) { - _writeByte(Trace::CALL_END); -} - -void Writer::beginLeave(unsigned call) { - _writeByte(Trace::EVENT_LEAVE); - _writeUInt(call); -} - -void Writer::endLeave(void) { - _writeByte(Trace::CALL_END); -} - -void Writer::beginArg(unsigned index) { - _writeByte(Trace::CALL_ARG); - _writeUInt(index); -} - -void Writer::beginReturn(void) { - _writeByte(Trace::CALL_RET); -} - -void Writer::beginArray(size_t length) { - _writeByte(Trace::TYPE_ARRAY); - _writeUInt(length); -} - -void Writer::beginStruct(const StructSig *sig) { - _writeByte(Trace::TYPE_STRUCT); - _writeUInt(sig->id); - if (!lookup(structs, sig->id)) { - _writeString(sig->name); - _writeUInt(sig->num_members); - for (unsigned i = 0; i < sig->num_members; ++i) { - _writeString(sig->member_names[i]); - } - structs[sig->id] = true; - } -} - -void Writer::writeBool(bool value) { - _writeByte(value ? Trace::TYPE_TRUE : Trace::TYPE_FALSE); -} - -void Writer::writeSInt(signed long long value) { - if (value < 0) { - _writeByte(Trace::TYPE_SINT); - _writeUInt(-value); - } else { - _writeByte(Trace::TYPE_UINT); - _writeUInt(value); - } -} - -void Writer::writeUInt(unsigned long long value) { - _writeByte(Trace::TYPE_UINT); - _writeUInt(value); -} - -void Writer::writeFloat(float value) { - _writeByte(Trace::TYPE_FLOAT); - _writeFloat(value); -} - -void Writer::writeDouble(double value) { - _writeByte(Trace::TYPE_DOUBLE); - _writeDouble(value); -} - -void Writer::writeString(const char *str) { - if (!str) { - Writer::writeNull(); - return; - } - _writeByte(Trace::TYPE_STRING); - _writeString(str); -} - -void Writer::writeString(const char *str, size_t len) { - if (!str) { - Writer::writeNull(); - return; - } - _writeByte(Trace::TYPE_STRING); - _writeUInt(len); - _write(str, len); -} - -void Writer::writeWString(const wchar_t *str) { - if (!str) { - Writer::writeNull(); - return; - } - _writeByte(Trace::TYPE_STRING); - _writeString(""); -} - -void Writer::writeBlob(const void *data, size_t size) { - if (!data) { - Writer::writeNull(); - return; - } - _writeByte(Trace::TYPE_BLOB); - _writeUInt(size); - if (size) { - _write(data, size); - } -} - -void Writer::writeEnum(const EnumSig *sig) { - _writeByte(Trace::TYPE_ENUM); - _writeUInt(sig->id); - if (!lookup(enums, sig->id)) { - _writeString(sig->name); - Writer::writeSInt(sig->value); - enums[sig->id] = true; - } -} - -void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) { - _writeByte(Trace::TYPE_BITMASK); - _writeUInt(sig->id); - if (!lookup(bitmasks, sig->id)) { - _writeUInt(sig->num_flags); - for (unsigned i = 0; i < sig->num_flags; ++i) { - if (i != 0 && sig->flags[i].value == 0) { - OS::DebugMessage("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name); - } - _writeString(sig->flags[i].name); - _writeUInt(sig->flags[i].value); - } - bitmasks[sig->id] = true; - } - _writeUInt(value); -} - -void Writer::writeNull(void) { - _writeByte(Trace::TYPE_NULL); -} - -void Writer::writeOpaque(const void *addr) { - if (!addr) { - Writer::writeNull(); - return; - } - _writeByte(Trace::TYPE_OPAQUE); - _writeUInt((size_t)addr); -} - - -} /* namespace Trace */ - diff --git a/trace_writer.hpp b/trace_writer.hpp deleted file mode 100644 index dfb76b2..0000000 --- a/trace_writer.hpp +++ /dev/null @@ -1,145 +0,0 @@ -/************************************************************************** - * - * Copyright 2007-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. - * - **************************************************************************/ - -/* - * Trace writing functions. - */ - -#ifndef _TRACE_WRITER_HPP_ -#define _TRACE_WRITER_HPP_ - - -#include - -#include - -#include "trace_model.hpp" - - -namespace Trace { - class File; - - class Writer { - protected: - File *m_file; - unsigned call_no; - - std::vector functions; - std::vector structs; - std::vector enums; - std::vector bitmasks; - - public: - Writer(); - ~Writer(); - - bool open(const char *filename); - void close(void); - - unsigned beginEnter(const FunctionSig *sig); - void endEnter(void); - - void beginLeave(unsigned call); - void endLeave(void); - - void beginArg(unsigned index); - inline void endArg(void) {} - - void beginReturn(void); - inline void endReturn(void) {} - - void beginArray(size_t length); - inline void endArray(void) {} - - inline void beginElement(void) {} - inline void endElement(void) {} - - void beginStruct(const StructSig *sig); - inline void endStruct(void) {} - - void writeBool(bool value); - void writeSInt(signed long long value); - void writeUInt(unsigned long long value); - void writeFloat(float value); - void writeDouble(double value); - void writeString(const char *str); - void writeString(const char *str, size_t size); - void writeWString(const wchar_t *str); - void writeBlob(const void *data, size_t size); - void writeEnum(const EnumSig *sig); - void writeBitmask(const BitmaskSig *sig, unsigned long long value); - void writeNull(void); - void writeOpaque(const void *ptr); - - void writeCall(Call *call); - - protected: - void inline _write(const void *sBuffer, size_t dwBytesToWrite); - void inline _writeByte(char c); - void inline _writeUInt(unsigned long long value); - void inline _writeFloat(float value); - void inline _writeDouble(double value); - void inline _writeString(const char *str); - - }; - - /** - * A specialized Writer class, mean to trace the current process. - * - * In particular: - * - it creates a trace file based on the current process name - * - uses mutexes to allow tracing from multiple threades - * - flushes the output to ensure the last call is traced in event of - * abnormal termination - */ - class LocalWriter : public Writer { - protected: - int acquired; - - public: - /** - * Should never called directly -- use localWriter singleton below instead. - */ - LocalWriter(); - ~LocalWriter(); - - void open(void); - - unsigned beginEnter(const FunctionSig *sig); - void endEnter(void); - - void beginLeave(unsigned call); - void endLeave(void); - - void flush(void); - }; - - /** - * Singleton. - */ - extern LocalWriter localWriter; -} - -#endif /* _TRACE_WRITER_HPP_ */