/****************************************************************************
*
- * Copyright 2008 Jose Fonseca
+ * Copyright 2008-2009 VMware, Inc.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
****************************************************************************/
+#include <stdarg.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+
+#include <zlib.h>
#include "log.hpp"
+#ifdef WIN32
+#ifndef PATH_MAX
+#define PATH_MAX _MAX_PATH
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef vsnprintf
+#define vsnprintf _vsnprintf
+#endif
+#endif
+
+
namespace Log {
-static HANDLE g_hFile = INVALID_HANDLE_VALUE;
-static TCHAR g_szFileName[MAX_PATH];
+static gzFile g_gzFile = NULL;
+static char g_szFileName[PATH_MAX];
+static CRITICAL_SECTION CriticalSection;
static void _Close(void) {
- if(g_hFile != INVALID_HANDLE_VALUE) {
- CloseHandle(g_hFile);
- g_hFile = INVALID_HANDLE_VALUE;
+ if(g_gzFile != NULL) {
+ gzclose(g_gzFile);
+ g_gzFile = NULL;
+ DeleteCriticalSection(&CriticalSection);
}
}
-static void _Open(const TCHAR *szName, const TCHAR *szExtension) {
+static void _Open(const char *szName, const char *szExtension) {
_Close();
- DWORD dwCounter = 0;
- do {
- if(dwCounter)
- _sntprintf(g_szFileName, MAX_PATH, TEXT("%s.%u.%s"), szName, dwCounter, szExtension);
- else
- _sntprintf(g_szFileName, MAX_PATH, TEXT("%s.%s"), szName, szExtension);
-
- g_hFile = CreateFile(g_szFileName,
- GENERIC_WRITE,
- FILE_SHARE_WRITE,
- NULL,
- CREATE_NEW,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- ++dwCounter;
- } while(g_hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_EXISTS);
-}
+ static unsigned dwCounter = 0;
-static void _ReOpen(void) {
- _Close();
-
- g_hFile = CreateFile(g_szFileName,
- GENERIC_WRITE,
- FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
-}
+ char szProcessPath[PATH_MAX];
+ char *lpProcessName;
+ char *lpProcessExt;
-static void Write(const char *sBuffer, DWORD dwBytesToWrite) {
- if(g_hFile == INVALID_HANDLE_VALUE)
- return;
-
- DWORD dwBytesWritten = 0;
-
- while (dwBytesWritten < dwBytesToWrite) {
- OVERLAPPED overlapped;
- memset(&overlapped, 0, sizeof(OVERLAPPED));
+ GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0]));
- /* Write to end of file */
- overlapped.Offset = 0xffffffff;
- overlapped.OffsetHigh = 0xffffffff;
+ lpProcessName = strrchr(szProcessPath, '\\');
+ lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
+ lpProcessExt = strrchr(lpProcessName, '.');
+ if(lpProcessExt)
+ *lpProcessExt = '\0';
+
+ for(;;) {
+ FILE *file;
- if(WriteFile(g_hFile,
- sBuffer + dwBytesWritten,
- dwBytesToWrite - dwBytesWritten,
- &dwBytesWritten,
- &overlapped) == FALSE) {
- _Close();
- _Open(TEXT("extra"), TEXT("xml"));
- return;
- }
+ if(dwCounter)
+ snprintf(g_szFileName, PATH_MAX, "%s.%s.%u.%s.gz", lpProcessName, szName, dwCounter, szExtension);
+ else
+ snprintf(g_szFileName, PATH_MAX, "%s.%s.%s.gz", lpProcessName, szName, szExtension);
+
+ file = fopen(g_szFileName, "rb");
+ if(file == NULL)
+ break;
+
+ fclose(file);
+
+ ++dwCounter;
}
-}
-static void Write(const char *szText) {
- Write(szText, (DWORD)strlen(szText));
+ g_gzFile = gzopen(g_szFileName, "wb");
+ InitializeCriticalSection(&CriticalSection);
}
-void Open(const TCHAR *szName) {
- _Open(szName, TEXT("xml"));
- Write("<?xml version='1.0' encoding='UTF-8'?>");
- NewLine();
- Write("<?xml-stylesheet type='text/xsl' href='d3dtrace.xsl'?>");
- NewLine();
- Write("<trace>");
- NewLine();
+static inline void _ReOpen(void) {
+ /* XXX */
}
-void ReOpen(void) {
- _ReOpen();
+static inline void Write(const char *sBuffer, size_t dwBytesToWrite) {
+ if(g_gzFile == NULL)
+ return;
+
+ gzwrite(g_gzFile, sBuffer, dwBytesToWrite);
}
-void Close(void) {
- Write("</trace>");
- NewLine();
- _Close();
+static inline void Write(const char *szText) {
+ Write(szText, strlen(szText));
}
-static void Escape(const char *s) {
+static inline void
+Escape(const char *s) {
/* FIXME */
Write(s);
}
+static inline void
+Indent(unsigned level) {
+ for(unsigned i = 0; i < level; ++i)
+ Write("\t");
+}
-DWORD g_dwIndent = 0;
-
-void NewLine(void) {
+static inline void
+NewLine(void) {
Write("\r\n");
- for(unsigned i = 0; i < g_dwIndent; ++i)
- Write("\t");
}
-void Tag(const char *name) {
+static inline void
+Tag(const char *name) {
Write("<");
Write(name);
Write("/>");
}
-void BeginTag(const char *name) {
+static inline void
+BeginTag(const char *name) {
Write("<");
Write(name);
Write(">");
- ++g_dwIndent;
}
-void BeginTag(const char *name,
- const char *attr1, const char *value1) {
+static inline void
+BeginTag(const char *name,
+ const char *attr1, const char *value1) {
Write("<");
Write(name);
Write(" ");
Write("=\"");
Escape(value1);
Write("\">");
- ++g_dwIndent;
}
-void BeginTag(const char *name,
- const char *attr1, const char *value1,
- const char *attr2, const char *value2) {
+static inline void
+BeginTag(const char *name,
+ const char *attr1, const char *value1,
+ const char *attr2, const char *value2) {
Write("<");
Write(name);
Write(" ");
Write("=\"");
Escape(value2);
Write("\">");
- ++g_dwIndent;
}
-void BeginTag(const char *name,
+static inline void
+BeginTag(const char *name,
const char *attr1, const char *value1,
const char *attr2, const char *value2,
const char *attr3, const char *value3) {
Write("=\"");
Escape(value3);
Write("\">");
- ++g_dwIndent;
}
-void EndTag(const char *name) {
- --g_dwIndent;
+static inline void
+EndTag(const char *name) {
Write("</");
Write(name);
Write(">");
}
+void Open(const char *name) {
+ _Open(name, "xml");
+ Write("<?xml version='1.0' encoding='UTF-8'?>");
+ NewLine();
+ Write("<?xml-stylesheet type='text/xsl' href='apitrace.xsl'?>");
+ NewLine();
+ BeginTag("trace");
+ NewLine();
+}
+
+void ReOpen(void) {
+ _ReOpen();
+}
+
+void Close(void) {
+ EndTag("trace");
+ NewLine();
+ _Close();
+}
+
void Text(const char *text) {
Escape(text);
}
Text(szBuffer);
}
+static LARGE_INTEGER frequency = {0};
+static LARGE_INTEGER startcounter;
+
void BeginCall(const char *function) {
+ EnterCriticalSection(&CriticalSection);
+ Indent(1);
BeginTag("call", "name", function);
NewLine();
+
+ if(!frequency.QuadPart)
+ QueryPerformanceFrequency(&frequency);
+
+ QueryPerformanceCounter(&startcounter);
}
void EndCall(void) {
+ LARGE_INTEGER endcounter;
+ LONGLONG usecs;
+
+ QueryPerformanceCounter(&endcounter);
+ usecs = (endcounter.QuadPart - startcounter.QuadPart)*1000000/frequency.QuadPart;
+
+ Indent(2);
+ BeginTag("duration");
+ TextF("%llu", usecs);
+ EndTag("duration");
+ NewLine();
+
+ Indent(1);
EndTag("call");
NewLine();
+ gzflush(g_gzFile, Z_SYNC_FLUSH);
+ LeaveCriticalSection(&CriticalSection);
}
void BeginArg(const char *type, const char *name) {
+ Indent(2);
BeginTag("arg", "type", type, "name", name);
}
}
void BeginReturn(const char *type) {
+ Indent(2);
BeginTag("ret", "type", type);
}
void BeginReference(const char *type, const void *addr) {
char saddr[256];
- _snprintf(saddr, sizeof(saddr), "%p", addr);
+ snprintf(saddr, sizeof(saddr), "%p", addr);
BeginTag("ref", "type", type, "addr", saddr);
}
else if(c == '\r')
Text("\\r");
else if(c == '\n')
- Text("\\n");
+ Text(" ");
else {
unsigned char octal0 = c & 0x7;
unsigned char octal1 = (c >> 3) & 0x7;
Log::Text("\"");
}
+void DumpWString(const wchar_t *str) {
+ const wchar_t *p = str;
+ Log::Text("L\"");
+ wchar_t c;
+ while((c = *p++) != 0) {
+ if(c == '\"')
+ Text("\\\"");
+ else if(c == '\\')
+ Text("\\\\");
+ else if(c >= 0x20 && c <= 0x7e)
+ TextChar((char)c);
+ else if(c == '\t')
+ Text("\\t");
+ else if(c == '\r')
+ Text("\\r");
+ else if(c == '\n')
+ Text(" ");
+ else {
+ unsigned octal0 = c & 0x7;
+ unsigned octal1 = (c >> 3) & 0x7;
+ unsigned octal2 = (c >> 3) & 0x7;
+ if(octal2)
+ TextF("\\%u%u%u", octal2, octal1, octal0);
+ else if(octal1)
+ TextF("\\%u%u", octal1, octal0);
+ else
+ TextF("\\%u", octal0);
+ }
+ }
+ Log::Text("\"");
+}
+
} /* namespace Log */