Initial commits of the sharedDebug and sharedMemoryManager projects

This commit is contained in:
Anonymous
2014-01-13 09:07:22 -07:00
parent 5940c017b7
commit b632e73284
91 changed files with 12704 additions and 0 deletions
+3
View File
@@ -1,3 +1,6 @@
add_subdirectory(sharedDebug)
add_subdirectory(sharedFoundation)
add_subdirectory(sharedFoundationTypes)
add_subdirectory(sharedMemoryManager)
add_subdirectory(sharedNetworkMessages)
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 2.8)
project(sharedDebug)
if(WIN32)
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public)
add_subdirectory(src)
@@ -0,0 +1 @@
#include "../../src/shared/CallStack.h"
@@ -0,0 +1 @@
#include "../../src/shared/CallStackCollector.h"
@@ -0,0 +1 @@
#include "../../src/linux/ConfigSharedDebugLinux.h"
@@ -0,0 +1 @@
#include "../../src/shared/DataLint.h"
@@ -0,0 +1 @@
#include "../../src/shared/DebugFlags.h"
@@ -0,0 +1,7 @@
#if defined(PLATFORM_WIN32)
#include "../../src/win32/DebugHelp.h"
#elif defined(PLATFORM_LINUX)
#include "../../src/linux/DebugHelp.h"
#else
#error unsupported platform
#endif
@@ -0,0 +1 @@
#include "../../src/shared/DebugKey.h"
@@ -0,0 +1,7 @@
#if defined(PLATFORM_WIN32)
#include "../../src/win32/DebugMonitor.h"
#elif defined(PLATFORM_LINUX)
#include "../../src/linux/DebugMonitor.h"
#else
#error unsupported platform
#endif
@@ -0,0 +1 @@
#include "../../src/shared/FirstSharedDebug.h"
@@ -0,0 +1 @@
#include "../../src/shared/InstallTimer.h"
@@ -0,0 +1 @@
#include "../../src/shared/LeakFinder.h"
@@ -0,0 +1,7 @@
#if defined(PLATFORM_WIN32)
#include "../../src/win32/PerformanceTimer.h"
#elif defined(PLATFORM_LINUX)
#include "../../src/linux/PerformanceTimer.h"
#else
#error unsupported platform
#endif
@@ -0,0 +1 @@
#include "../../src/shared/PixCounter.h"
@@ -0,0 +1 @@
#include "../../src/shared/Profiler.h"
@@ -0,0 +1,7 @@
#if defined(PLATFORM_WIN32)
#include "../../src/win32/ProfilerTimer.h"
#elif defined(PLATFORM_LINUX)
#include "../../src/linux/ProfilerTimer.h"
#else
#error unsupported platform
#endif
@@ -0,0 +1 @@
#include "../../src/shared/RemoteDebug.h"
@@ -0,0 +1 @@
#include "../../src/shared/RemoteDebug_inner.h"
@@ -0,0 +1 @@
#include "../../src/shared/Report.h"
@@ -0,0 +1 @@
#include "../../src/shared/SetupSharedDebug.h"
@@ -0,0 +1,7 @@
#if defined(PLATFORM_WIN32)
#include "../../src/win32/VTune.h"
#elif defined(PLATFORM_LINUX)
#include "../../src/linux/VTune.h"
#else
#error unsupported platform
#endif
@@ -0,0 +1,74 @@
set(SHARED_SOURCES
shared/CallStack.cpp
shared/CallStack.h
shared/CallStackCollector.cpp
shared/CallStackCollector.h
shared/DataLint.cpp
shared/DataLint.h
shared/DebugFlags.cpp
shared/DebugFlags.h
shared/DebugKey.cpp
shared/DebugKey.h
shared/FirstSharedDebug.h
shared/InstallTimer.cpp
shared/InstallTimer.h
shared/PixCounter.cpp
shared/PixCounter.h
shared/Profiler.cpp
shared/Profiler.h
shared/RemoteDebug.cpp
shared/RemoteDebug.h
shared/RemoteDebug_inner.cpp
shared/RemoteDebug_inner.h
shared/Report.cpp
shared/Report.h
shared/SetupSharedDebug.cpp
shared/SetupSharedDebug.h
)
if(WIN32)
set(PLATFORM_SOURCES
win32/DebugHelp.cpp
win32/DebugHelp.h
win32/DebugMonitor.cpp
win32/DebugMonitor.h
win32/FirstSharedDebug.cpp
win32/PerformanceTimer.cpp
win32/PerformanceTimer.h
win32/ProfilerTimer.cpp
win32/ProfilerTimer.h
win32/VTune.cpp
win32/VTune.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32)
else()
set(PLATFORM_SOURCES
linux/ConfigSharedDebugLinux.cpp
linux/ConfigSharedDebugLinux.h
linux/DebugHelp.cpp
linux/DebugHelp.h
linux/DebugMonitor.cpp
linux/DebugMonitor.h
linux/PerformanceTimer.cpp
linux/PerformanceTimer.h
linux/ProfilerTimer.cpp
linux/ProfilerTimer.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/linux)
endif()
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/shared
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public
${SWG_ROOT_SOURCE_DIR}/external/3rd/library/vtune
)
add_library(sharedDebug STATIC
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
@@ -0,0 +1,70 @@
// ======================================================================
//
// ConfigSharedDebugLinux.cpp
// Copyright 2002 Sony Online Entertainment, Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/ConfigSharedDebugLinux.h"
#include "sharedDebug/Profiler.h"
#include "sharedFoundation/ConfigFile.h"
//===================================================================
namespace ConfigSharedDebugLinuxNamespace
{
bool s_useTty;
const char *s_debugMonitorOutputFilename;
bool s_logTtySetup;
}
using namespace ConfigSharedDebugLinuxNamespace;
//===================================================================
#define KEY_BOOL(a,b) (s_ ## a = ConfigFile::getKeyBool("SharedDebugLinux", #a, b))
#define KEY_STRING(a,b) (s_ ## a = ConfigFile::getKeyString("SharedDebugLinux", #a, b))
// #define KEY_INT(a,b) (s_ ## a = ConfigFile::getKeyInt("ClientAnimation", #a, b))
// #define KEY_FLOAT(a,b) (s_ ## a = ConfigFile::getKeyFloat("ClientAnimation", #a, b))
//===================================================================
void ConfigSharedDebugLinux::install(void)
{
KEY_BOOL(useTty, false);
KEY_STRING(debugMonitorOutputFilename, "ttySpecifier.txt");
KEY_BOOL(logTtySetup, false);
//-- Handle startup profiler handling here.
// @todo this should move into ConfigSharedDebug or be loaded
// by Profiler. Profiler can't load this config file option
// because the Profiler is installed prior to the config file
// system.
Profiler::enableProfilerOutput(ConfigFile::getKeyBool("SharedDebugLinux", "reportProfiler", false));
}
// ------------------------------------------------------------------
bool ConfigSharedDebugLinux::getUseTty()
{
return s_useTty;
}
// ------------------------------------------------------------------
char const *ConfigSharedDebugLinux::getDebugMonitorOutputFilename()
{
return s_debugMonitorOutputFilename;
}
// ------------------------------------------------------------------
bool ConfigSharedDebugLinux::getLogTtySetup()
{
return s_logTtySetup;
}
//===================================================================
@@ -0,0 +1,29 @@
// ======================================================================
//
// ConfigSharedDebugLinux.h
// Copyright 2002 Sony Online Entertainment, Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_ConfigSharedDebugLinux_H
#define INCLUDED_ConfigSharedDebugLinux_H
//===================================================================
class ConfigSharedDebugLinux
{
public:
static void install();
static bool getUseTty();
static char const *getDebugMonitorOutputFilename();
static bool getLogTtySetup();
};
//===================================================================
#endif
@@ -0,0 +1,677 @@
// ======================================================================
//
// DebugHelp.cpp
// Copyright 2001-2003 Sony Online Entertainment
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/DebugHelp.h"
#include "sharedSynchronization/Mutex.h"
#include <execinfo.h>
#include <elf.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <dlfcn.h>
#include <map>
#include <vector>
// ======================================================================
class SymbolCache
{
public:
struct SymbolInfo
{
char const *srcLib;
char const *srcFile;
int srcLine;
bool found;
};
static void clear();
static SymbolInfo const &lookup(void const *addr);
static char const *uniqueString(char const *s);
static void *memPoolAllocate(size_t size);
private:
static const size_t cms_memPoolMaxBytes = 8*1024*1024;
static size_t ms_memPoolUsed;
static char ms_memPool[cms_memPoolMaxBytes];
static char *ms_memPoolFreeList;
static Mutex ms_memPoolMutex;
static SymbolInfo ms_nullSym;
};
// ----------------------------------------------------------------------
template <class T>
class SymbolCacheAllocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T * pointer;
typedef T const * const_pointer;
typedef T & reference;
typedef T const & const_reference;
typedef T value_type;
public:
SymbolCacheAllocator() {}
template <class U> SymbolCacheAllocator(SymbolCacheAllocator<U> const &) {}
template <class U> struct rebind { typedef SymbolCacheAllocator<U> other; };
pointer allocate(size_type n, const_pointer = 0) { return reinterpret_cast<pointer>(SymbolCache::memPoolAllocate(n*sizeof(value_type))); }
void deallocate(const_pointer p, size_type n) {}
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
size_type max_size() const { return SymbolCache::cms_memPoolMaxBytes; }
void construct(pointer p, value_type const & x) { new(p) value_type(x); }
void destroy(pointer p) { p->~value_type(); }
};
// ----------------------------------------------------------------------
size_t SymbolCache::ms_memPoolUsed;
char SymbolCache::ms_memPool[SymbolCache::cms_memPoolMaxBytes];
char *SymbolCache::ms_memPoolFreeList;
Mutex SymbolCache::ms_memPoolMutex;
SymbolCache::SymbolInfo SymbolCache::ms_nullSym;
typedef std::map<void const *, SymbolCache::SymbolInfo, std::less<void const *>, SymbolCacheAllocator<std::pair<void const *, SymbolCache::SymbolInfo> > > SymbolMap;
typedef std::vector<char const *, SymbolCacheAllocator<char const *> > UniqueStringVector;
static SymbolMap ms_cacheMap;
static UniqueStringVector ms_uniqueStringVector;
// ----------------------------------------------------------------------
static Elf32_Shdr const *elfGetObjSectionHeader(void const *objBaseAddr, int sectionIndex)
{
Elf32_Ehdr const *eh = reinterpret_cast<Elf32_Ehdr const *>(objBaseAddr);
if (sectionIndex >= 0 && sectionIndex < eh->e_shnum)
return reinterpret_cast<Elf32_Shdr const *>(static_cast<char const *>(objBaseAddr)+eh->e_shoff+sectionIndex*eh->e_shentsize);
return 0;
}
// ----------------------------------------------------------------------
static char const *elfGetObjSectionData(void const *objBaseAddr, int sectionIndex)
{
Elf32_Shdr const *sh = elfGetObjSectionHeader(objBaseAddr, sectionIndex);
if (sh)
return reinterpret_cast<char const *>(objBaseAddr)+sh->sh_offset;
return 0;
}
// ----------------------------------------------------------------------
static unsigned int elfGetObjSectionSize(void const *objBaseAddr, int sectionIndex)
{
Elf32_Shdr const *sh = elfGetObjSectionHeader(objBaseAddr, sectionIndex);
if (sh)
return sh->sh_size;
return 0;
}
// ----------------------------------------------------------------------
static char const *elfGetObjSectionName(void const *objBaseAddr, int sectionIndex)
{
Elf32_Ehdr const *eh = reinterpret_cast<Elf32_Ehdr const *>(objBaseAddr);
char const *sectionStr = elfGetObjSectionData(objBaseAddr, eh->e_shstrndx);
if (sectionStr)
{
Elf32_Shdr const *sh = elfGetObjSectionHeader(objBaseAddr, sectionIndex);
if (sh)
return sectionStr+sh->sh_name;
}
return 0;
}
// ----------------------------------------------------------------------
static int elfGetObjSectionByName(void const *objBaseAddr, char const *sectionName)
{
int n = reinterpret_cast<Elf32_Ehdr const *>(objBaseAddr)->e_shnum;
for (int i = 0; i < n; ++i)
if (!strcmp(elfGetObjSectionName(objBaseAddr, i), sectionName))
return i;
return -1;
}
// ----------------------------------------------------------------------
inline unsigned int dwarfGet(char const *src, u_int8_t &dest)
{
memcpy(&dest, src, sizeof(u_int8_t));
return sizeof(u_int8_t);
}
// ----------------------------------------------------------------------
inline unsigned int dwarfGet(char const *src, u_int16_t &dest)
{
memcpy(&dest, src, sizeof(u_int16_t));
return sizeof(u_int16_t);
}
// ----------------------------------------------------------------------
inline unsigned int dwarfGet(char const *src, u_int32_t &dest)
{
memcpy(&dest, src, sizeof(u_int32_t));
return sizeof(u_int32_t);
}
// ----------------------------------------------------------------------
class LEB128
{
public:
operator int() const { return value; }
int value;
};
// ----------------------------------------------------------------------
inline unsigned int dwarfGet(char const *src, LEB128 &dest)
{
unsigned int pos = 0;
int shift = 7;
int byte = ((u_int8_t*)src)[pos++];
dest.value = byte;
while (byte >= 0x80)
{
byte = ((u_int8_t *)src)[pos++] ^ 1;
dest.value ^= byte << shift;
shift += 7;
}
if (shift < 32 && (byte & 0x40))
dest.value |= -(1L<<shift);
return pos;
}
// ----------------------------------------------------------------------
class LEB128u
{
public:
operator unsigned int() const { return value; }
unsigned int value;
};
// ----------------------------------------------------------------------
inline unsigned int dwarfGet(char const *src, LEB128u &dest)
{
unsigned int pos = 0;
int shift = 7;
unsigned int byte = ((u_int8_t*)src)[pos++];
dest.value = byte;
while (byte >= 0x80)
{
byte = ((u_int8_t *)src)[pos++] ^ 1;
dest.value ^= byte << shift;
shift += 7;
}
return pos;
}
// ----------------------------------------------------------------------
static bool dwarfSearch(char const *dwarfLines, unsigned int linesLength, void const *addr, Dl_info const &info, char const *&retSrcFile, int &retSrcLine)
{
enum
{
DW_LNE_end_sequence = 1,
DW_LNE_set_address = 2,
DW_LNS_copy = 1,
DW_LNS_advance_pc = 2,
DW_LNS_advance_line = 3,
DW_LNS_set_file = 4,
DW_LNS_set_column = 5,
DW_LNS_negate_stmt = 6,
DW_LNS_set_basic_block = 7,
DW_LNS_const_add_pc = 8,
DW_LNS_fixed_advance_pc = 9,
};
////
void const *bestOverAddr = reinterpret_cast<void const *>(0xffffffff);
void const *bestUnderAddr = 0;
char const *bestUnderSrcFileTable = 0;
int bestUnderSrcFileNum = 0;
int bestUnderSrcLine = 0;
unsigned int stmtProgMaxLen = linesLength;
u_int32_t stmtProgLen = 0;
for (unsigned int progBeginOffset = 0; progBeginOffset < linesLength; progBeginOffset += stmtProgLen+4, stmtProgMaxLen -= stmtProgLen+4)
{
char const *stmtProg = dwarfLines+progBeginOffset;
// get program length
stmtProg += dwarfGet(stmtProg, stmtProgLen);
if (stmtProgLen < 12 || stmtProgLen+4 > stmtProgMaxLen)
continue;
char const *stmtProgEnd = stmtProg+stmtProgLen;
stmtProg += 2; // skip version
// get prologue length
u_int32_t stmtProgPrologueLen; stmtProg += dwarfGet(stmtProg, stmtProgPrologueLen);
if (stmtProgPrologueLen+10 > stmtProgMaxLen)
continue;
char const *stmtProgStart = stmtProg;
u_int8_t stmtProgMinInstructionLen; stmtProg += dwarfGet(stmtProg, stmtProgMinInstructionLen);
if (stmtProgMinInstructionLen == 0)
continue;
++stmtProg; // skip default_is_stmt
int8_t stmtProgLineBase; stmtProg += dwarfGet(stmtProg, *(u_int8_t*)&stmtProgLineBase);
u_int8_t stmtProgLineRange; stmtProg += dwarfGet(stmtProg, stmtProgLineRange);
if (stmtProgLineRange == 0)
continue;
u_int8_t stmtProgOpcodeBase; stmtProg += dwarfGet(stmtProg, stmtProgOpcodeBase);
u_int8_t const *stmtProgOpcodeLengths = reinterpret_cast<u_int8_t const *>(stmtProg);
stmtProg += stmtProgOpcodeBase-1;
// include dirs here
while (*stmtProg)
while (*stmtProg++);
char const *stmtProgFilenames = stmtProg;
stmtProg = stmtProgStart+stmtProgPrologueLen;
// run program
while (stmtProg < stmtProgEnd)
{
int progFile = 0;
int progLine = 1;
u_int32_t progAddr = 0;
bool done = false;
bool valid = false;
while (!done)
{
u_int8_t opcode = *stmtProg++;
if (opcode < stmtProgOpcodeBase)
{
switch (opcode)
{
case 0: // extended
{
u_int8_t size, extendedOpcode;
stmtProg += dwarfGet(stmtProg, size);
stmtProg += dwarfGet(stmtProg, extendedOpcode);
switch (extendedOpcode)
{
case DW_LNE_end_sequence:
valid = true;
done = true;
break;
case DW_LNE_set_address:
stmtProg += dwarfGet(stmtProg, progAddr);
break;
default: // unimplemented extended opcode, skip parms
stmtProg += size-1;
break;
}
}
break;
case DW_LNS_advance_pc:
{
LEB128u incr; stmtProg += dwarfGet(stmtProg, incr);
progAddr += incr*stmtProgMinInstructionLen;
}
break;
case DW_LNS_const_add_pc:
progAddr += (255-stmtProgOpcodeBase)/stmtProgLineRange*stmtProgMinInstructionLen;
break;
case DW_LNS_fixed_advance_pc:
{
u_int16_t incr; stmtProg += dwarfGet(stmtProg, incr);
progAddr += incr;
}
break;
case DW_LNS_advance_line:
{
LEB128 incr; stmtProg += dwarfGet(stmtProg, incr);
progLine += incr;
}
break;
case DW_LNS_set_file:
{
LEB128u fileNum; stmtProg += dwarfGet(stmtProg, fileNum);
progFile = fileNum-1;
}
break;
case DW_LNS_copy:
valid = true;
break;
// ignored
case DW_LNS_set_column:
{
LEB128u col; stmtProg += dwarfGet(stmtProg, col);
}
break;
case DW_LNS_negate_stmt:
case DW_LNS_set_basic_block:
break;
default:
{
// unimplemented standard opcode
// look up standard opcode length and skip that many LEB128u's
LEB128u temp;
for (int i = 0; i < stmtProgOpcodeLengths[opcode-1]; ++i)
stmtProg += dwarfGet(stmtProg, temp);
}
break;
}
}
else // special opcode
{
progLine += stmtProgLineBase+(opcode-stmtProgOpcodeBase)%stmtProgLineRange;
progAddr += (opcode-stmtProgOpcodeBase)/stmtProgLineRange*stmtProgMinInstructionLen;
valid = true;
}
if (valid)
{
unsigned int addrOffset = 0;
if (progAddr < reinterpret_cast<unsigned int>(info.dli_fbase))
addrOffset = reinterpret_cast<unsigned int>(info.dli_fbase);
const void *testAddr = reinterpret_cast<const void *>(progAddr+addrOffset);
if (testAddr >= addr)
{
if (testAddr < bestOverAddr)
bestOverAddr = testAddr;
}
else if (testAddr > bestUnderAddr)
{
bestUnderAddr = testAddr;
bestUnderSrcFileTable = stmtProgFilenames;
bestUnderSrcFileNum = progFile;
bestUnderSrcLine = progLine;
}
}
}
}
}
if (bestUnderAddr && bestOverAddr != reinterpret_cast<void const *>(0xffffffff))
{
char const *srcFile = bestUnderSrcFileTable+1;
for (int i = 0; i < bestUnderSrcFileNum; ++i)
{
while (*srcFile++);
srcFile += 3;
}
retSrcFile = SymbolCache::uniqueString(srcFile);
retSrcLine = bestUnderSrcLine;
return true;
}
return false;
}
// ----------------------------------------------------------------------
static bool dwarfFind(void const *addr, Dl_info const &info, char const *& retSrcFile, int &retSrcLine)
{
bool found = false;
int fd = open(info.dli_fname, O_RDONLY);
if (fd != -1)
{
int fileSize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
void const *mappedAddr = reinterpret_cast<void const *>(mmap(0, fileSize, PROT_READ, MAP_PRIVATE, fd, 0));
close(fd);
if (mappedAddr != MAP_FAILED)
{
int dwarfLinesIndex = elfGetObjSectionByName(mappedAddr, ".debug_line");
if (dwarfLinesIndex != -1)
{
try
{
found = dwarfSearch(
elfGetObjSectionData(mappedAddr, dwarfLinesIndex),
elfGetObjSectionSize(mappedAddr, dwarfLinesIndex),
addr,
info,
retSrcFile,
retSrcLine);
}
catch (std::bad_alloc &)
{
munmap(const_cast<void *>(mappedAddr), fileSize);
throw std::bad_alloc();
}
}
munmap(const_cast<void *>(mappedAddr), fileSize);
}
}
return found;
}
// ----------------------------------------------------------------------
struct Stab
{
unsigned int n_strx; // index into string table
unsigned char n_type; // type of stab entry
char n_other;
unsigned short n_desc; // for N_SLINE entries, line number
unsigned int n_value; // value of symbol
};
// ----------------------------------------------------------------------
static bool stabSearch(Stab const *stab, unsigned int stabSize, char const *stabStr, void const *addr, Dl_info const &info, char const *&retSrcFile, int &retSrcLine)
{
enum
{
N_UNDF = 0, // undefined
N_FUN = 0x24, // function
N_SLINE = 0x44, // source line
N_SO = 0x64, // source file name
N_SOL = 0x84 // local source file name
};
unsigned int stabCount = stabSize/sizeof(Stab);
char const *srcFile = "";
void const *funcBase = 0;
int foundSrcLine = -1;
for (unsigned int i = 0; i < stabCount; ++i, ++stab)
{
if (stab->n_type == N_UNDF) // new stabs section, do a recursive search of it
{
if (stabSearch(stab+1, stab->n_desc*sizeof(Stab), stabStr, addr, info, retSrcFile, retSrcLine))
return true;
i += stab->n_desc;
stab += stab->n_desc;
srcFile = "";
continue;
}
else if (stab->n_type == N_SO || stab->n_type == N_SOL) // source or header file specification
srcFile = stabStr+stab->n_strx;
else if (stab->n_type == N_FUN) // function specification
{
// This may not be terribly accurate - it's attempting to differentiate between already relocated symbols (main program)
// and shared libs, which need to be offset by their file base
if (reinterpret_cast<void const *>(stab->n_value) > info.dli_fbase)
funcBase = reinterpret_cast<void const *>(stab->n_value);
else
funcBase = reinterpret_cast<void const *>(reinterpret_cast<unsigned int>(info.dli_fbase)+stab->n_value);
foundSrcLine = -1;
}
else if (stab->n_type == N_SLINE && addr >= funcBase) // source line
{
if (stab->n_value < reinterpret_cast<unsigned int>(addr)-reinterpret_cast<unsigned int>(funcBase))
foundSrcLine = stab->n_desc;
else
{
retSrcLine = foundSrcLine == -1 ? stab->n_desc : foundSrcLine;
retSrcFile = SymbolCache::uniqueString(srcFile);
return true;
}
}
}
return false;
}
// ----------------------------------------------------------------------
static bool stabsFind(void const *addr, Dl_info const &info, char const *& retSrcFile, int &retSrcLine)
{
bool found = false;
int fd = open(info.dli_fname, O_RDONLY);
if (fd != -1)
{
int fileSize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
void const *mappedAddr = reinterpret_cast<void const *>(mmap(0, fileSize, PROT_READ, MAP_PRIVATE, fd, 0));
close(fd);
if (mappedAddr != MAP_FAILED)
{
int stabIndex = elfGetObjSectionByName(mappedAddr, ".stab");
int stabStrIndex = elfGetObjSectionByName(mappedAddr, ".stabstr");
if (stabIndex != -1 && stabStrIndex != -1)
{
try
{
found = stabSearch(
reinterpret_cast<Stab const *>(elfGetObjSectionData(mappedAddr, stabIndex)),
elfGetObjSectionSize(mappedAddr, stabIndex),
elfGetObjSectionData(mappedAddr, stabStrIndex),
addr,
info,
retSrcFile,
retSrcLine);
}
catch (std::bad_alloc &)
{
munmap(const_cast<void *>(mappedAddr), fileSize);
throw std::bad_alloc();
}
}
munmap(const_cast<void *>(mappedAddr), fileSize);
}
}
return found;
}
// ----------------------------------------------------------------------
SymbolCache::SymbolInfo const &SymbolCache::lookup(void const *addr)
{
SymbolMap::const_iterator i = ms_cacheMap.find(addr);
if (i != ms_cacheMap.end())
return (*i).second;
// allow for running out of the fixed memory pool and recover gracefully
for (int tries = 0; tries < 2; ++tries)
{
try
{
SymbolInfo &symInfo = ms_cacheMap[addr];
Dl_info info;
if (dladdr(addr, &info))
{
symInfo.srcLib = uniqueString(info.dli_fname);
if ( stabsFind(addr, info, symInfo.srcFile, symInfo.srcLine)
|| dwarfFind(addr, info, symInfo.srcFile, symInfo.srcLine))
symInfo.found = true;
}
return symInfo;
}
catch (std::bad_alloc &)
{
ms_uniqueStringVector.clear();
ms_cacheMap.clear();
ms_memPoolUsed = 0;
}
}
return ms_nullSym;
}
// ----------------------------------------------------------------------
char const *SymbolCache::uniqueString(char const *s)
{
for (UniqueStringVector::const_iterator i = ms_uniqueStringVector.begin(); i != ms_uniqueStringVector.end(); ++i)
if (!strcmp(s, *i))
return *i;
char *newString = static_cast<char *>(memPoolAllocate((strlen(s)+8)&(~7)));
strcpy(newString, s);
ms_uniqueStringVector.push_back(newString);
return newString;
}
// ----------------------------------------------------------------------
void *SymbolCache::memPoolAllocate(size_t size)
{
ms_memPoolMutex.enter();
if (ms_memPoolUsed+size > cms_memPoolMaxBytes)
{
ms_memPoolMutex.leave();
throw std::bad_alloc();
}
void *ret = ms_memPool+ms_memPoolUsed;
ms_memPoolUsed += size;
ms_memPoolMutex.leave();
return ret;
}
// ----------------------------------------------------------------------
bool lookupAddressInfo(void const *addr, char *retSrcLib, char *retSrcFile, int &retSrcLine, int stringBufLengths)
{
SymbolCache::SymbolInfo const &symInfo = SymbolCache::lookup(addr);
if (retSrcLib && symInfo.srcLib)
{
strncpy(retSrcLib, symInfo.srcLib, stringBufLengths);
retSrcLib[stringBufLengths-1] = '\0';
}
if (symInfo.found && retSrcFile)
{
strncpy(retSrcFile, symInfo.srcFile, stringBufLengths);
retSrcFile[stringBufLengths-1] = '\0';
}
retSrcLine = symInfo.srcLine;
return symInfo.found;
}
////
// ======================================================================
void DebugHelp::install()
{
}
// ----------------------------------------------------------------------
void DebugHelp::remove()
{
}
// ----------------------------------------------------------------------
bool DebugHelp::lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line)
{
return lookupAddressInfo(reinterpret_cast<void const *>(address), libName, fileName, line, fileNameLength);
}
// ----------------------------------------------------------------------
void DebugHelp::getCallStack(uint32 *callStack, int sizeOfCallStack)
{
for (int i = 0; i < sizeOfCallStack; ++i)
callStack[i] = 0;
IGNORE_RETURN(backtrace(reinterpret_cast<void **>(callStack), sizeOfCallStack));
}
// ======================================================================
@@ -0,0 +1,33 @@
// ======================================================================
//
// DebugHelp.h
// copyright 2000 Verant Interactive
//
// ======================================================================
#ifndef DEBUG_HELP_H
#define DEBUG_HELP_H
#include "sharedDebug/FirstSharedDebug.h"
// ======================================================================
typedef unsigned long uint32;
// ======================================================================
class DebugHelp
{
public:
static void install();
static void remove();
static void getCallStack(uint32 *callStack, int sizeOfCallStack);
static bool lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line);
};
// ======================================================================
#endif
@@ -0,0 +1,445 @@
// ======================================================================
//
// DebugMonitor.cpp
// Copyright 2002, Sony Online Entertainment.h
// All rights reserved.
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/DebugMonitor.h"
#ifdef _DEBUG
#include "sharedDebug/ConfigSharedDebugLinux.h"
#include "sharedDebug/Profiler.h"
#include "sharedFoundation/ConfigSharedFoundation.h"
#include <curses.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
// ======================================================================
namespace DebugMonitorNamespace
{
bool s_installed;
SCREEN *s_initialScreen;
WINDOW *s_initialWindow;
FILE *s_ttyOutputFile;
FILE *s_ttyInputFile;
SCREEN *s_outputScreen;
WINDOW *s_outputWindow;
}
using namespace DebugMonitorNamespace;
// ======================================================================
// Install the debug monitor subsystem
//
// Remarks:
//
// This routine will first attempt to install the selected debug monitor.
void DebugMonitor::install(void)
{
DEBUG_FATAL(s_installed, ("DebugMonitor already installed."));
//-- Check if user wants to use a TTY for the DebugMonitor.
if (!ConfigSharedDebugLinux::getUseTty())
{
// Do not use the DebugMonitor.
DEBUG_REPORT_LOG(ConfigSharedDebugLinux::getLogTtySetup(), ("DebugMonitor: skipping install, ConfigSharedDebugLinux/useTty is false.\n"));
return;
}
//-- Open and retrieve the name of the TTY file for output from the TTY Specification file.
char const *const configFilename = ConfigSharedDebugLinux::getDebugMonitorOutputFilename();
if (!configFilename || (*configFilename == '\0'))
{
DEBUG_WARNING(true, ("DebugMonitor(): skipping installation, no debugMonitorOutputFilename specified."));
return;
}
char ttyFilename[1024];
if (configFilename[0] != '@')
{
// filename is the real output filename (usually a device) for DebugMonitor output.
strncpy(ttyFilename, configFilename, sizeof(ttyFilename) - 1);
ttyFilename[sizeof(ttyFilename)-1] = 0;
}
else
{
// filename is actually an indirection filename, the contents of this file contains the real filename.
FILE *ttySpecifierFile = fopen(configFilename + 1, "r");
if (!ttySpecifierFile)
{
DEBUG_WARNING(true, ("DebugMonitor: failed to open tty specifier file [%s]: [%s].", configFilename + 1, strerror(errno)));
return;
}
// Retrieve the TTY file name.
fgets(ttyFilename, sizeof(ttyFilename), ttySpecifierFile);
fclose(ttySpecifierFile);
}
// Strip trailing newline from TTY filename.
const int filenameLength = strlen(ttyFilename);
if (filenameLength > 0)
{
// chop off trailing newline if present.
if (ttyFilename[filenameLength - 1] == '\n')
ttyFilename[filenameLength - 1] = '\0';
}
//-- Open the TTY file for output.
DEBUG_REPORT_LOG(ConfigSharedDebugLinux::getLogTtySetup(), ("DebugMonitor: opening TTY file [%s] for reading and writing.\n", ttyFilename));
FILE *s_ttyOutputFile = fopen(ttyFilename, "w");
if (!s_ttyOutputFile)
{
DEBUG_WARNING(true, ("DebugMonitor: failed to open tty file for output [%s]: [%s].", ttyFilename, strerror(errno)));
return;
}
//-- Open the TTY file for input.
FILE *s_ttyInputFile = fopen(ttyFilename, "r");
if (!s_ttyInputFile)
{
DEBUG_WARNING(true, ("DebugMonitor: failed to open tty file for input [%s]: [%s].", ttyFilename, strerror(errno)));
fclose(s_ttyOutputFile);
return;
}
#if 1
// NOTE: -TRF- I would not expect this chunk of termios setup
// code to be necessary. My expectation is that it should
// be handled by the curs_inopts (see man page) options I have
// selected below. Alas, these are needed.
//-- Setup profiler window input mode.
const int inputFd = STDIN_FILENO;
// Get terminal attributes.
termios terminalAttributes;
if (tcgetattr(inputFd, &terminalAttributes) != 0)
{
DEBUG_WARNING(true, ("DebugMonitor: tcgetattr failed [%s].", strerror(errno)));
return;
}
// Turn off line-processing mode. We want a character at a time.
terminalAttributes.c_lflag &= ~ICANON;
// Turn off echo.
terminalAttributes.c_lflag &= ~ECHO;
// Specify that read should return immediately (non-blocking).
terminalAttributes.c_cc[VMIN] = 0;
terminalAttributes.c_cc[VTIME] = 0;
// Set terminal attributes.
if (tcsetattr(inputFd, TCSAFLUSH, &terminalAttributes) != 0)
{
DEBUG_WARNING(true, ("DebugMonitor: tcsetattr failed [%s].", strerror(errno)));
return;
}
#endif
//-- Create a curses screen to represent the DebugMonitor output tty.
// NOTE: for now the curses input is hooked up to the application's
// standard input. Later we may want to change that to
// handle input from the output terminal, particularly to
// handle profiler modifications when the output window
// is active.
s_outputScreen = newterm(NULL, s_ttyOutputFile, stdin);
if (!s_outputScreen)
{
DEBUG_WARNING(true, ("DebugMonitor: newterm() failed [%s].", strerror(errno)));
fclose(s_ttyOutputFile);
fclose(s_ttyInputFile);
return;
}
//-- Initialize the curses library.
s_initialWindow = initscr();
if (!s_initialWindow)
{
DEBUG_WARNING(true, ("DebugMonitor: initscr(): failed [%s].", strerror(errno)));
fclose(s_ttyOutputFile);
fclose(s_ttyInputFile);
return;
}
//-- Restore the stdout window to its previous state. We won't use stdout.
endwin();
//-- Set the default terminal to be the output TTY's terminal screen.
s_initialScreen = set_term(s_outputScreen);
if (!s_initialScreen)
{
DEBUG_WARNING(true, ("DebugMonitor: set_term(): failed [%s].", strerror(errno)));
delscreen(s_outputScreen);
fclose(s_ttyOutputFile);
fclose(s_ttyInputFile);
return;
}
//-- Create the curses WINDOW at the full size of the TTY.
s_outputWindow = newwin(0, 0, 0, 0);
if (!s_outputWindow)
{
DEBUG_WARNING(true, ("DebugMonitor: newwin(): failed [%s].", strerror(errno)));
delscreen(s_outputScreen);
fclose(s_ttyOutputFile);
fclose(s_ttyInputFile);
return;
}
//-- Destroy curses data structures associated with the stdout TTY
delwin(s_initialWindow);
delscreen(s_initialScreen);
//-- Additional profiler input setup.
// Allow translation of arrow keys.
if (keypad(s_outputWindow, true) == ERR)
{
DEBUG_WARNING(true, ("DebugMonitor: keypad() failed [%s].", strerror(errno)));
return;
}
//-- Add the removal routine to the ExitChain.
s_installed = true;
// NOTE: this can't go on the exit chain because the MemoryManager
// will write to it way late in processing.
//ExitChain::add(remove, "DebugMonitor");
}
// ----------------------------------------------------------------------
void DebugMonitor::remove(void)
{
if (!s_installed)
{
// Exit silently rather than FATAL. There's any number of reasons why
// we might not be installed, and the ExitChain does not call remove,
// so this should be valid.
return;
}
s_installed = false;
//-- Restore the TTY's state.
endwin();
//-- Delete curses data structures associated with the output terminal.
delwin(s_outputWindow);
s_outputWindow = 0;
delscreen(s_outputScreen);
s_outputScreen = 0;
//-- Close file handle to output terminal.
fclose(s_ttyOutputFile);
s_ttyOutputFile = 0;
fclose(s_ttyInputFile);
s_ttyInputFile = 0;
}
// ----------------------------------------------------------------------
/**
* Set the debug window's z-order.
*/
void DebugMonitor::setBehindWindow(HWND window)
{
UNREF(window);
}
// ----------------------------------------------------------------------
/**
* Clear the debug monitor and home the cursor.
*
* If the mono monitor is not installed, this routine does nothing.
*
* This routine will clear the contents of the debug monitor, reset the screen
* offset to 0, and move the cursor to the upper left corner of the screen.
*
* @see DebugMonitor::home(), DebugMonitor::clearToCursor()
*/
void DebugMonitor::clearScreen(void)
{
//-- Ignore request if DebugMonitor isn't installed.
if (!s_installed)
return;
//-- Tell curses to clear the virtual screen. The actual
// clear will not take effect until the next showOutput() call
// is made.
IGNORE_RETURN(wclear(s_outputWindow));
//-- Goto upper left corner.
gotoXY(0, 0);
}
// ----------------------------------------------------------------------
/**
* Clear the debug monitor to the current cursor position and home the cursor.
*
* If the debug monitor is not installed, this routine does nothing.
*
* This routine will clear the contents of the debug monitor only up to the
* cursor position. If the cursor is not very far down on the screen,
* this routine may be significantly more efficient clearing the screen.
*
* It will also move the cursor to the upper left corner of the screen.
*
* @see DebugMonitor::clearScreen(), DebugMonitor::home()
*/
void DebugMonitor::clearToCursor(void)
{
//-- Ignore request if DebugMonitor isn't installed.
if (!s_installed)
return;
//-- I don't see this functionality in curses. Just clear
// the entire screen.
clearScreen();
}
// ----------------------------------------------------------------------
/**
* Position the cursor on the debug monitor screen.
*
* If the debug monitor is not installed, this routine does nothing.
*
* All printing happens at the cursor position.
*
* @param x New X position for the cursor
* @param y New Y position for the cursor
*/
void DebugMonitor::gotoXY(int x, int y)
{
//-- Ignore request if DebugMonitor isn't installed.
if (!s_installed)
return;
//-- Move the cursor position to the specified location.
const int result = wmove(s_outputWindow, y, x);
DEBUG_REPORT_LOG(result == ERR, ("DebugMonitor: wmove(%d, %d) failed [%s].\n", y, x, strerror(errno)));
UNREF(result);
}
// ----------------------------------------------------------------------
/**
* Display a string on the debug monitor.
* * If the debug monitor is not installed, this routine does nothing.
*
* Printing occurs from the cursor position.
*
* Newline characters '\n' will cause the cursor position to advance to the
* beginning of the next line. If the cursor is already on the last line of
* the screen, the screen will scroll up one line and the cursor will move to
* the beginning of the last line.
*
* The backspace character '\b' will cause the cursor to move one character
* backwards. If at the beginning of the line, the cursor will move to the
* end of the previous line. If already on the first line of the screen, the
* cursor position and screen contents will be unchanged.
*
* All other characters are placed directly into the text frame buffer.
* After each character, the cursor will be logically advanced one
* character forward. If the cursor was on the last column, it will advance
* to the next line. If the cursor was already on the last line, the screen
* will be scrolled up one line and the cursor will move to the beginning of
* the last line.
*
* @param string String to display on the debug monitor
*/
void DebugMonitor::print(const char *string)
{
//-- Ignore request if DebugMonitor isn't installed.
if (!s_installed)
return;
const int result = wprintw(s_outputWindow, const_cast<char*>(string));
DEBUG_REPORT_LOG(result == ERR, ("WARNING: DebugMonitor: wprintw failed [%s].\n", strerror(errno)));
UNREF(result);
}
// ----------------------------------------------------------------------
/**
* Ensure all changes to the DebugMonitor have taken effect by the time
* this function returns.
*
* Note: some platforms may do nothing here. The Win32 platform does not
* require flushing. The Linux platform does. Call it assuming
* that it is needed. It will be a no-op when not required.
*/
void DebugMonitor::flushOutput()
{
//-- Ignore request if DebugMonitor isn't installed.
if (!s_installed)
return;
//-- Tell curses to refresh the output window so that
// the virtual curses display is rendered to the real
// terminal display.
const int result = wrefresh(s_outputWindow);
DEBUG_REPORT_LOG(result == ERR, ("WARNING: DebugMonitor: wrefresh failed [%s].\n", strerror(errno)));
UNREF(result);
//-- Handle tty input here. This is somewhat hacky. Unix tty input
// and output currently are intimately tied to the profiler. Later
// this can be separated out so we can handle multiple TTYs for
// multiple purposes, such as for handling a TTY-based popup debug
// menu for on-the-fly options changing.
const int input = wgetch(s_outputWindow);
if (input != ERR)
{
#if 0
DEBUG_REPORT_LOG(true, ("DebugMonitor: received key [index=%d].\n", input));
#endif
//-- Handle input.
switch (input)
{
case '8':
case KEY_UP:
Profiler::selectionMoveUp();
break;
case '9':
case KEY_DOWN:
Profiler::selectionMoveDown();
break;
case '0':
case 10:
case KEY_LEFT:
case KEY_RIGHT:
Profiler::selectionToggleExpanded();
break;
default:
// Nothing to do.
break;
}
}
}
// ======================================================================
#endif
@@ -0,0 +1,67 @@
// ======================================================================
//
// DebugMonitor.h
// Portions Copyright 1998, Bootprint Entertainment, Inc.
// Portions Copyright 2002, Sony Online Entertainment, Inc.
//
// ======================================================================
#ifndef INCLUDED_DebugMonitor_H
#define INCLUDED_DebugMonitor_H
// ======================================================================
#ifdef _DEBUG
class DebugMonitor
{
private:
public:
static void install(void);
static void remove(void);
typedef void* HWND;
static void setBehindWindow(HWND window);
static void clearScreen(void);
static void clearToCursor(void);
static void home(void);
static void gotoXY(int x, int y);
static void print(const char *string);
static void flushOutput();
};
#endif
// ======================================================================
// Move the cursor to the upper left hand corner of the mono monitor screen
//
// Remarks:
//
// If the debug monitor is not installed, this routine does nothing.
//
// All printing happens at the cursor position.
//
// This routine is identical to calling gotoXY(0,0);
//
// See Also:
//
// DebugMonitor::gotoXY()
#ifdef _DEBUG
inline void DebugMonitor::home(void)
{
gotoXY(0,0);
}
#endif
// ======================================================================
#endif
@@ -0,0 +1,125 @@
//=================================================================== //
//
// PerformanceTimer.cpp
// copyright 2000-2004 Sony Online Entertainment
// All Rights Reserved
//
//===================================================================
#include "sharedFoundation/FirstSharedFoundation.h"
#include "sharedDebug/PerformanceTimer.h"
//===================================================================
#include <cstdio>
//===================================================================
void PerformanceTimer::install()
{
}
//-------------------------------------------------------------------
PerformanceTimer::PerformanceTimer()
{
startTime.tv_sec = 0;
startTime.tv_usec = 0;
stopTime.tv_sec = 0;
stopTime.tv_usec = 0;
}
//-------------------------------------------------------------------
PerformanceTimer::~PerformanceTimer()
{
}
//-------------------------------------------------------------------
void PerformanceTimer::start()
{
int const result = gettimeofday(&startTime, NULL);
FATAL(result != 0,("PerformanceTimer::start failed"));
}
//-------------------------------------------------------------------
void PerformanceTimer::resume()
{
long sec = stopTime.tv_sec - startTime.tv_sec;
long usec = stopTime.tv_usec - startTime.tv_usec;
if(usec < 0)
{
--sec;
usec += 1000000;
}
int const result = gettimeofday(&startTime, NULL);
FATAL(result != 0,("PerformanceTimer::resume failed"));
startTime.tv_sec -= sec;
startTime.tv_usec -= usec;
if(startTime.tv_usec < 0)
{
--startTime.tv_sec;
startTime.tv_usec += 1000000;
}
}
//-------------------------------------------------------------------
void PerformanceTimer::stop()
{
int result = gettimeofday(&stopTime, NULL);
FATAL(result != 0,("PerformanceTimer::start failed"));
}
//-------------------------------------------------------------------
float PerformanceTimer::getElapsedTime() const
{
long sec = stopTime.tv_sec - startTime.tv_sec;
long usec = stopTime.tv_usec - startTime.tv_usec;
if(usec < 0)
{
--sec;
usec += 1000000;
}
return static_cast<float>(sec) +(static_cast<float>(usec) / 1000000.0f);
}
//-------------------------------------------------------------------
float PerformanceTimer::getSplitTime() const
{
timeval currentTime;
int const result = gettimeofday(&currentTime, NULL);
FATAL(result != 0,("PerformanceTimer::getSplitTime failed"));
long sec = currentTime.tv_sec - startTime.tv_sec;
long usec = currentTime.tv_usec - startTime.tv_usec;
if(usec < 0)
{
--sec;
usec += 1000000;
}
return static_cast<float>(sec) +(static_cast<float>(usec) / 1000000.0f);
}
//-------------------------------------------------------------------
void PerformanceTimer::logElapsedTime(const char* string) const
{
UNREF(string);
#ifdef _DEBUG
static char buffer [1000];
sprintf(buffer, "%s : %1.5f seconds\n", string ? string : "null", getElapsedTime());
DEBUG_REPORT_LOG_PRINT(true, ("%s", buffer));
#endif
}
//-------------------------------------------------------------------
@@ -0,0 +1,51 @@
//=================================================================== //
//
// PerformanceTimer.h
// copyright 2000-2004 Sony Online Entertainment
// All Rights Reserved
//
//===================================================================
#ifndef INCLUDED_PerformaceTimer_H
#define INCLUDED_PerformaceTimer_H
//===================================================================
#include <unistd.h>
#include <sys/time.h>
//===================================================================
class PerformanceTimer
{
public:
static void install();
public:
PerformanceTimer();
~PerformanceTimer();
void start();
void resume();
void stop();
float getElapsedTime() const;
float getSplitTime() const;
void logElapsedTime(const char* string) const;
private:
timeval startTime;
timeval stopTime;
private:
PerformanceTimer(PerformanceTimer const &);
PerformanceTimer & operator=(PerformanceTimer const &);
};
//===================================================================
#endif
@@ -0,0 +1,39 @@
// ======================================================================
//
// ProfilerTimer.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/ProfilerTimer.h"
// ======================================================================
void ProfilerTimer::install()
{
}
// ----------------------------------------------------------------------
void ProfilerTimer::getTime(Type &time)
{
timeval tv;
gettimeofday(&tv, 0);
time = static_cast<Type>(tv.tv_sec)*static_cast<Type>(1000000)+static_cast<Type>(tv.tv_usec);
}
// ----------------------------------------------------------------------
void ProfilerTimer::getCalibratedTime(Type &time, Type &frequency)
{
getTime(time);
frequency = 1000000;
}
void ProfilerTimer::getFrequency(Type &frequency)
{
frequency = 1000000;
}
// ======================================================================
@@ -0,0 +1,29 @@
// ======================================================================
//
// ProfilerTimer.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_ProfilerTimer_H
#define INCLUDED_ProfilerTimer_H
// ======================================================================
class ProfilerTimer
{
public:
typedef uint64 Type;
public:
static void install();
static void getTime(Type &type);
static void getCalibratedTime(Type &time, Type &frequency);
static void getFrequency(Type &frequency);
};
// ======================================================================
#endif
@@ -0,0 +1,85 @@
// ======================================================================
//
// CallStack.cpp
// asommers
//
// Copyright 2004, Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/CallStack.h"
#include "sharedDebug/DebugHelp.h"
#include <algorithm>
// ======================================================================
#define DESIRED_CALLSTACK_DEPTH 24
#define CALLSTACK_DEPTH std::min(static_cast<size_t>(CallStack::S_callStack), static_cast<size_t>(DESIRED_CALLSTACK_DEPTH + 2))
// ======================================================================
CallStack::CallStack()
{
Zero(m_callStack);
}
// ----------------------------------------------------------------------
CallStack::~CallStack()
{
}
// ----------------------------------------------------------------------
bool CallStack::operator<(const CallStack &o) const
{
return memcmp(m_callStack, o.m_callStack, sizeof(m_callStack))<0;
}
// ----------------------------------------------------------------------
void CallStack::sample()
{
DebugHelp::getCallStack(m_callStack, CALLSTACK_DEPTH);
}
// ----------------------------------------------------------------------
void CallStack::debugPrint() const
{
char libName[256];
char fileName[256];
int line = 0;
for (size_t i = 2; i < CALLSTACK_DEPTH; ++i)
{
if (DebugHelp::lookupAddress(m_callStack[i], libName, fileName, sizeof(fileName), line))
DEBUG_REPORT_PRINT(true, (" (0x%08X) %s(%d) : caller %d\n", static_cast<int>(m_callStack[i]), fileName, line, i - 1));
else
DEBUG_REPORT_PRINT(true, (" unknown(0x%08X) : caller %d\n", static_cast<int>(m_callStack[i]), i - 1));
}
}
// ----------------------------------------------------------------------
void CallStack::debugLog() const
{
char libName[256];
char fileName[256];
int line = 0;
for (size_t i = 2; i < CALLSTACK_DEPTH && m_callStack[i]!=0; ++i)
{
if (DebugHelp::lookupAddress(m_callStack[i], libName, fileName, sizeof(fileName), line))
DEBUG_REPORT_LOG(true, (" (0x%08X) %s(%d) : caller %d\n", static_cast<int>(m_callStack[i]), fileName, line, i - 1));
else
DEBUG_REPORT_LOG(true, (" unknown(0x%08X) : caller %d\n", static_cast<int>(m_callStack[i]), i - 1));
}
}
// ======================================================================
@@ -0,0 +1,48 @@
// ======================================================================
//
// CallStack.h
// asommers
//
// Copyright 2004, Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#ifndef INCLUDED_CallStack_H
#define INCLUDED_CallStack_H
// ======================================================================
class CallStack
{
public:
public:
CallStack();
~CallStack();
bool operator<(const CallStack &o) const;
void sample();
void debugPrint() const;
void debugLog() const;
private:
enum
{
//-- This is to avoid memory allocations and needing to free the memory
S_callStack = 32
};
private:
uint32 m_callStack[S_callStack];
};
// ======================================================================
#endif
@@ -0,0 +1,262 @@
// ======================================================================
//
// CallStackCollector.cpp
// asommers
//
// Copyright 2004, Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/CallStackCollector.h"
#include "sharedDebug/DebugFlags.h"
#include "sharedDebug/DebugHelp.h"
#include "sharedFoundation/ConstCharCrcString.h"
#include "sharedFoundation/Crc.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedFoundation/LessPointerComparator.h"
#include "sharedFoundation/PersistentCrcString.h"
#include <algorithm>
#include <map>
#include <vector>
// ======================================================================
#define DESIRED_CALLSTACK_DEPTH 24
#define CALLSTACK_DEPTH DESIRED_CALLSTACK_DEPTH + 2
// ======================================================================
namespace CallStackCollectorNamespace
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void remove();
void clear();
void debugReport();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Node
{
public:
explicit Node(char const * name);
~Node();
CrcString const & getName() const;
void addCallStack(uint32 * callStack);
void debugReport() const;
private:
struct CallStackEntry
{
public:
static bool compare(CallStackEntry const * a, CallStackEntry const * b);
public:
uint32 * m_callStack;
int m_calls;
};
private:
Node(Node const &);
Node & operator=(Node const &);
private:
PersistentCrcString const m_name;
typedef std::map<uint32, CallStackEntry> CallStackEntryMap;
CallStackEntryMap m_callStackEntryMap;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
typedef std::map<CrcString const *, Node *, LessPointerComparator> NodeMap;
NodeMap ms_nodeMap;
bool ms_debugReport;
bool ms_enabled;
bool ms_clear;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}
using namespace CallStackCollectorNamespace;
// ======================================================================
bool CallStackCollectorNamespace::Node::CallStackEntry::compare(CallStackEntry const * const a, CallStackEntry const * const b)
{
return b->m_calls < a->m_calls;
}
// ======================================================================
CallStackCollectorNamespace::Node::Node(char const * const name) :
m_name(name, false),
m_callStackEntryMap()
{
}
// ----------------------------------------------------------------------
CallStackCollectorNamespace::Node::~Node()
{
for (CallStackEntryMap::iterator iter = m_callStackEntryMap.begin(); iter != m_callStackEntryMap.end(); ++iter)
delete [] iter->second.m_callStack;
}
// ----------------------------------------------------------------------
CrcString const & CallStackCollectorNamespace::Node::getName() const
{
return m_name;
}
// ----------------------------------------------------------------------
void CallStackCollectorNamespace::Node::addCallStack(uint32 * const callStack)
{
//-- Compute crc of memory
uint32 const crc = Crc::calculate(callStack, sizeof(uint32) * CALLSTACK_DEPTH);
//-- Find callstack in list
CallStackEntryMap::iterator iter = m_callStackEntryMap.find(crc);
if (iter != m_callStackEntryMap.end())
{
//-- Increment count of existing callstack
++iter->second.m_calls;
}
else
{
//-- Create new callstack
uint32 * const newCallStack = new uint32[CALLSTACK_DEPTH];
memcpy(newCallStack, callStack, sizeof(uint32) * CALLSTACK_DEPTH);
CallStackEntry callStackEntry;
callStackEntry.m_callStack = newCallStack;
callStackEntry.m_calls = 1;
m_callStackEntryMap.insert(std::make_pair(crc, callStackEntry));
}
}
// ----------------------------------------------------------------------
void CallStackCollectorNamespace::Node::debugReport() const
{
//-- Find top 3 entries per node
typedef std::vector<CallStackEntry const *> CallStackEntryList;
CallStackEntryList callStackEntryList;
for (CallStackEntryMap::const_iterator iter = m_callStackEntryMap.begin(); iter != m_callStackEntryMap.end(); ++iter)
callStackEntryList.push_back(&iter->second);
std::stable_sort(callStackEntryList.begin(), callStackEntryList.end(), CallStackEntry::compare);
//-- Print out entries
size_t const c_maximumNumberOfPrintedEntries = 3;
for (size_t i = 0; i < std::min(c_maximumNumberOfPrintedEntries, callStackEntryList.size()); ++i)
{
CallStackEntry const * const callStackEntry = callStackEntryList[i];
char libName[256];
char fileName[256];
int line = 0;
REPORT_LOG(true, ("CallStackCollector(%s:%i) callstack called %d times\n", m_name.getString(), i, callStackEntry->m_calls));
for (size_t j = 2; j < CALLSTACK_DEPTH; ++j)
{
if (DebugHelp::lookupAddress(callStackEntry->m_callStack[j], libName, fileName, sizeof(fileName), line))
REPORT_LOG(true, (" %s(%d) : caller %d\n", fileName, line, j - 1));
else
REPORT_LOG(true, (" unknown(0x%08X) : caller %d\n", static_cast<int>(callStackEntry->m_callStack[j]), j - 1));
}
}
}
// ======================================================================
void CallStackCollector::install()
{
DebugFlags::registerFlag(ms_enabled, "SharedDebug/CallStackCollector", "enabled");
DebugFlags::registerFlag(ms_debugReport, "SharedDebug/CallStackCollector", "debugReport", debugReport);
DebugFlags::registerFlag(ms_clear, "SharedDebug/CallStackCollector", "clear");
ExitChain::add(CallStackCollectorNamespace::remove, "CallStackCollectorNamespace::remove");
}
// ----------------------------------------------------------------------
void CallStackCollector::sample(char const * const name)
{
if (ms_clear)
clear();
if (!ms_enabled)
return;
//-- Get the desired node
Node * node = 0;
ConstCharCrcString const crcName(name);
NodeMap::iterator iter = ms_nodeMap.find((const CrcString*)&crcName);
if (iter != ms_nodeMap.end())
node = iter->second;
else
{
node = new Node(name);
ms_nodeMap.insert(std::make_pair(&node->getName(), node));
}
//-- Sample the callstack
uint32 callStack[CALLSTACK_DEPTH];
DebugHelp::getCallStack(&callStack[0], CALLSTACK_DEPTH);
//-- Add to the node
node->addCallStack(&callStack[0]);
}
// ----------------------------------------------------------------------
void CallStackCollectorNamespace::remove()
{
DebugFlags::unregisterFlag(ms_debugReport);
clear();
}
// ----------------------------------------------------------------------
void CallStackCollectorNamespace::clear()
{
for (NodeMap::iterator iter = ms_nodeMap.begin(); iter != ms_nodeMap.end(); ++iter)
delete iter->second;
ms_nodeMap.clear();
ms_clear = false;
}
// ----------------------------------------------------------------------
void CallStackCollectorNamespace::debugReport()
{
if (ms_debugReport)
{
for (NodeMap::iterator iter = ms_nodeMap.begin(); iter != ms_nodeMap.end(); ++iter)
iter->second->debugReport();
ms_debugReport = false;
}
}
// ======================================================================
@@ -0,0 +1,27 @@
// ======================================================================
//
// CallStackCollector.h
// asommers
//
// Copyright 2004, Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#ifndef INCLUDED_CallStackCollector_H
#define INCLUDED_CallStackCollector_H
// ======================================================================
class CallStackCollector
{
public:
static void install();
static void sample(char const * name);
};
// ======================================================================
#endif
@@ -0,0 +1,907 @@
// ============================================================================
//
// DataLint.cpp
// Copyright Sony Online Entertainment
//
// ============================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/DataLint.h"
#include "sharedFoundation/ConfigSharedFoundation.h"
#include "sharedFoundation/ExitChain.h"
#include <cstdio>
#include <set>
#include <stack>
#include <string>
#include <vector>
// ============================================================================
namespace DataLintNamespace
{
enum Mode
{
M_client,
M_server
};
typedef stdvector<std::string>::fwd StringList;
typedef std::pair<std::string, std::pair<DataLint::AssetType, StringList> > WarningPair;
typedef stdvector<WarningPair>::fwd WarningList;
typedef bool (*AssetFunction)(char const *);
bool ms_installed = false;
DataLint::AssetType m_currentAssetType = DataLint::AT_invalid;
bool m_enabled = false;
WarningList * m_warningList = NULL;
StringList * m_assetStack = NULL;
DataLint::StringPairList * m_assetList = NULL;
std::string m_dataLintCategorizedAssetsFile("DataLint_CategorizedAssets.txt");
std::string m_dataLintUnSupportedAssetsFile("DataLint_UnSupportedAssets.txt");
Mode m_mode = M_client;
bool isAnAppearanceAsset(char const *text);
bool isAnArrangementDescriptorAsset(char const *text);
bool isALocalizedStringAsset(char const *text);
bool isAnObjectTemplateAsset(char const *text);
bool isAPortalProprtyAsset(char const *text);
bool isAShaderTemplateAsset(char const *text);
bool isASkyBoxAsset(char const *text);
bool isASlotDescriptorAsset(char const *text);
bool isASoundAsset(char const *text);
bool isATerrainAsset(char const *text);
bool isATextureAsset(char const *text);
bool isATextureRendererTemplateAsset(char const *text);
bool isAnUnSupportedAsset(char const *text);
void fixUpSlashes(char *text);
DataLint::StringPairList getList(int const reserveCount, AssetFunction listTypeFunction);
void writeToCategorizedFile(FILE *fp, char const *title, DataLint::AssetType const listType);
std::string formatErrorMessage(WarningPair &warningPair, int &currentErrorCount);
void writeError(FILE *fp, WarningPair &warningPair, int &currentErrorCount);
}
using namespace DataLintNamespace;
// ============================================================================
//
// DataLint
//
// ============================================================================
void DataLint::install()
{
DEBUG_FATAL(ms_installed, ("DataLint::install: already installed"));
ms_installed = true;
m_enabled = true;
m_warningList = new WarningList();
m_warningList->reserve(4096);
m_assetStack = new StringList ();
m_assetList = new StringPairList();
m_assetList->reserve(4096);
FatalSetThrowExceptions(true);
ExitChain::add(&remove, "DataLint::remove");
}
//-----------------------------------------------------------------------------
bool DataLint::isInstalled()
{
return ms_installed;
}
//-----------------------------------------------------------------------------
void DataLint::report()
{
if (m_enabled)
{
// Error Assets
DEBUG_REPORT_LOG_PRINT(true, ("Writing error files\n"));
// Setup filenames for client versus server mode
std::string dataLintErrorsAll((m_mode == M_client) ? "DataLint_Errors_All.txt" : "DataLintServer_Errors_All.txt");
std::string dataLintErrorsAllFatal((m_mode == M_client) ? "DataLint_Errors_All_Fatal.txt" : "DataLintServer_Errors_All_Fatal.txt");
std::string dataLintErrorsAllWarning((m_mode == M_client) ? "DataLint_Errors_All_Warning.txt" : "DataLintServer_Errors_All_Warning.txt");
std::string dataLintErrorsAllObjectTemplate((m_mode == M_client) ? "DataLint_Errors_ObjectTemplate.txt" : "DataLintServer_Errors_ObjectTemplate.txt");
// Server/client
FILE *assetErrorFileAll = fopen(dataLintErrorsAll.c_str(), "wt");
FILE *assetErrorFileAllFatal = fopen(dataLintErrorsAllFatal.c_str(), "wt");
FILE *assetErrorFileAllWarning = fopen(dataLintErrorsAllWarning.c_str(), "wt");
FILE *assetErrorFileObjectTemplate = fopen(dataLintErrorsAllObjectTemplate.c_str(), "wt");
// Client only
FILE *assetErrorFileAppearance = NULL;
FILE *assetErrorFileArrangementDescriptor = NULL;
FILE *assetErrorFileLocalizedStringTable = NULL;
FILE *assetErrorFilePortalProperty = NULL;
FILE *assetErrorFileShaderTemplate = NULL;
FILE *assetErrorFileSkyBox = NULL;
FILE *assetErrorFileSlotDescriptor = NULL;
FILE *assetErrorFileSoundTemplate = NULL;
FILE *assetErrorFileTerrain = NULL;
FILE *assetErrorFileTexture = NULL;
FILE *assetErrorFileTextureRenderer = NULL;
if (m_mode == M_client)
{
assetErrorFileAppearance = fopen("DataLint_Errors_Appearance.txt", "wt");
assetErrorFileArrangementDescriptor = fopen("DataLint_Errors_ArrangementDescriptor.txt", "wt");
assetErrorFileLocalizedStringTable = fopen("DataLint_Errors_LocalizedStringTable.txt", "wt");
assetErrorFilePortalProperty = fopen("DataLint_Errors_PortalProperty.txt", "wt");
assetErrorFileShaderTemplate = fopen("DataLint_Errors_ShaderTemplate.txt", "wt");
assetErrorFileSkyBox = fopen("DataLint_Errors_SkyBox.txt", "wt");
assetErrorFileSlotDescriptor = fopen("DataLint_Errors_SlotDescriptor.txt", "wt");
assetErrorFileSoundTemplate = fopen("DataLint_Errors_SoundTemplate.txt", "wt");
assetErrorFileTerrain = fopen("DataLint_Errors_Terrain.txt", "wt");
assetErrorFileTexture = fopen("DataLint_Errors_Texture.txt", "wt");
assetErrorFileTextureRenderer = fopen("DataLint_Errors_TextureRenderer.txt", "wt");
}
// Might want to think of a better way to keep track of the number of errors for each specific asset type.
int totalErrorCountAll = 1;
int totalErrorCountAllFatal = 1;
int totalErrorCountAllWarning = 1;
int totalErrorCountAppearance = 1;
int totalErrorCountArrangementDescriptor = 1;
int totalErrorCountLocalizedStringTable = 1;
int totalErrorCountObjectTemplate = 1;
int totalErrorCountPortalProperty = 1;
int totalErrorCountShaderTemplate = 1;
int totalErrorCountSkyBox = 1;
int totalErrorCountSlotDescriptor = 1;
int totalErrorCountSoundTemplate = 1;
int totalErrorCountTerrain = 1;
int totalErrorCountTexture = 1;
int totalErrorCountTextureRenderer = 1;
typedef std::set<std::string> StringSet;
StringSet duplicateStringSet;
if (assetErrorFileAll)
{
WarningList::iterator warningListIter = m_warningList->begin();
for (; warningListIter != m_warningList->end(); ++warningListIter)
{
// Build a duplicate string
std::string duplicateString(warningListIter->first);
StringList::const_iterator stringStackIter = warningListIter->second.second.begin();
for (; stringStackIter != warningListIter->second.second.end(); ++stringStackIter)
{
duplicateString += *stringStackIter;
}
if (duplicateStringSet.find(duplicateString) == duplicateStringSet.end())
{
// This is the first instance of this error, so log it
duplicateStringSet.insert(duplicateString);
}
else
{
// We found a duplicate warning, so don't show it twice
continue;
}
// Write the error to the appropriate error file
switch (warningListIter->second.first)
{
case AT_appearance:
{
if (m_mode == M_client)
{
writeError(assetErrorFileAppearance, *warningListIter, totalErrorCountAppearance);
}
}
break;
case AT_arrangementDescriptor:
{
if (m_mode == M_client)
{
writeError(assetErrorFileArrangementDescriptor, *warningListIter, totalErrorCountArrangementDescriptor);
}
}
break;
case AT_localizedStringTable:
{
if (m_mode == M_client)
{
writeError(assetErrorFileLocalizedStringTable, *warningListIter, totalErrorCountLocalizedStringTable);
}
}
break;
case AT_objectTemplate:
{
writeError(assetErrorFileObjectTemplate, *warningListIter, totalErrorCountObjectTemplate);
}
break;
case AT_portalProperty:
{
if (m_mode == M_client)
{
writeError(assetErrorFilePortalProperty, *warningListIter, totalErrorCountPortalProperty);
}
}
break;
case AT_shaderTemplate:
{
if (m_mode == M_client)
{
writeError(assetErrorFileShaderTemplate, *warningListIter, totalErrorCountShaderTemplate);
}
}
break;
case AT_skyBox:
{
if (m_mode == M_client)
{
writeError(assetErrorFileSkyBox, *warningListIter, totalErrorCountSkyBox);
}
}
break;
case AT_slotDescriptor:
{
if (m_mode == M_client)
{
writeError(assetErrorFileSlotDescriptor, *warningListIter, totalErrorCountSlotDescriptor);
}
}
break;
case AT_soundTemplate:
{
if (m_mode == M_client)
{
writeError(assetErrorFileSoundTemplate, *warningListIter, totalErrorCountSoundTemplate);
}
}
break;
case AT_terrain:
{
if (m_mode == M_client)
{
writeError(assetErrorFileTerrain, *warningListIter, totalErrorCountTerrain);
}
}
break;
case AT_texture:
{
if (m_mode == M_client)
{
writeError(assetErrorFileTexture, *warningListIter, totalErrorCountTexture);
}
}
break;
case AT_textureRendererTemplate:
{
if (m_mode == M_client)
{
writeError(assetErrorFileTextureRenderer, *warningListIter, totalErrorCountTextureRenderer);
}
}
break;
default:
{
DEBUG_REPORT_LOG_PRINT(true, ("DataLint::remove() - Unsupported asset type: %s", warningListIter->first.c_str()));
}
break;
}
// Write the error to the master error file
writeError(assetErrorFileAll, *warningListIter, totalErrorCountAll);
// If this is a fatal, write to the fatal list
if (strstr(warningListIter->first.c_str(), "FATAL:"))
{
writeError(assetErrorFileAllFatal, *warningListIter, totalErrorCountAllFatal);
}
// If a warning, write to the warning list
if (strstr(warningListIter->first.c_str(), "WARNING:"))
{
writeError(assetErrorFileAllWarning, *warningListIter, totalErrorCountAllWarning);
}
}
if (assetErrorFileAll) { fclose(assetErrorFileAll); }
if (assetErrorFileAllFatal) { fclose(assetErrorFileAllFatal); }
if (assetErrorFileAllWarning) { fclose(assetErrorFileAllWarning); }
if (assetErrorFileObjectTemplate) { fclose(assetErrorFileObjectTemplate); }
if (m_mode == M_client)
{
if (assetErrorFileAppearance) { fclose(assetErrorFileAppearance); }
if (assetErrorFileArrangementDescriptor) { fclose(assetErrorFileArrangementDescriptor); }
if (assetErrorFileLocalizedStringTable) { fclose(assetErrorFileLocalizedStringTable); }
if (assetErrorFilePortalProperty) { fclose(assetErrorFilePortalProperty); }
if (assetErrorFileShaderTemplate) { fclose(assetErrorFileShaderTemplate); }
if (assetErrorFileSkyBox) { fclose(assetErrorFileSkyBox); }
if (assetErrorFileSlotDescriptor) { fclose(assetErrorFileSlotDescriptor); }
if (assetErrorFileSoundTemplate) { fclose(assetErrorFileSoundTemplate); }
if (assetErrorFileTerrain) { fclose(assetErrorFileTerrain); }
if (assetErrorFileTexture) { fclose(assetErrorFileTexture); }
if (assetErrorFileTextureRenderer) { fclose(assetErrorFileTextureRenderer); }
}
}
// UnSupported Assets
DEBUG_REPORT_LOG_PRINT(true, ("Writing unsupported assets list: %s\n", m_dataLintUnSupportedAssetsFile.c_str()));
FILE *fp = fopen(m_dataLintUnSupportedAssetsFile.c_str(), "wt");
if (fp)
{
StringPairList unSupportedStringPairList(getList(AT_unSupported));
StringPairList::iterator stringPairListIter = unSupportedStringPairList.begin();
int count = 1;
for (; stringPairListIter != unSupportedStringPairList.end(); ++stringPairListIter)
{
fprintf(fp, "%3d %s @ %s\n", count, stringPairListIter->first.c_str(), stringPairListIter->second.c_str());
++count;
}
fclose(fp);
}
else
{
DEBUG_REPORT_LOG_PRINT(true, ("Error writing unsupported assets list: %s\n", m_dataLintUnSupportedAssetsFile.c_str()));
}
// Categorized Assets
DEBUG_REPORT_LOG_PRINT(true, ("Writing categorized files list: %s\n", m_dataLintCategorizedAssetsFile.c_str()));
fp = fopen(m_dataLintCategorizedAssetsFile.c_str(), "wt");
if (fp)
{
fprintf(fp, "This file contains a categorized listing of the linted assets in the game. The categories are as follows:\n");
fprintf(fp, "\n");
fprintf(fp, "1. Appearances (%5d)\n", getList(AT_appearance).size());
fprintf(fp, "2. Arrangement Descriptors (%5d)\n", getList(AT_arrangementDescriptor).size());
fprintf(fp, "3. Localized String Tables (%5d)\n", getList(AT_localizedStringTable).size());
fprintf(fp, "4. Object Templates (%5d)\n", getList(AT_objectTemplate).size());
fprintf(fp, "5. Portal Properties (%5d)\n", getList(AT_portalProperty).size());
fprintf(fp, "6. Shader Templates (%5d)\n", getList(AT_shaderTemplate).size());
fprintf(fp, "7. SkyBoxes (%5d)\n", getList(AT_skyBox).size());
fprintf(fp, "8. Slot Descriptors (%5d)\n", getList(AT_slotDescriptor).size());
fprintf(fp, "9. Sound Templates (%5d)\n", getList(AT_soundTemplate).size());
fprintf(fp, "10. Terrain (%5d)\n", getList(AT_terrain).size());
fprintf(fp, "11. Textures (%5d)\n", getList(AT_texture).size());
fprintf(fp, "12. Texture Renderer Templates (%5d)\n", getList(AT_textureRendererTemplate).size());
fprintf(fp, "--------------------------------------\n");
fprintf(fp, "13. Total Linted Assets (%5d)\n", m_assetList->size() - getList(AT_unSupported).size());
fprintf(fp, "\n");
writeToCategorizedFile(fp, "Appearances", AT_appearance);
writeToCategorizedFile(fp, "Arrangement Descriptors", AT_arrangementDescriptor);
writeToCategorizedFile(fp, "Localized String Tables", AT_localizedStringTable);
writeToCategorizedFile(fp, "Object Templates", AT_objectTemplate);
writeToCategorizedFile(fp, "Portal Properties", AT_portalProperty);
writeToCategorizedFile(fp, "Shader Templates", AT_shaderTemplate);
writeToCategorizedFile(fp, "SkyBoxes", AT_skyBox);
writeToCategorizedFile(fp, "Slot Descriptors", AT_slotDescriptor);
writeToCategorizedFile(fp, "Sound Templates", AT_soundTemplate);
writeToCategorizedFile(fp, "Terrain", AT_terrain);
writeToCategorizedFile(fp, "Textures", AT_texture);
writeToCategorizedFile(fp, "Texture Renderer Templates", AT_textureRendererTemplate);
fclose(fp);
}
}
}
//-----------------------------------------------------------------------------
void DataLint::remove()
{
DEBUG_FATAL(!ms_installed, ("DataLint::remove: not installed"));
ms_installed = false;
m_enabled = false;
delete m_warningList;
delete m_assetStack;
delete m_assetList;
FatalSetThrowExceptions(false);
}
//-----------------------------------------------------------------------------
void DataLintNamespace::writeError(FILE *fp, WarningPair &warningPair, int &currentErrorCount)
{
std::string formatedErrorMessage(formatErrorMessage(warningPair, currentErrorCount));
if (fp)
{
fprintf(fp, "%s", formatedErrorMessage.c_str());
}
}
//-----------------------------------------------------------------------------
std::string DataLintNamespace::formatErrorMessage(WarningPair &warningPair, int &currentErrorCount)
{
std::string result;
char formatedError[4096];
char text[4096];
sprintf(text, "%s", warningPair.first.c_str());
fixUpSlashes(text);
char *assetError = strstr(text, " : ");
if (assetError != NULL)
{
++assetError;
++assetError;
++assetError;
}
char *lineOfCode = &text[0];
char *seperator = strstr(text, " : ");
if (seperator)
{
*seperator = '\0';
}
if (assetError)
{
// Remove any trailing carriage returns
int assetErrorLength = strlen(assetError);
if (assetErrorLength > 0)
{
char *walkPtr = &assetError[0] + (assetErrorLength - 1);
while ((assetErrorLength > 0) && (*walkPtr == '\n'))
{
--assetErrorLength;
*walkPtr = '\0';
--walkPtr;
}
}
sprintf(formatedError, "%3d Error: %s\n", currentErrorCount, assetError);
result += formatedError;
}
if (lineOfCode)
{
sprintf(formatedError, " Line of Code: %s\n", lineOfCode);
result += formatedError;
}
StringList::reverse_iterator stringListIter = warningPair.second.second.rbegin();
for (; stringListIter != warningPair.second.second.rend(); ++stringListIter)
{
std::string stackString(*stringListIter);
sprintf(text, " Loaded From: %s\n", stackString.c_str());
fixUpSlashes(text);
sprintf(formatedError, "%s", text);
result += formatedError;
}
result += "\n";
++currentErrorCount;
return result;
}
//-----------------------------------------------------------------------------
void DataLint::setEnabled(bool const enabled)
{
m_enabled = enabled;
}
//-----------------------------------------------------------------------------
bool DataLint::isEnabled()
{
return m_enabled || ConfigSharedFoundation::getVerboseWarnings();
}
//-----------------------------------------------------------------------------
void DataLint::pushAsset(char const *assetPath)
{
if (m_assetStack)
{
int const size = m_assetStack->size();
UNREF(size);
m_assetStack->push_back(assetPath);
}
}
//-----------------------------------------------------------------------------
void DataLint::popAsset()
{
if (m_assetStack)
{
int const size = m_assetStack->size();
UNREF(size);
DEBUG_FATAL(m_assetStack->empty(), ("DataLint::popAsset() - Trying to pop the asset stack when it is empty."));
m_assetStack->pop_back();
}
}
//-----------------------------------------------------------------------------
void DataLint::logWarning(std::string const &warning)
{
if (m_enabled)
{
m_warningList->push_back(std::make_pair(warning, std::make_pair(m_currentAssetType, *m_assetStack)));
}
}
//-----------------------------------------------------------------------------
void DataLint::clearAssetStack()
{
if (m_assetStack)
m_assetStack->clear();
}
//-----------------------------------------------------------------------------
void DataLint::addFilePath(char const *filePath)
{
if (filePath == NULL || (strlen(filePath) <= 0))
{
return;
}
if (m_assetList != NULL)
{
char text[4096];
sprintf(text, "%s", filePath);
char *seperator = strstr(text, " @ ");
char *longPath = seperator;
++longPath;
++longPath;
++longPath;
char *shortPath = &text[0];
*seperator = '\0';
m_assetList->push_back(std::make_pair(shortPath, longPath));
}
}
//-----------------------------------------------------------------------------
void DataLint::removeFilePath(char const *filePath)
{
if (m_assetList != NULL)
{
StringPairList::iterator stringPairListIter = m_assetList->begin();
for (; stringPairListIter != m_assetList->end(); ++stringPairListIter)
{
char const *first = stringPairListIter->first.c_str();
if (strcmp(first, filePath) == 0)
{
m_assetList->erase(stringPairListIter);
}
}
}
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isAnAppearanceAsset(char const *text)
{
bool const appearanceAsset = (strstr(text, "appearance/") != NULL);
bool const portalPropertyAsset = (strstr(text, ".pob") != NULL);
return (appearanceAsset && !portalPropertyAsset);
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isAnArrangementDescriptorAsset(char const *text)
{
bool const arrangementDescriptorAsset = (strstr(text, "slot/arrangement/") != NULL);
return arrangementDescriptorAsset;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isALocalizedStringAsset(char const *text)
{
bool const localizedStringAsset = (strstr(text, ".stf") != NULL);
return localizedStringAsset;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isAnObjectTemplateAsset(char const *text)
{
bool result = false;
UNREF(text);
bool const isInTheObjectDirectory = (strstr(text, "object/") != NULL);
bool const isInTheAbstractDirectory = (strstr(text, "abstract/") != NULL);
if (isInTheObjectDirectory || isInTheAbstractDirectory)
{
bool const arrangementDescriptorAsset = isAnArrangementDescriptorAsset(text);
bool const slotDescriptorAsset = isASlotDescriptorAsset(text);
result = (!arrangementDescriptorAsset) && (!slotDescriptorAsset);
}
return result;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isAPortalProprtyAsset(char const *text)
{
bool const portalPropertyAsset = (strstr(text, ".pob") != NULL);
return portalPropertyAsset;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isAShaderTemplateAsset(char const *text)
{
bool const shaderTemplateAsset = (strstr(text, "shader/") != NULL);
return shaderTemplateAsset;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isASkyBoxAsset(char const *text)
{
bool const skyBoxAsset = (strstr(text, "skybox/") != NULL);
return skyBoxAsset;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isASlotDescriptorAsset(char const *text)
{
bool const slotDescriptorAsset = (strstr(text, "slot/descriptor/") != NULL);
return slotDescriptorAsset;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isASoundAsset(char const *text)
{
bool const soundAsset = (strstr(text, "sound/") != NULL);
return soundAsset;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isATerrainAsset(char const *text)
{
return strstr(text, ".trn") != 0;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isATextureAsset(char const *text)
{
bool const textureAsset = (strstr(text, ".dds") != NULL);
return textureAsset;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isATextureRendererTemplateAsset(char const *text)
{
bool const textureRendererAsset = (strstr(text, ".trt") != NULL);
return textureRendererAsset;
}
//-----------------------------------------------------------------------------
bool DataLintNamespace::isAnUnSupportedAsset(char const *text)
{
bool const appearanceAsset = isAnAppearanceAsset(text);
bool const arrangementDescriptorAsset = isAnArrangementDescriptorAsset(text);
bool const localizedStringAsset = isALocalizedStringAsset(text);
bool const objectTemplateAsset = isAnObjectTemplateAsset(text);
bool const portalPropertyAsset = isAPortalProprtyAsset(text);
bool const shaderTemplateAsset = isAShaderTemplateAsset(text);
bool const skyBoxAsset = isASkyBoxAsset(text);
bool const slotDescriptorAsset = isASlotDescriptorAsset(text);
bool const soundAsset = isASoundAsset(text);
bool const terrainAsset = isATerrainAsset(text);
bool const textureAsset = isATextureAsset(text);
bool const textureRendererTemplateAsset = isATextureRendererTemplateAsset(text);
bool const result = !(appearanceAsset ||
arrangementDescriptorAsset ||
localizedStringAsset ||
objectTemplateAsset ||
portalPropertyAsset ||
shaderTemplateAsset ||
skyBoxAsset ||
slotDescriptorAsset ||
soundAsset ||
terrainAsset ||
textureAsset ||
textureRendererTemplateAsset);
return result;
}
//-----------------------------------------------------------------------------
DataLint::StringPairList DataLintNamespace::getList(int const reserveCount, AssetFunction assetTypeFunction)
{
DEBUG_FATAL(!m_assetList, ("DataLint::getList() - m_assetList is NULL"));
// Create the list of terrains
DataLint::StringPairList stringPairList;
stringPairList.reserve(reserveCount);
DataLint::StringPairList::iterator stringPairListIter = m_assetList->begin();
for (; stringPairListIter != m_assetList->end(); ++stringPairListIter)
{
char const *first = stringPairListIter->first.c_str();
char const *second = stringPairListIter->second.c_str();
if (assetTypeFunction(first))
{
stringPairList.push_back(std::make_pair(first, second));
}
}
return stringPairList;
}
//-----------------------------------------------------------------------------
DataLint::StringPairList DataLint::getList(AssetType const assetType)
{
switch (assetType)
{
case AT_appearance:
{
return DataLintNamespace::getList(8192, isAnAppearanceAsset);
}
break;
case AT_arrangementDescriptor:
{
return DataLintNamespace::getList(1024, isAnArrangementDescriptorAsset);
}
break;
case AT_localizedStringTable:
{
return DataLintNamespace::getList(1024, isALocalizedStringAsset);
}
break;
case AT_objectTemplate:
{
return DataLintNamespace::getList(8192, isAnObjectTemplateAsset);
}
break;
case AT_portalProperty:
{
return DataLintNamespace::getList(512, isAPortalProprtyAsset);
}
break;
case AT_shaderTemplate:
{
return DataLintNamespace::getList(4096, isAShaderTemplateAsset);
}
break;
case AT_skyBox:
{
return DataLintNamespace::getList(256, isASkyBoxAsset);
}
break;
case AT_slotDescriptor:
{
return DataLintNamespace::getList(1024, isASlotDescriptorAsset);
}
break;
case AT_soundTemplate:
{
return DataLintNamespace::getList(4096, isASoundAsset);
}
break;
case AT_terrain:
{
return DataLintNamespace::getList(32, isATerrainAsset);
}
break;
case AT_texture:
{
return DataLintNamespace::getList(8192, isATextureAsset);
}
break;
case AT_textureRendererTemplate:
{
return DataLintNamespace::getList(512, isATextureRendererTemplateAsset);
}
break;
case AT_unSupported:
{
return DataLintNamespace::getList(4096, isAnUnSupportedAsset);
}
break;
default:
{
DEBUG_FATAL(true, ("DataLint::getList() - Unknown list type."));
}
}
return StringPairList();
}
//-----------------------------------------------------------------------------
void DataLintNamespace::fixUpSlashes(char *text)
{
char *slashEater = &text[0];
while (*slashEater != '\0')
{
if (*slashEater == '\\')
{
*slashEater = '/';
}
++slashEater;
}
}
//-----------------------------------------------------------------------------
void DataLintNamespace::writeToCategorizedFile(FILE *fp, char const *title, DataLint::AssetType const assetType)
{
DataLint::StringPairList stringPairlist(DataLint::getList(assetType));
fprintf(fp, "-----------------%s (%d assets)-----------------\n", title, static_cast<int>(stringPairlist.size()));
fprintf(fp, "\n");
DataLint::StringPairList::const_iterator stringPairListIter = stringPairlist.begin();
int count = 1;
for (; stringPairListIter != stringPairlist.end(); ++stringPairListIter)
{
fprintf(fp, "%4d %s @ %s\n", count, stringPairListIter->first.c_str(), stringPairListIter->second.c_str());
++count;
}
fprintf(fp, "\n");
}
//-----------------------------------------------------------------------------
void DataLint::setCurrentAssetType(AssetType const assetType)
{
m_currentAssetType = assetType;
}
//-----------------------------------------------------------------------------
void DataLint::setClientMode()
{
m_mode = M_client;
}
//-----------------------------------------------------------------------------
void DataLint::setServerMode()
{
m_mode = M_server;
}
// ============================================================================
@@ -0,0 +1,73 @@
// ============================================================================
//
// DataLint.h
// Copyright Sony Online Entertainment
//
// ============================================================================
#ifndef DATALINT_H
#define DATALINT_H
// ============================================================================
class DataLint
{
public:
typedef stdvector<std::pair<std::string, std::string> >::fwd StringPairList;
public:
static void install();
static void remove();
static bool isInstalled();
static void setClientMode();
static void setServerMode();
static void addFilePath(char const *filePath);
static void removeFilePath(char const *filePath);
DLLEXPORT static bool isEnabled();
static void setEnabled(bool const enabled);
static void clearAssetStack();
static void logWarning(std::string const &warning);
static void logNote(std::string const &warning);
static void pushAsset(char const *assetPath);
static void popAsset();
// Dump the report files
static void report();
// If you add a new asset type, it needs a matching isA<AssetType> function below
enum AssetType
{
AT_appearance,
AT_arrangementDescriptor,
AT_localizedStringTable,
AT_objectTemplate,
AT_portalProperty,
AT_shaderTemplate,
AT_skyBox,
AT_slotDescriptor,
AT_soundTemplate,
AT_terrain,
AT_texture,
AT_textureRendererTemplate,
AT_unSupported,
AT_count,
AT_invalid = -1
};
static StringPairList getList(AssetType const listType);
static void setCurrentAssetType(AssetType const assetType);
};
// ============================================================================
#endif
@@ -0,0 +1,259 @@
// ======================================================================
//
// DebugFlags.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/DebugFlags.h"
#include "sharedFoundation/ConfigFile.h"
#include <algorithm>
#include <vector>
// ======================================================================
std::vector<DebugFlags::Flag> DebugFlags::ms_flagsSortedByName;
std::vector<DebugFlags::Flag> DebugFlags::ms_flagsSortedByReportPriority;
// ======================================================================
/**
* @internal
*/
void DebugFlags::config(bool &variable, const char *configSection, const char *configName)
{
DEBUG_FATAL(strchr(configSection, ' ') != NULL, ("no spaces are allowed in debug flag section names: %s", configSection));
DEBUG_FATAL(strchr(configName, ' ') != NULL, ("no spaces are allowed in debug flag names: %s", configName));
if (configSection && configName && ConfigFile::isInstalled())
{
#ifdef _DEBUG
Flag const * const flag = getFlag(configSection, configName);
if (flag)
{
DEBUG_WARNING(true, ("DebugFlags::registerFlag: %s/%s is already registered", configSection, configName));
flag->m_callStack.debugLog();
}
#endif
variable = ConfigFile::getKeyBool(configSection, configName, variable);
}
}
// ----------------------------------------------------------------------
/**
* @internal
*/
static bool sortByNameLess(const DebugFlags::Flag &lhs, const DebugFlags::Flag &rhs)
{
const int s = strcmp(lhs.section, rhs.section);
if (s < 0)
return true;
if (s > 0)
return false;
return strcmp(lhs.name, rhs.name) < 0;
}
// ----------------------------------------------------------------------
/**
* @internal
*/
static bool sortByReportPriorityLess(const DebugFlags::Flag &lhs, const DebugFlags::Flag &rhs)
{
return (lhs.reportPriority < rhs.reportPriority);
}
// ----------------------------------------------------------------------
/**
* @internal
*/
void DebugFlags::insert(const Flag &flag)
{
ms_flagsSortedByName.insert(std::lower_bound(ms_flagsSortedByName.begin(), ms_flagsSortedByName.end(), flag, sortByNameLess), flag);
if (flag.reportRoutine1 || flag.reportRoutine2)
ms_flagsSortedByReportPriority.insert(std::lower_bound(ms_flagsSortedByReportPriority.begin(), ms_flagsSortedByReportPriority.end(), flag, sortByReportPriorityLess), flag);
}
// ----------------------------------------------------------------------
/**
* Register a debug flag.
* The parameters passed to this function must never go out of scope.
* @param variable The bool variable to determine whether the flag is on or not.
* @param section The section for the variable.
* @param name The name of the variable.
*/
void DebugFlags::registerFlag(bool &variable, const char *section, const char *name)
{
NOT_NULL(section);
NOT_NULL(name);
config(variable, section, name);
Flag f;
f.variable = &variable;
f.section = section;
f.name = name;
f.reportPriority = 0;
f.reportRoutine1 = NULL;
f.reportRoutine2 = NULL;
f.context = NULL;
#ifdef _DEBUG
f.m_callStack.sample();
#endif
insert(f);
}
// ----------------------------------------------------------------------
void DebugFlags::registerFlag(bool &variable, const char *section, const char *name, ReportRoutine1 reportRoutine, int reportPriority)
{
NOT_NULL(section);
NOT_NULL(name);
config(variable, section, name);
Flag f;
f.variable = &variable;
f.section = section;
f.name = name;
f.reportPriority = reportPriority;
f.reportRoutine1 = reportRoutine;
f.reportRoutine2 = NULL;
f.context = NULL;
#ifdef _DEBUG
f.m_callStack.sample();
#endif
insert(f);
}
// ----------------------------------------------------------------------
void DebugFlags::registerFlag(bool &variable, const char *section, const char *name, ReportRoutine2 reportRoutine, void *context, int reportPriority)
{
NOT_NULL(section);
NOT_NULL(name);
config(variable, section, name);
Flag f;
f.variable = &variable;
f.section = section;
f.name = name;
f.reportPriority = reportPriority;
f.reportRoutine1 = NULL;
f.reportRoutine2 = reportRoutine;
f.context = context;
#ifdef _DEBUG
f.m_callStack.sample();
#endif
insert(f);
}
// ----------------------------------------------------------------------
/**
* Unregister a debug flag.
*/
void DebugFlags::unregisterFlag(bool &variable)
{
{
FlagVector::iterator end = ms_flagsSortedByName.end();
for (FlagVector::iterator i = ms_flagsSortedByName.begin(); i != end; ++i)
if (i->variable == &variable)
{
ms_flagsSortedByName.erase(i);
break;
}
}
{
FlagVector::iterator end = ms_flagsSortedByReportPriority.end();
for (FlagVector::iterator i = ms_flagsSortedByReportPriority.begin(); i != end; ++i)
if (i->variable == &variable)
{
ms_flagsSortedByReportPriority.erase(i);
break;
}
}
}
// ----------------------------------------------------------------------
void DebugFlags::callReportRoutines()
{
FlagVector::const_iterator end = ms_flagsSortedByReportPriority.end();
for (FlagVector::const_iterator i = ms_flagsSortedByReportPriority.begin(); i != end; ++i)
{
const Flag &f = *i;
if (*f.variable)
{
if (f.reportRoutine1)
f.reportRoutine1();
else
if (f.reportRoutine2)
f.reportRoutine2(f.context);
}
}
}
// ----------------------------------------------------------------------
bool * DebugFlags::findFlag(char const * const section, char const * const name)
{
Flag const * const flag = getFlag(section, name);
if (flag)
return flag->variable;
return 0;
}
// ----------------------------------------------------------------------
DebugFlags::Flag const * DebugFlags::getFlag(char const * const section, char const * name)
{
FlagVector::const_iterator iEnd = ms_flagsSortedByName.end();
for (FlagVector::const_iterator i = ms_flagsSortedByName.begin(); i != iEnd; ++i)
{
Flag const & f = *i;
if (strcmp(f.section, section) == 0 && strcmp(f.name, name) == 0)
return &f;
}
return NULL;
}
// ----------------------------------------------------------------------
int DebugFlags::getNumberOfFlags()
{
return static_cast<int>(ms_flagsSortedByName.size());
}
// ----------------------------------------------------------------------
char const * DebugFlags::getFlagSection(int const index)
{
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfFlags());
return ms_flagsSortedByName[index].section;
}
// ----------------------------------------------------------------------
char const * DebugFlags::getFlagName(int const index)
{
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfFlags());
return ms_flagsSortedByName[index].name;
}
// ======================================================================
@@ -0,0 +1,73 @@
// ======================================================================
//
// DebugFlags.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_DebugFlags_H
#define INCLUDED_DebugFlags_H
// ======================================================================
#include "CallStack.h"
// ======================================================================
class DebugFlags
{
friend class Os;
public:
typedef void (*ReportRoutine1)();
typedef void (*ReportRoutine2)(void *context);
public:
static DLLEXPORT void registerFlag(bool &variable, const char *section, const char *name);
static DLLEXPORT void registerFlag(bool &variable, const char *section, const char *name, ReportRoutine1 reportRoutine, int reportPriority=0);
static void registerFlag(bool &variable, const char *section, const char *name, ReportRoutine2 reportRoutine, void *context, int reportPriority=0);
static DLLEXPORT void unregisterFlag(bool &variable);
static void callReportRoutines();
static bool *findFlag(const char *section, const char *name);
static int getNumberOfFlags();
static char const * getFlagSection(int index);
static char const * getFlagName(int index);
public:
struct Flag
{
bool *variable;
const char *section;
const char *name;
int reportPriority;
ReportRoutine1 reportRoutine1;
ReportRoutine2 reportRoutine2;
void *context;
#ifdef _DEBUG
CallStack m_callStack;
#endif
};
private:
static void config(bool &variable, const char *configSection, const char *configName);
static void insert(const Flag &flag);
static Flag const * getFlag(char const * const section, char const * name);
private:
typedef stdvector<Flag>::fwd FlagVector;
static FlagVector ms_flagsSortedByName;
static FlagVector ms_flagsSortedByReportPriority;
};
// ======================================================================
#endif
@@ -0,0 +1,164 @@
// ======================================================================
//
// DebugKey.cpp
// copyright 1998 Bootprint Entertainment
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/DebugKey.h"
#include "sharedFoundation/ConfigFile.h"
#include "sharedFoundation/Production.h"
#include <algorithm>
#include <vector>
// ======================================================================
#if PRODUCTION == 0
bool *DebugKey::ms_currentFlag;
bool DebugKey::ms_pressed[10];
bool DebugKey::ms_down[10];
DebugKey::FlagVector DebugKey::ms_flags;
#endif
// ======================================================================
/**
* @internal
*/
bool DebugKey::Flag::operator <(const Flag &rhs) const
{
return strcmp(name, rhs.name) < 0;
}
// ----------------------------------------------------------------------
void DebugKey::newFrame()
{
#if PRODUCTION == 0
memset(ms_pressed, 0, sizeof(ms_pressed));
#endif
}
// ----------------------------------------------------------------------
void DebugKey::lostFocus()
{
#if PRODUCTION == 0
memset(ms_down, 0, sizeof(ms_down));
memset(ms_pressed, 0, sizeof(ms_pressed));
#endif
}
// ----------------------------------------------------------------------
/**
* Register a debug key flag.
* The parameters passed to this function must never go out of scope.
* @param variable The bool variable to determine whether the flag is on or not.
* @param name The name of the variable.
*/
void DebugKey::registerFlag(bool &variable, const char *name)
{
#if PRODUCTION == 0
if (ConfigFile::isInstalled())
variable = ConfigFile::getKeyBool("SharedDebug/DebugKey", name, variable);
Flag f;
f.variable = &variable;
f.name = name;
ms_flags.insert(std::lower_bound(ms_flags.begin(), ms_flags.end(), f), f);
#else
UNREF(variable);
UNREF(name);
#endif
}
// ----------------------------------------------------------------------
bool DebugKey::isPressed(int i)
{
#if PRODUCTION == 0
DEBUG_FATAL(i < 0 || i > 9, ("DebugKey::isPressed out of range 0/%d/9", i));
return ms_pressed[i];
#else
UNREF(i);
return false;
#endif
}
// ----------------------------------------------------------------------
bool DebugKey::isDown(int i)
{
#if PRODUCTION == 0
DEBUG_FATAL(i < 0 || i > 9, ("DebugKey::isDown out of range 0/%d/9", i));
return (ms_pressed[i] || ms_down[i]);
#else
UNREF(i);
return false;
#endif
}
// ----------------------------------------------------------------------
bool DebugKey::isActive()
{
#if PRODUCTION == 0
return ms_currentFlag != NULL;
#else
return false;
#endif
}
// ----------------------------------------------------------------------
void DebugKey::setCurrentFlag(const bool *newFlag)
{
#if PRODUCTION == 0
lostFocus();
// make sure the old flag gets set false
if (ms_currentFlag)
*ms_currentFlag = false;
// update the flag pointer
ms_currentFlag = const_cast<bool *>(newFlag);
// make sure the new flag gets set true
if (ms_currentFlag)
*ms_currentFlag = true;
#else
UNREF(newFlag);
#endif
}
// ----------------------------------------------------------------------
void DebugKey::pressKey(int i)
{
#if PRODUCTION == 0
DEBUG_FATAL(i < 0 || i > 9, ("DebugKey::pressKey out of range 0/%d/9", i));
ms_pressed[i] = true;
ms_down[i] = true;
#else
UNREF(i);
#endif
}
// ----------------------------------------------------------------------
void DebugKey::releaseKey(int i)
{
#if PRODUCTION == 0
DEBUG_FATAL(i < 0 || i > 9, ("DebugKey::releastKey out of range 0/%d/9", i));
ms_down[i] = false;
#else
UNREF(i);
#endif
}
// ======================================================================
@@ -0,0 +1,56 @@
// ======================================================================
//
// DebugKey.h
// copyright 1998 Bootprint Entertainment
// copyright 2001 Sony Online Entertainment
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_DebugKey_H
#define INCLUDED_DebugKey_H
// ======================================================================
class DebugKey
{
friend class Os;
public:
static DLLEXPORT void registerFlag(bool &variable, const char *name);
static void newFrame();
static void lostFocus();
static bool isActive();
static void setCurrentFlag(const bool *flag);
static void pressKey(int i);
static void releaseKey(int i);
static DLLEXPORT bool isPressed(int i);
static DLLEXPORT bool isDown(int i);
private:
struct Flag
{
bool *variable;
const char *name;
bool operator <(const Flag &rhs) const;
};
typedef stdvector<Flag>::fwd FlagVector;
private:
static bool *ms_currentFlag;
static bool ms_pressed[10];
static bool ms_down[10];
static FlagVector ms_flags;
};
// ======================================================================
#endif
@@ -0,0 +1,17 @@
// ======================================================================
//
// FirstDebug.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_FirstDebug_H
#define INCLUDED_FirstDebug_H
// ======================================================================
#include "sharedFoundation/FirstSharedFoundation.h"
// ======================================================================
#endif
@@ -0,0 +1,71 @@
// ======================================================================
//
// InstallTimer.cpp
// Copyright 2004 Sony Online Entertainment Inc
// All Rights Reserved
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/InstallTimer.h"
#include "sharedFoundation/ConfigFile.h"
// ======================================================================
namespace InstallTimerNamespace
{
bool ms_enabled;
int ms_indent = 1;
}
using namespace InstallTimerNamespace;
// ======================================================================
void InstallTimer::enable()
{
ms_enabled = true;
}
// ----------------------------------------------------------------------
void InstallTimer::checkConfigFile()
{
ms_enabled = ConfigFile::getKeyBool("SharedDebug/InstallTimer", "enabled", false);
}
// ======================================================================
InstallTimer::InstallTimer(char const * description)
:
m_description(description),
m_performanceTimer(),
m_startingNumberOfBytesAllocated(MemoryManager::getCurrentNumberOfBytesAllocated())
{
NOT_NULL(m_description);
m_performanceTimer.start();
++ms_indent;
}
// ----------------------------------------------------------------------
InstallTimer::~InstallTimer()
{
manualExit();
}
// ----------------------------------------------------------------------
void InstallTimer::manualExit()
{
if (m_description)
{
m_performanceTimer.stop();
unsigned long const endingNumberOfBytesAllocated = MemoryManager::getCurrentNumberOfBytesAllocated();
--ms_indent;
REPORT_LOG_PRINT(ms_enabled, ("InstallTimer:%*c%6.4f %d %s\n", ms_indent * 2, ' ', m_performanceTimer.getElapsedTime(), static_cast<int>(endingNumberOfBytesAllocated - m_startingNumberOfBytesAllocated), m_description));
m_description = NULL;
}
}
// ======================================================================
@@ -0,0 +1,46 @@
// ======================================================================
//
// InstallTimer.h
// Copyright 2004 Sony Online Entertainment Inc
// All Rights Reserved
//
// ======================================================================
#ifndef INCLUDED_InstallTimer_H
#define INCLUDED_InstallTimer_H
// ======================================================================
#include "sharedDebug/PerformanceTimer.h"
// ======================================================================
class InstallTimer
{
public:
static void enable();
static void checkConfigFile();
public:
InstallTimer(char const * description);
~InstallTimer();
void manualExit();
private:
InstallTimer(InstallTimer const &);
InstallTimer & operator=(InstallTimer const &);
private:
char const * m_description;
PerformanceTimer m_performanceTimer;
unsigned long const m_startingNumberOfBytesAllocated;
};
// ======================================================================
#endif
@@ -0,0 +1,197 @@
// ======================================================================
//
// LeakFinder.cpp
// bearhart
//
// Copyright 2005, Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/LeakFinder.h"
#include <map>
// ======================================================================
LeakFinder::LeakFinder()
{
}
// ----------------------------------------------------------------------
LeakFinder::~LeakFinder()
{
}
// ----------------------------------------------------------------------
void LeakFinder::onAllocate(void *object)
{
ObjectData od;
od.callStack.sample();
liveObjects[object]=od;
}
// ----------------------------------------------------------------------
void LeakFinder::onFree(void *object)
{
liveObjects.erase(object);
}
// ----------------------------------------------------------------------
void LeakFinder::onReference(void *object)
{
ObjectMap::iterator oi = liveObjects.find(object);
if (oi!=liveObjects.end())
{
ObjectData &od = oi->second;
if (!od.referenceData)
{
od.referenceData = new ReferenceCountingData;
}
ReferenceCountChange rc;
rc.dir=ReferenceCountChange::up;
rc.callStack.sample();
od.referenceData->push_back(rc);
}
}
// ----------------------------------------------------------------------
void LeakFinder::onDereference(void *object)
{
ObjectMap::iterator oi = liveObjects.find(object);
if (oi!=liveObjects.end())
{
ObjectData &od = oi->second;
if (!od.referenceData)
{
od.referenceData = new ReferenceCountingData;
}
ReferenceCountChange rc;
rc.dir=ReferenceCountChange::down;
rc.callStack.sample();
od.referenceData->push_back(rc);
}
}
// ----------------------------------------------------------------------
void LeakFinder::getCurrentObjects(LiveObjectList &o_objects) const
{
o_objects.reserve(o_objects.size() + liveObjects.size());
for (ObjectMap::const_iterator oi=liveObjects.begin();oi!=liveObjects.end();++oi)
{
LiveObject lo;
lo.object=oi->first;
lo.callStack=oi->second.callStack;
lo.referenceData = oi->second.referenceData;
o_objects.push_back(lo);
}
}
// ----------------------------------------------------------------------
void LeakFinder::debugPrint() const
{
LeakFinder::LiveObjectList leaks;
getCurrentObjects(leaks);
if (!leaks.empty())
{
std::map<CallStack, std::vector<const LiveObject *> > uniques;
std::map<CallStack, std::vector<const LiveObject *> >::iterator ui;
LeakFinder::LiveObjectList::iterator li;
for (li=leaks.begin();li!=leaks.end();++li)
{
uniques[li->callStack].push_back(&(*li));
}
for (ui=uniques.begin();ui!=uniques.end();++ui)
{
bool printedRefs=false;
REPORT_PRINT(true, ("------------------------------------------------------------------------------\n"));
REPORT_PRINT(true, ("leaked objects:\n"));
size_t i;
for (i=0;i<ui->second.size();++i)
{
const ReferenceCountingData *referenceData = ui->second[i]->referenceData;
const bool printRefs = referenceData && !printedRefs;
if (i>0 && (i%10 == 0) || printRefs)
{
REPORT_PRINT(true, ("\n"));
}
REPORT_PRINT(true, ("(0x%08X) ", reinterpret_cast<int>(ui->second[i]->object)));
if (printRefs)
{
printedRefs=true;
REPORT_PRINT(true, ("\n"));
_printReferenceCountingData(*referenceData);
}
}
if (i%10!=0)
{
REPORT_PRINT(true, ("\n"));
}
REPORT_PRINT(true, ("from:\n"));
ui->first.debugPrint();
REPORT_PRINT(true, ("------------------------------------------------------------------------------\n"));
}
}
}
// ----------------------------------------------------------------------
void LeakFinder::_printReferenceCountingData(const ReferenceCountingData &history) const
{
if (history.empty())
{
REPORT_PRINT(true, ("No reference counting history.\n"));
return;
}
std::map<CallStack, int> refs;
std::map<CallStack, int> derefs;
std::list<ReferenceCountChange>::const_iterator hi;
for (hi=history.begin();hi!=history.end();++hi)
{
const ReferenceCountChange &rc = *hi;
if (rc.dir==ReferenceCountChange::up)
{
refs[rc.callStack]++;
}
else
{
derefs[rc.callStack]++;
}
}
std::map<CallStack, int>::iterator ri;
for (ri=refs.begin();ri!=refs.end();++ri)
{
REPORT_PRINT(true, ("%d Refs:\n", ri->second));
ri->first.debugPrint();
}
for (ri=derefs.begin();ri!=derefs.end();++ri)
{
REPORT_PRINT(true, ("%d De-Refs:\n", ri->second));
ri->first.debugPrint();
}
}
// ======================================================================
@@ -0,0 +1,99 @@
// ======================================================================
//
// LeakFinder.h
// bearhart
//
// Copyright 2005, Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#ifndef INCLUDED_LeakFinder_H
#define INCLUDED_LeakFinder_H
// ======================================================================
#include "sharedDebug/CallStack.h"
#include <vector>
#include <list>
#include <hash_map>
// ======================================================================
class LeakFinder
{
public:
// --------------------------------------------------------
LeakFinder();
~LeakFinder();
// --------------------------------------------------------
void clear() { liveObjects.clear(); }
void onAllocate(void *object);
void onFree(void *object);
void onReference(void *object);
void onDereference(void *object);
// --------------------------------------------------------
struct ReferenceCountChange
{
enum ChangeDirection { up, down };
ReferenceCountChange() : dir(up) {}
ChangeDirection dir;
CallStack callStack;
};
typedef std::list<ReferenceCountChange> ReferenceCountingData;
struct LiveObject
{
void *object;
CallStack callStack;
const ReferenceCountingData *referenceData;
};
typedef std::vector<LiveObject> LiveObjectList;
// --------------------------------------------------------
bool empty() const { return liveObjects.empty(); }
int size() const { return liveObjects.size(); }
void getCurrentObjects(LiveObjectList &o_objects) const;
// --------------------------------------------------------
void debugPrint() const;
protected:
void _printReferenceCountingData(const ReferenceCountingData &) const;
struct ptr_hash {
size_t operator()(void *p) const { return std::hash<unsigned long>()((unsigned long)p); }
};
struct ObjectData
{
ObjectData() : referenceData(0) { }
~ObjectData() { if (referenceData) { delete referenceData; } }
CallStack callStack;
ReferenceCountingData *referenceData;
};
typedef std::hash_map<void *, ObjectData, ptr_hash> ObjectMap;
ObjectMap liveObjects;
};
// ======================================================================
#endif
@@ -0,0 +1,505 @@
// ======================================================================
//
// PixCounter.cpp
// Copyright 2004 Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/PixCounter.h"
#if PRODUCTION == 0
#include "sharedFoundation/ExitChain.h"
#include <algorithm>
#include <vector>
// ======================================================================
#ifdef _WIN32
#define STDCALL __stdcall
#else
#define STDCALL
#endif
namespace PixCounterNamespace
{
typedef std::vector<PixCounter::Counter *> Counters;
typedef BOOL (STDCALL *SetCounterFloat)(char const * name, float * value);
typedef BOOL (STDCALL *SetCounterInt)(char const * name, int * value);
typedef BOOL (STDCALL *SetCounterInt64)(char const * name, __int64 * value);
typedef BOOL (STDCALL *SetCounterString)(char const * name, char const * const * value);
typedef void (STDCALL *PollRoutine)();
typedef void (STDCALL *ClientInstall)(bool * active, PollRoutine pollRoutine);
void remove();
void STDCALL poll();
#ifdef _WIN32
HINSTANCE ms_pixDll;
#endif
SetCounterFloat ms_setCounterFloat;
SetCounterInt ms_setCounterInt;
SetCounterInt64 ms_setCounterInt64;
SetCounterString ms_setCounterString;
Counters ms_counters;
bool ms_enabled;
bool ms_connectedToPixProfiler;
}
using namespace PixCounterNamespace;
// ======================================================================
void PixCounter::install()
{
#ifdef _WIN32
ms_pixDll = LoadLibrary("C:\\Program Files\\Microsoft DirectX 9.0 SDK (October 2004)\\Utilities\\PIX\\SoePix.PIXPlugin");
if (ms_pixDll)
{
ms_setCounterFloat = reinterpret_cast<SetCounterFloat> (GetProcAddress(ms_pixDll, "SetCounterFloat"));
ms_setCounterInt = reinterpret_cast<SetCounterInt> (GetProcAddress(ms_pixDll, "SetCounterInt"));
ms_setCounterInt64 = reinterpret_cast<SetCounterInt64> (GetProcAddress(ms_pixDll, "SetCounterInt64"));
ms_setCounterString = reinterpret_cast<SetCounterString>(GetProcAddress(ms_pixDll, "SetCounterString"));
NOT_NULL(ms_setCounterFloat);
NOT_NULL(ms_setCounterInt);
NOT_NULL(ms_setCounterInt64);
NOT_NULL(ms_setCounterString);
ClientInstall clientInstall = reinterpret_cast<ClientInstall>(GetProcAddress(ms_pixDll, "ClientInstall"));
NOT_NULL(clientInstall);
(*clientInstall)(&ms_connectedToPixProfiler, &PixCounterNamespace::poll);
ExitChain::add(PixCounterNamespace::remove, "PixCounter");
}
#endif
}
// ----------------------------------------------------------------------
void PixCounterNamespace::remove()
{
#ifdef _WIN32
FreeLibrary(ms_pixDll);
ms_pixDll = NULL;
#endif
ms_setCounterFloat = NULL;
ms_setCounterInt = NULL;
ms_setCounterInt64 = NULL;
ms_setCounterString = NULL;
// Make sure the counter memory gets freed at this point
Counters().swap(ms_counters);
}
// ----------------------------------------------------------------------
void PixCounter::enable()
{
if (!ms_enabled)
{
resetAllCounters();
ms_enabled = true;
}
}
// ----------------------------------------------------------------------
void PixCounter::disable()
{
ms_enabled = false;
resetAllCounters();
}
// ----------------------------------------------------------------------
bool PixCounter::isEnabled()
{
return ms_enabled;
}
// ----------------------------------------------------------------------
bool PixCounter::connectedToPixProfiler()
{
return ms_connectedToPixProfiler;
}
// ----------------------------------------------------------------------
void PixCounter::bindToCounter(char const * name, int * value)
{
if (ms_setCounterInt && (*ms_setCounterInt)(name, value) == false)
DEBUG_WARNING(true, ("Could not bind int pix counter %s", name));
}
// ----------------------------------------------------------------------
void PixCounter::bindToCounter(char const * name, float * value)
{
if (ms_setCounterFloat && (*ms_setCounterFloat)(name, value) == false)
DEBUG_WARNING(true, ("Could not bind float pix counter %s", name));
}
// ----------------------------------------------------------------------
void PixCounter::bindToCounter(char const * name, __int64 * value)
{
if (ms_setCounterInt64 && (*ms_setCounterInt64)(name, value) == false)
DEBUG_WARNING(true, ("Could not bind int64 pix counter %s", name));
}
// ----------------------------------------------------------------------
void PixCounter::bindToCounter(char const * name, char const * const * value)
{
if (ms_setCounterString && (*ms_setCounterString)(name, value) == false)
DEBUG_WARNING(true, ("Could not bind string pix counter %s", name));
}
// ----------------------------------------------------------------------
void PixCounter::resetAllCounters()
{
Counters::iterator const iEnd = ms_counters.end();
for (Counters::iterator i = ms_counters.begin(); i != iEnd; ++i)
(*i)->reset();
}
// ----------------------------------------------------------------------
void PixCounter::update()
{
if (!ms_connectedToPixProfiler)
poll();
}
// ----------------------------------------------------------------------
void STDCALL PixCounterNamespace::poll()
{
if (ms_enabled)
{
Counters::iterator const iEnd = ms_counters.end();
for (Counters::iterator i = ms_counters.begin(); i != iEnd; ++i)
(*i)->poll();
}
}
// ======================================================================
PixCounter::Counter::Counter()
{
}
// ----------------------------------------------------------------------
PixCounter::Counter::~Counter()
{
disable();
}
// ----------------------------------------------------------------------
void PixCounter::Counter::enable()
{
ms_counters.push_back(this);
}
// ----------------------------------------------------------------------
void PixCounter::Counter::disable()
{
Counters::iterator i = std::find(ms_counters.begin(), ms_counters.end(), this);
if (i != ms_counters.end())
ms_counters.erase(i);
}
// ======================================================================
PixCounter::Integer::Integer()
: Counter(),
m_lastFrameValue(0),
m_currentValue(0)
{
}
// ----------------------------------------------------------------------
void PixCounter::Integer::bindToCounter(char const * name)
{
PixCounter::bindToCounter(name, &m_lastFrameValue);
enable();
}
// ----------------------------------------------------------------------
void PixCounter::Integer::poll()
{
m_lastFrameValue = m_currentValue;
}
// ----------------------------------------------------------------------
void PixCounter::Integer::reset()
{
m_currentValue = 0;
}
// ----------------------------------------------------------------------
void PixCounter::Integer::operator =(int value)
{
m_currentValue = value;
}
// ----------------------------------------------------------------------
void PixCounter::Integer::operator +=(int value)
{
m_currentValue += value;
}
// ----------------------------------------------------------------------
void PixCounter::Integer::operator ++()
{
++m_currentValue;
}
// ----------------------------------------------------------------------
int PixCounter::Integer::getCurrentValue() const
{
return m_currentValue;
}
// ----------------------------------------------------------------------
int PixCounter::Integer::getLastFrameValue() const
{
return m_lastFrameValue;
}
// ======================================================================
PixCounter::ResetInteger::ResetInteger()
: Integer()
{
}
// ----------------------------------------------------------------------
void PixCounter::ResetInteger::poll()
{
Integer::poll();
reset();
}
// ======================================================================
PixCounter::Float::Float()
: Counter(),
m_lastFrameValue(0.0f),
m_currentValue(0.0f)
{
}
// ----------------------------------------------------------------------
void PixCounter::Float::bindToCounter(char const * name)
{
PixCounter::bindToCounter(name, &m_lastFrameValue);
enable();
}
// ----------------------------------------------------------------------
void PixCounter::Float::poll()
{
m_lastFrameValue = m_currentValue;
}
// ----------------------------------------------------------------------
void PixCounter::Float::reset()
{
m_currentValue = 0.0f;
}
// ----------------------------------------------------------------------
void PixCounter::Float::operator =(float value)
{
m_currentValue = value;
}
// ----------------------------------------------------------------------
void PixCounter::Float::operator +=(float value)
{
m_currentValue += value;
}
// ----------------------------------------------------------------------
float PixCounter::Float::getCurrentValue() const
{
return m_currentValue;
}
// ----------------------------------------------------------------------
float PixCounter::Float::getLastFrameValue() const
{
return m_lastFrameValue;
}
// ======================================================================
PixCounter::ResetFloat::ResetFloat()
: Float()
{
}
// ----------------------------------------------------------------------
void PixCounter::ResetFloat::poll()
{
Float::poll();
reset();
}
// ======================================================================
PixCounter::String::String()
: Counter(),
m_enabled(false),
m_lastFrameValue(),
m_lastFrameValuePointer(NULL),
m_currentValue()
{
}
// ----------------------------------------------------------------------
void PixCounter::String::bindToCounter(char const * name)
{
PixCounter::bindToCounter(name, &m_lastFrameValuePointer);
enable();
}
// ----------------------------------------------------------------------
void PixCounter::String::poll()
{
m_lastFrameValue = m_currentValue;
m_lastFrameValuePointer = &(m_lastFrameValue.c_str()[0]);
}
// ----------------------------------------------------------------------
void PixCounter::String::pollAndReset()
{
m_lastFrameValue.swap(m_currentValue);
m_currentValue.clear();
m_lastFrameValuePointer = &(m_lastFrameValue.c_str()[0]);
}
// ----------------------------------------------------------------------
void PixCounter::String::reset()
{
m_currentValue.clear();
}
// ----------------------------------------------------------------------
void PixCounter::String::enable()
{
Counter::enable();
m_enabled = true;
}
// ----------------------------------------------------------------------
void PixCounter::String::disable()
{
Counter::disable();
m_enabled = false;
m_lastFrameValue.clear();
m_currentValue.clear();
}
// ----------------------------------------------------------------------
void PixCounter::String::operator =(const char * value)
{
if (ms_enabled && m_enabled)
m_currentValue = value;
}
// ----------------------------------------------------------------------
void PixCounter::String::operator +=(const char * value)
{
if (ms_enabled && m_enabled)
m_currentValue += value;
}
// ----------------------------------------------------------------------
void PixCounter::String::set(const char * format, ...)
{
if (ms_enabled && m_enabled)
{
va_list va;
va_start(va, format);
char buffer[512];
vsnprintf(buffer, sizeof(buffer), format, va);
buffer[sizeof(buffer-1)] = '\0';
operator =(buffer);
va_end(va);
}
}
// ----------------------------------------------------------------------
void PixCounter::String::append(const char * format, ...)
{
if (ms_enabled && m_enabled)
{
va_list va;
va_start(va, format);
char buffer[512];
vsnprintf(buffer, sizeof(buffer), format, va);
buffer[sizeof(buffer)-1] = '\0';
operator +=(buffer);
va_end(va);
}
}
// ======================================================================
PixCounter::ResetString::ResetString()
: String()
{
}
// ----------------------------------------------------------------------
void PixCounter::ResetString::poll()
{
String::pollAndReset();
}
// ======================================================================
#endif
@@ -0,0 +1,184 @@
// ======================================================================
//
// PixCounter.h
// Copyright 2004, Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#ifndef INCLUDED_PixCounter_H
#define INCLUDED_PixCounter_H
// ======================================================================
#include "sharedFoundation/Production.h"
#include <string>
// ======================================================================
#if PRODUCTION == 0
class PixCounter
{
public:
/// Base class for all other counters
class Counter
{
public:
Counter();
virtual ~Counter();
virtual void poll() = 0;
virtual void reset() = 0;
virtual void enable();
virtual void disable();
private:
Counter(Counter const &);
Counter & operator = (Counter const &);
};
/// General integer counter
class Integer : public Counter
{
public:
Integer();
void bindToCounter(char const * name);
virtual void poll();
virtual void reset();
void operator =(int value);
void operator +=(int value);
void operator ++();
int getCurrentValue() const;
int getLastFrameValue() const;
private:
Integer(Integer const &);
Integer & operator = (Integer const &);
private:
int m_lastFrameValue;
int m_currentValue;
};
/// Integer counter whose value gets reset to 0 immediately after being polled
class ResetInteger : public Integer
{
public:
ResetInteger();
virtual void poll();
private:
ResetInteger(ResetInteger const &);
ResetInteger & operator = (ResetInteger const &);
};
/// General float counter
class Float : public Counter
{
public:
Float();
void bindToCounter(char const * name);
virtual void poll();
virtual void reset();
void operator =(float value);
void operator +=(float value);
float getCurrentValue() const;
float getLastFrameValue() const;
private:
Float(Float const &);
Float & operator = (Float const &);
private:
float m_lastFrameValue;
float m_currentValue;
};
/// Float counter whose value gets reset to 0 immediately after being polled
class ResetFloat : public Float
{
public:
ResetFloat();
virtual void poll();
private:
ResetFloat(ResetFloat const &);
ResetFloat & operator = (ResetFloat const &);
};
/// General string counter
class String : public Counter
{
public:
String();
void bindToCounter(char const * name);
virtual void poll();
virtual void reset();
virtual void enable();
virtual void disable();
void operator =(const char * value);
void operator +=(const char * value);
void set(const char * format, ...);
void append(const char * format, ...);
private:
String(String const &);
String & operator = (String const &);
protected:
void pollAndReset();
private:
bool m_enabled;
std::string m_lastFrameValue;
char const * m_lastFrameValuePointer;
std::string m_currentValue;
};
/// String counter whose value gets reset to "" immediately after being polled
class ResetString : public String
{
public:
ResetString();
virtual void poll();
private:
ResetString(ResetString const &);
ResetString & operator = (ResetString const &);
};
public:
static void install();
static void update();
static void enable();
static void disable();
static bool isEnabled();
static bool connectedToPixProfiler();
static void resetAllCounters();
static void bindToCounter(char const * name, int * value);
static void bindToCounter(char const * name, float * value);
static void bindToCounter(char const * name, __int64 * value);
static void bindToCounter(char const * name, char const * const * value);
};
#endif
// ======================================================================
#endif
@@ -0,0 +1,874 @@
// ======================================================================
//
// Profiler.cpp
//
// Copyright 2003 Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/Profiler.h"
#include "sharedDebug/DebugFlags.h"
#include "sharedDebug/DebugKey.h"
#include "sharedDebug/ProfilerTimer.h"
#include "sharedFoundation/ConfigFile.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedFoundation/MemoryBlockManager.h"
#include "sharedFoundation/MemoryBlockManagerMacros.h"
#include <vector>
#include <algorithm>
// ======================================================================
namespace ProfilerNamespace
{
struct ProfilerEntry
{
typedef std::vector<int> Children;
const char *name;
int parent;
Children children;
int totalCalls;
ProfilerTimer::Type totalTime;
};
class VisibleExpandableEntry
{
public:
VisibleExpandableEntry(char const * name);
~VisibleExpandableEntry();
char const * getName() const;
bool isExpanded() const;
void setExpanded(bool opened);
void toggleExpanded();
void markAllChildrenInvisible();
VisibleExpandableEntry * findOrAddExpandableChild(char const *name);
bool pruneInvisibleChildren();
private:
typedef std::vector<VisibleExpandableEntry *> Children;
private:
static bool ms_destroyedSelected;
private:
char const * m_name;
Children m_children;
bool m_expanded;
bool m_visible;
};
typedef std::vector<ProfilerEntry> ProfilerEntries;
typedef std::vector<ProfilerEntry *> SortedProfilerEntries;
struct SortMultisiteEntries
{
bool operator()(ProfilerEntry const * lhs, ProfilerEntry const * rhs) const;
};
void formatInteger(int length, int value);
void formatString(const char *string);
bool formatEntry(int indent, ProfilerTimer::Type totalTime, int totalCalls, bool expandable, bool expanded, bool selected, char const *name);
void processEntry(char const *rootName, int indent, ProfilerEntry const & entry, VisibleExpandableEntry * opened);
void enterWithTime(char const *name, ProfilerTimer::Type time);
void leaveWithTime(char const *name, ProfilerTimer::Type time);
void generateReport();
bool myCompare(const char *a, const char *b);
std::vector<int> ms_profilerEntryStack;
ProfilerEntries * ms_profilerEntriesCurrent;
ProfilerEntries * ms_profilerEntriesLast;
ProfilerEntries ms_profilerEntries1;
ProfilerEntries ms_profilerEntries2;
char const * ms_rootProfilerName;
VisibleExpandableEntry * ms_rootVisibleExpandableEntry;
VisibleExpandableEntry * ms_beforeSelectedVisibleExpandableEntry;
VisibleExpandableEntry * ms_selectedVisibleExpandableEntry;
VisibleExpandableEntry * ms_afterSelectedVisibleExpandableEntry;
VisibleExpandableEntry * ms_previousVisibleExpandableEntry;
std::vector<char> ms_text;
ProfilerTimer::Type ms_timeDivisor;
ProfilerTimer::Type ms_percentageDivisor;
ProfilerTimer::Type ms_frequency;
bool ms_enabled = true;
bool ms_desiredEnabled = true;
bool ms_debugKeyContext;
bool ms_debugReportFlag;
bool ms_debugReportLogFlag;
bool ms_temporaryExpandAll;
bool ms_multisiteCallerSummary;
bool ms_setRoot;
bool ms_selectedUp;
bool ms_selectedDown;
bool ms_selectedExpand;
bool ms_selectedCollapse;
bool ms_selectedToggle;
int ms_displayPercentageMinimum;
int ms_stackDepth;
SortedProfilerEntries ms_sortedProfilerEntries;
}
using namespace ProfilerNamespace;
bool VisibleExpandableEntry::ms_destroyedSelected;
// ======================================================================
VisibleExpandableEntry::VisibleExpandableEntry(char const * name)
:
m_name(name),
m_children(),
m_expanded(false),
m_visible(true)
{
}
// ----------------------------------------------------------------------
VisibleExpandableEntry::~VisibleExpandableEntry()
{
// handle case where the selected item gets deleted
if (this == ms_selectedVisibleExpandableEntry)
ms_destroyedSelected = true;
while (!m_children.empty())
{
VisibleExpandableEntry *back = m_children.back();
m_children.pop_back();
delete back;
}
}
// ----------------------------------------------------------------------
inline char const * VisibleExpandableEntry::getName() const
{
return m_name;
}
// ----------------------------------------------------------------------
inline bool VisibleExpandableEntry::isExpanded() const
{
return m_expanded || ms_temporaryExpandAll;
}
// ----------------------------------------------------------------------
inline void VisibleExpandableEntry::setExpanded(bool expanded)
{
m_expanded = expanded;
}
// ----------------------------------------------------------------------
inline void VisibleExpandableEntry::toggleExpanded()
{
m_expanded = !m_expanded;
}
// ----------------------------------------------------------------------
void VisibleExpandableEntry::markAllChildrenInvisible()
{
Children::iterator const iEnd = m_children.end();
for (Children::iterator i = m_children.begin(); i != iEnd; ++i)
(*i)->m_visible = false;
}
// ----------------------------------------------------------------------
VisibleExpandableEntry * VisibleExpandableEntry::findOrAddExpandableChild(char const *name)
{
Children::iterator const iEnd = m_children.end();
for (Children::iterator i = m_children.begin(); i != iEnd; ++i)
{
VisibleExpandableEntry * child = *i;
if (child->m_name == name)
{
child->m_visible = true;
return child;
}
}
m_children.push_back(new VisibleExpandableEntry(name));
return m_children.back();
}
// ----------------------------------------------------------------------
bool VisibleExpandableEntry::pruneInvisibleChildren()
{
for (Children::iterator i = m_children.begin(); i != m_children.end(); )
if ((*i)->m_visible == false)
{
delete *i;
m_children.erase(i);
}
else
++i;
bool const result = ms_destroyedSelected;
ms_destroyedSelected = false;
return result;
}
// ======================================================================
void Profiler::install()
{
ExitChain::add(Profiler::remove, "Profiler::remove");
ms_profilerEntriesCurrent = &ms_profilerEntries1;
ms_profilerEntriesLast = &ms_profilerEntries2;
ms_rootVisibleExpandableEntry = new VisibleExpandableEntry(NULL);
ms_rootVisibleExpandableEntry->setExpanded(true);
ms_selectedVisibleExpandableEntry = ms_rootVisibleExpandableEntry;
}
// ----------------------------------------------------------------------
void Profiler::remove()
{
delete ms_rootVisibleExpandableEntry;
ms_rootVisibleExpandableEntry = NULL;
ms_beforeSelectedVisibleExpandableEntry = NULL;
ms_selectedVisibleExpandableEntry = NULL;
ms_afterSelectedVisibleExpandableEntry = NULL;
ms_previousVisibleExpandableEntry = NULL;
ms_profilerEntriesCurrent = NULL;
ms_profilerEntriesLast = NULL;
}
// ----------------------------------------------------------------------
void Profiler::registerDebugFlags()
{
DebugKey::registerFlag(ms_debugKeyContext, "profiler");
DebugFlags::registerFlag(ms_debugReportFlag, "SharedDebug/Profiler", "report", printLastFrameData);
DebugFlags::registerFlag(ms_desiredEnabled, "SharedDebug/Profiler", "enabled");
DebugFlags::registerFlag(ms_debugReportLogFlag, "SharedDebug/Profiler", "logNextReport");
DebugFlags::registerFlag(ms_temporaryExpandAll, "SharedDebug/Profiler", "temporaryExpandAll");
ms_displayPercentageMinimum = ConfigFile::getKeyInt("SharedDebug/Profiler", "displayPercentageMinimum", 0);
}
// ----------------------------------------------------------------------
void Profiler::enable(bool enable)
{
ms_desiredEnabled = enable;
}
// ----------------------------------------------------------------------
void Profiler::enableProfilerOutput(bool enableOutput)
{
ms_debugReportFlag = enableOutput;
}
// ----------------------------------------------------------------------
void ProfilerNamespace::formatInteger(int length, int value)
{
// pad with spaces
for (int i = 0; i < length; ++i)
ms_text.push_back(' ');
// get a pointer to the last character
char *buffer = &ms_text[ms_text.size()-1];
// write the value right to left
do
{
*buffer = static_cast<char>('0' + (value % 10));
--length;
--buffer;
value /= 10;
} while (length && value);
}
// ----------------------------------------------------------------------
void ProfilerNamespace::formatString(char const *string)
{
for ( ; *string; ++string)
ms_text.push_back(*string);
}
// ----------------------------------------------------------------------
bool ProfilerNamespace::formatEntry(int indent, ProfilerTimer::Type totalTime, int totalCalls, bool expandable, bool expanded, bool selected, char const * name)
{
int const percentage = static_cast<int>(totalTime / ms_percentageDivisor);
if (percentage < ms_displayPercentageMinimum)
return false;
int const ticks = static_cast<int>(totalTime / ms_timeDivisor);
// indent
{
for (int i = 0; i < indent; ++i)
ms_text.push_back(' ');
}
// print number of ticks
formatInteger(7, ticks);
ms_text.push_back(' ');
// pring % of frame time
formatInteger(3, percentage);
ms_text.push_back('%');
ms_text.push_back(' ');
// print the number of calls
formatInteger(8, totalCalls);
ms_text.push_back(' ');
if (expandable)
{
// print the expanded state
if (expanded)
ms_text.push_back('-');
else
ms_text.push_back('+');
// print the selection marker
if (selected)
ms_text.push_back('>');
else
ms_text.push_back(' ');
}
else
{
ms_text.push_back(' ');
ms_text.push_back(' ');
}
// print the entry name
formatString(name);
ms_text.push_back('\n');
return true;
}
// ----------------------------------------------------------------------
void ProfilerNamespace::processEntry(char const *rootName, int indent, ProfilerEntry const & entry, VisibleExpandableEntry * visibleExpandableEntry)
{
if (rootName == entry.name)
rootName = NULL;
if (!rootName)
{
if (!formatEntry(indent, entry.totalTime, entry.totalCalls, visibleExpandableEntry != NULL, visibleExpandableEntry && visibleExpandableEntry->isExpanded(), visibleExpandableEntry == ms_selectedVisibleExpandableEntry, entry.name))
return;
}
if (visibleExpandableEntry)
{
// keep track of before and after the selected entry
if (ms_selectedVisibleExpandableEntry == visibleExpandableEntry)
ms_beforeSelectedVisibleExpandableEntry = ms_previousVisibleExpandableEntry;
if (!entry.children.empty())
{
if (ms_previousVisibleExpandableEntry == ms_selectedVisibleExpandableEntry)
ms_afterSelectedVisibleExpandableEntry = visibleExpandableEntry;
ms_previousVisibleExpandableEntry = visibleExpandableEntry;
}
// process the children
visibleExpandableEntry->markAllChildrenInvisible();
// indent if we have already seen the root
if (!rootName)
indent += 2;
if (visibleExpandableEntry->isExpanded())
{
ProfilerEntry::Children::const_iterator iEnd = entry.children.end();
for (ProfilerEntry::Children::const_iterator i = entry.children.begin(); i != iEnd; ++i)
{
ProfilerEntry const & child = (*ms_profilerEntriesLast)[*i];
if (child.children.empty())
{
processEntry(rootName, indent, child, NULL);
}
else
{
VisibleExpandableEntry * childVisibleExpandableEntry = visibleExpandableEntry->findOrAddExpandableChild(child.name);
processEntry(rootName, indent, child, childVisibleExpandableEntry);
}
}
}
if (visibleExpandableEntry->pruneInvisibleChildren())
ms_selectedVisibleExpandableEntry = visibleExpandableEntry;
}
}
// ----------------------------------------------------------------------
inline bool SortMultisiteEntries::operator()(ProfilerEntry const * lhs, ProfilerEntry const * rhs) const
{
return lhs->name < rhs->name;
}
// ----------------------------------------------------------------------
void ProfilerNamespace::generateReport()
{
PROFILER_AUTO_BLOCK_DEFINE("Profiler::generateReport");
if (!ms_profilerEntriesLast->empty())
{
if (ms_debugKeyContext)
{
if (DebugKey::isPressed(1))
ms_desiredEnabled = !ms_desiredEnabled;
if (DebugKey::isPressed(2))
ms_debugReportLogFlag = true;
if (DebugKey::isPressed(3))
ms_temporaryExpandAll = !ms_temporaryExpandAll;
if (DebugKey::isPressed(4))
ms_setRoot = true;
if (DebugKey::isPressed(5))
ms_multisiteCallerSummary = !ms_multisiteCallerSummary;
if (DebugKey::isPressed(6))
ms_displayPercentageMinimum = clamp(0, ms_displayPercentageMinimum - 1, 100);
if (DebugKey::isPressed(7))
ms_displayPercentageMinimum = clamp(0, ms_displayPercentageMinimum + 1, 100);
if (DebugKey::isPressed(8))
Profiler::selectionMoveUp();
if (DebugKey::isPressed(9))
Profiler::selectionMoveDown();
if (DebugKey::isPressed(0))
Profiler::selectionToggleExpanded();
}
// try to get the ticks to approximately 1 million per second
ms_timeDivisor = ms_frequency / static_cast<ProfilerTimer::Type>(1000000);
if (ms_timeDivisor == 0)
ms_timeDivisor = 1;
// figure out what to divide by to get the value in percent of total frame time
ms_percentageDivisor = (*ms_profilerEntriesLast)[0].totalTime / static_cast<ProfilerTimer::Type>(100);
if (ms_percentageDivisor == 0)
ms_percentageDivisor = 1;
formatString("Profiler (min ");
formatInteger(3, ms_displayPercentageMinimum);
formatString("%):\n");
ProfilerEntry const & rootEntry = (*ms_profilerEntriesLast)[0];
ms_rootVisibleExpandableEntry->markAllChildrenInvisible();
ms_rootVisibleExpandableEntry->findOrAddExpandableChild(rootEntry.name);
ms_previousVisibleExpandableEntry = NULL;
ms_beforeSelectedVisibleExpandableEntry = NULL;
ms_afterSelectedVisibleExpandableEntry = NULL;
processEntry(ms_rootProfilerName, 0, rootEntry, ms_rootVisibleExpandableEntry);
if (ms_rootVisibleExpandableEntry->pruneInvisibleChildren())
ms_selectedVisibleExpandableEntry = ms_rootVisibleExpandableEntry;
if (ms_setRoot)
{
if (ms_rootProfilerName)
ms_rootProfilerName = NULL;
else
ms_rootProfilerName = ms_selectedVisibleExpandableEntry->getName();
ms_setRoot = false;
}
if (ms_selectedUp)
{
if (ms_beforeSelectedVisibleExpandableEntry)
ms_selectedVisibleExpandableEntry = ms_beforeSelectedVisibleExpandableEntry;
ms_selectedUp = false;
}
if (ms_selectedDown)
{
if (ms_afterSelectedVisibleExpandableEntry)
ms_selectedVisibleExpandableEntry = ms_afterSelectedVisibleExpandableEntry;
ms_selectedDown = false;
}
if (ms_selectedExpand)
{
ms_selectedVisibleExpandableEntry->setExpanded(true);
ms_selectedExpand= false;
}
if (ms_selectedCollapse)
{
ms_selectedVisibleExpandableEntry->setExpanded(false);
ms_selectedCollapse = false;
}
if (ms_selectedToggle)
{
ms_selectedVisibleExpandableEntry->toggleExpanded();
ms_selectedToggle = false;
}
}
if (ms_multisiteCallerSummary)
{
// generate a vector of all entries
{
ms_sortedProfilerEntries.clear();
ProfilerEntries::iterator const iEnd = ms_profilerEntriesLast->end();
for (ProfilerEntries::iterator i = ms_profilerEntriesLast->begin(); i != iEnd; ++i)
ms_sortedProfilerEntries.push_back(&(*i));
}
// sort them by name
std::sort(ms_sortedProfilerEntries.begin(), ms_sortedProfilerEntries.end(), SortMultisiteEntries());
// find multiple entries with the same name
{
formatString("Multisite entries:\n");
SortedProfilerEntries::iterator i = ms_sortedProfilerEntries.begin();
SortedProfilerEntries::iterator const iEnd = ms_sortedProfilerEntries.end();
do
{
char const * const iName = (*i)->name;
SortedProfilerEntries::iterator j = i + 1;
bool display = false;
int totalCalls = (*i)->totalCalls;
ProfilerTimer::Type totalTime = (*i)->totalTime;
// find the span of entries with the same name
while (j != iEnd && iName == (*j)->name)
{
display = true;
totalCalls += (*j)->totalCalls;
totalTime += (*j)->totalTime;
++j;
}
// if the name had multiple entries, report so here
if (display)
formatEntry(2, totalTime, totalCalls, false, false, false, iName);
i = j;
} while (i != iEnd);
}
}
ms_text.push_back('\0');
}
// ----------------------------------------------------------------------
char const *Profiler::getLastFrameData()
{
if (ms_text.empty())
generateReport();
return &(ms_text[0]);
}
// ----------------------------------------------------------------------
void Profiler::printLastFrameData()
{
if (ms_text.empty())
generateReport();
Report::setFlags(Report::RF_print | (ms_debugReportLogFlag ? Report::RF_log : 0));
Report::puts(&ms_text[0]);
ms_debugReportLogFlag = false;
}
// ----------------------------------------------------------------------
void Profiler::selectionMoveUp()
{
ms_selectedUp = true;
}
// ----------------------------------------------------------------------
void Profiler::selectionMoveDown()
{
ms_selectedDown = true;
}
// ----------------------------------------------------------------------
void Profiler::selectionExpand()
{
ms_selectedExpand = true;
}
// ----------------------------------------------------------------------
void Profiler::selectionCollapse()
{
ms_selectedCollapse = true;
}
// ----------------------------------------------------------------------
void Profiler::selectionToggleExpanded()
{
ms_selectedToggle = true;
}
// ----------------------------------------------------------------------
void Profiler::setTemporaryExpandAll(bool temporaryExpandAll)
{
ms_temporaryExpandAll = temporaryExpandAll;
}
// ----------------------------------------------------------------------
void Profiler::setDisplayPercentageMinimum(int percentage)
{
ms_displayPercentageMinimum = percentage;
}
// ----------------------------------------------------------------------
bool ProfilerNamespace::myCompare(const char *a, const char *b)
{
while (*a && *b && tolower(*a) == tolower(*b))
{
++a;
++b;
}
return *a == '\0';
}
// ----------------------------------------------------------------------
void Profiler::handleOperation(char const *operation)
{
if (_stricmp(operation, "up") == 0)
selectionMoveUp();
else if (_stricmp(operation, "down") == 0)
selectionMoveDown();
else if (_stricmp(operation, "toggle") == 0)
selectionToggleExpanded();
else if (_stricmp(operation, "expand") == 0)
selectionExpand();
else if (_stricmp(operation, "collapse") == 0)
selectionCollapse();
else if (_stricmp(operation, "enable") == 0)
enable(true);
else if (_stricmp(operation, "disable") == 0)
enable(false);
else if (_stricmp(operation, "enableOutput") == 0)
enableProfilerOutput(true);
else if (_stricmp(operation, "disableOutput") == 0)
enableProfilerOutput(false);
else if (_stricmp(operation, "showAll") == 0)
setTemporaryExpandAll(true);
else if (_stricmp(operation, "showNormal") == 0)
setTemporaryExpandAll(false);
else if (myCompare("displayMinimum", operation))
{
const char *result = strchr(operation, ' ');
if (result)
ms_displayPercentageMinimum = atoi(result+1);
}
}
// ----------------------------------------------------------------------
void ProfilerNamespace::enterWithTime(char const *name, ProfilerTimer::Type time)
{
if (ms_stackDepth == 0)
{
ms_enabled = ms_desiredEnabled;
if (!ms_enabled)
{
ms_text.clear();
ms_text.push_back('\0');
}
}
++ms_stackDepth;
if (!ms_enabled)
return;
// search for another call to this block from the parent
int entryIndex = -1;
ProfilerEntry *entry = NULL;
if (!ms_profilerEntryStack.empty())
{
ProfilerEntry &parent = (*ms_profilerEntriesCurrent)[ms_profilerEntryStack.back()];
ProfilerEntry::Children::iterator iEnd = parent.children.end();
for (ProfilerEntry::Children::iterator i = parent.children.begin(); i != iEnd; ++i)
{
entryIndex = *i;
ProfilerEntry &check = (*ms_profilerEntriesCurrent)[entryIndex];
if (check.name == name)
{
entry = &check;
break;
}
}
}
// no previous call to this block, so create a new entry
if (!entry)
{
entryIndex = ms_profilerEntriesCurrent->size();
ms_profilerEntriesCurrent->push_back(ProfilerEntry());
entry = &ms_profilerEntriesCurrent->back();
entry->name = name;
if (ms_profilerEntryStack.empty())
{
entry->parent = -1;
}
else
{
entry->parent = ms_profilerEntryStack.back();
(*ms_profilerEntriesCurrent)[entry->parent].children.push_back(entryIndex);
}
entry->totalCalls = 0;
entry->totalTime = 0;
}
// record the profiling time
entry->totalCalls += 1;
entry->totalTime -= time;
ms_profilerEntryStack.push_back(entryIndex);
}
// ----------------------------------------------------------------------
void ProfilerNamespace::leaveWithTime(char const *name, ProfilerTimer::Type time)
{
if (!ms_enabled)
return;
UNREF(name);
if (ms_profilerEntryStack.empty())
{
WARNING(true, ("Profiler::leave stack underflow leaving %s", name));
return;
}
--ms_stackDepth;
// pop the current entry off the stack
ProfilerEntry &entry= (*ms_profilerEntriesCurrent)[ms_profilerEntryStack.back()];
ms_profilerEntryStack.pop_back();
DEBUG_FATAL(entry.name != name, ("Profiler::leave exiting '%s' but expected '%s'", name, entry.name));
// record the time in the entry
if (ms_profilerEntryStack.empty())
{
// get the calibrated loop end time
ProfilerTimer::getCalibratedTime(time, ms_frequency);
entry.totalTime += time;
// clear the text so we know the profile data must be regenerated if it is desired
ms_text.clear();
// swap the pointers
std::vector<ProfilerEntry> * temp = ms_profilerEntriesCurrent;
ms_profilerEntriesCurrent = ms_profilerEntriesLast;
ms_profilerEntriesLast = temp;
// clear the entries for next frame
ms_profilerEntriesCurrent->clear();
}
else
{
entry.totalTime += time;
}
}
// ----------------------------------------------------------------------
void Profiler::enter(char const *name)
{
ProfilerTimer::Type time;
ProfilerTimer::getTime(time);
enterWithTime(name, time);
}
// ----------------------------------------------------------------------
void Profiler::leave(char const *name)
{
ProfilerTimer::Type time;
ProfilerTimer::getTime(time);
leaveWithTime(name, time);
}
// ----------------------------------------------------------------------
void Profiler::transfer(char const *leaveName, char const *enterName)
{
ProfilerTimer::Type time;
ProfilerTimer::getTime(time);
leaveWithTime(leaveName, time);
enterWithTime(enterName, time);
}
// ----------------------------------------------------------------------
void Profiler::adjustForLostBlocks(char const *expectingName)
{
// This deals with cases where we've either missed closing a block or closed a block that wasn't open.
// We prefer to guess that we've failed to close a block, since that is the more common mistake, before
// trying to deal with it as though a block was closed but not opened.
if (!ms_profilerEntryStack.empty())
{
// if everything is correct, the back entry will be the expected one, so we don't have to do anything
if ((*ms_profilerEntriesCurrent)[ms_profilerEntryStack.back()].name == expectingName)
return;
for (int i = ms_profilerEntryStack.size()-2; i >= 0; --i)
{
if ((*ms_profilerEntriesCurrent)[ms_profilerEntryStack[i]].name == expectingName)
{
// we've got unclosed blocks, so close them
for (int j = ms_profilerEntryStack.size()-1; j > i; --j)
{
DEBUG_WARNING(true, ("Profiler adjusting for unclosed block '%s'.", (*ms_profilerEntriesCurrent)[ms_profilerEntryStack[j]].name));
PROFILER_BLOCK_DEFINE(p, (*ms_profilerEntriesCurrent)[ms_profilerEntryStack[j]].name);
PROFILER_BLOCK_LEAVE(p);
}
return;
}
}
}
DEBUG_WARNING(true, ("Profiler adjusting for unopened block '%s'.", expectingName));
// we're about to close a block that was not open, so open it
PROFILER_BLOCK_DEFINE(p, expectingName);
PROFILER_BLOCK_ENTER(p);
}
// ======================================================================
@@ -0,0 +1,287 @@
// ======================================================================
//
// Profiler.h
//
// Copyright 2003 Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#ifndef INCLUDED_Profiler_H
#define INCLUDED_Profiler_H
// ======================================================================
#include "sharedFoundation/Production.h"
// ======================================================================
class ProfilerBlock
{
public:
ProfilerBlock(char const *name);
void enter();
void leave();
void transfer(char const *newName);
void adjustForLostBlocks();
private:
ProfilerBlock();
ProfilerBlock(ProfilerBlock const &);
ProfilerBlock & operator =(ProfilerBlock const &);
private:
char const * m_name;
};
// ----------------------------------------------------------------------
class ProfilerAutoBlock
{
public:
ProfilerAutoBlock(char const *name);
~ProfilerAutoBlock();
void transfer(char const *newName);
private:
ProfilerAutoBlock();
ProfilerAutoBlock(ProfilerAutoBlock const &);
ProfilerAutoBlock & operator =(ProfilerAutoBlock const &);
private:
ProfilerBlock m_profilerBlock;
};
// ----------------------------------------------------------------------
class ProfilerAutoBlockCheck
{
public:
ProfilerAutoBlockCheck(char const *name);
~ProfilerAutoBlockCheck();
void transfer(char const *newName);
private:
ProfilerAutoBlockCheck();
ProfilerAutoBlockCheck(ProfilerAutoBlockCheck const &);
ProfilerAutoBlockCheck & operator =(ProfilerAutoBlockCheck const &);
private:
ProfilerBlock m_profilerBlock;
};
//----------------------------------------------------------------------
class CuiManager;
// ----------------------------------------------------------------------
class Profiler
{
friend class ProfilerBlock;
friend class CuiManager;
public:
static void install();
static void remove();
static void registerDebugFlags();
static void enable(bool enabled);
static void enableProfilerOutput(bool enabled);
static char const *getLastFrameData();
static void printLastFrameData();
static void selectionMoveUp();
static void selectionMoveDown();
static void selectionExpand();
static void selectionCollapse();
static void selectionToggleExpanded();
static void setTemporaryExpandAll(bool temporaryExpandAll);
static void setDisplayPercentageMinimum(int percentage);
static void handleOperation(char const *operation);
private:
static void DLLEXPORT enter(char const *name);
static void DLLEXPORT leave(char const *name);
static void DLLEXPORT transfer(char const *leaveName, char const *enterName);
static void adjustForLostBlocks(char const *nextName);
};
// ======================================================================
inline ProfilerBlock::ProfilerBlock(const char *name)
:
m_name(name)
{
}
// ----------------------------------------------------------------------
inline void ProfilerBlock::enter()
{
Profiler::enter(m_name);
}
// ----------------------------------------------------------------------
inline void ProfilerBlock::leave()
{
Profiler::leave(m_name);
}
// ----------------------------------------------------------------------
inline void ProfilerBlock::transfer(char const *name)
{
Profiler::transfer(m_name, name);
m_name = name;
}
// ----------------------------------------------------------------------
inline void ProfilerBlock::adjustForLostBlocks()
{
Profiler::adjustForLostBlocks(m_name);
}
// ======================================================================
inline ProfilerAutoBlock::ProfilerAutoBlock(char const *name)
:
m_profilerBlock(name)
{
m_profilerBlock.enter();
}
// ----------------------------------------------------------------------
inline ProfilerAutoBlock::~ProfilerAutoBlock()
{
m_profilerBlock.leave();
}
// ----------------------------------------------------------------------
inline void ProfilerAutoBlock::transfer(char const *name)
{
m_profilerBlock.transfer(name);
}
// ======================================================================
inline ProfilerAutoBlockCheck::ProfilerAutoBlockCheck(char const *name)
:
m_profilerBlock(name)
{
m_profilerBlock.enter();
}
// ----------------------------------------------------------------------
inline ProfilerAutoBlockCheck::~ProfilerAutoBlockCheck()
{
m_profilerBlock.adjustForLostBlocks();
m_profilerBlock.leave();
}
// ----------------------------------------------------------------------
inline void ProfilerAutoBlockCheck::transfer(char const *name)
{
m_profilerBlock.transfer(name);
}
// ======================================================================
#if defined(_DEBUG) || defined(PLATFORM_LINUX)
#define PROFILER_BLOCK_DEFINE(a, b) ProfilerBlock a ( b )
#define PROFILER_BLOCK_ENTER(a) a.enter()
#define PROFILER_BLOCK_LEAVE(a) a.leave()
#define PROFILER_BLOCK_TRANSFER(a,b) a.transfer(b)
#define PROFILER_BLOCK_LOST_CHECK(a) a.adjustForLostBlocks()
#define PABD_PASTE(a,b) a##b
#define PABD_XPASTE(a,b) PABD_PASTE(a,b)
#define PROFILER_AUTO_BLOCK_DEFINE(a) ProfilerAutoBlock PABD_XPASTE(profilerAutoBlock, __LINE__) ( a )
#define PROFILER_AUTO_BLOCK_CHECK_DEFINE(a) ProfilerAutoBlockCheck PABD_XPASTE(profilerAutoBlockCheck, __LINE__) ( a )
#define PROFILER_NAMED_AUTO_BLOCK_DEFINE(a,b) ProfilerAutoBlock a ( b )
#define PROFILER_NAMED_AUTO_BLOCK_TRANSFER(a,b) a.transfer(b)
#define PROFILER_GET_LAST_FRAME_DATA() Profiler::getLastFrameData()
#else
#define PROFILER_BLOCK_DEFINE(a, b)
#define PROFILER_BLOCK_CHECK_DEFINE(a, b)
#define PROFILER_BLOCK_ENTER(a) NOP
#define PROFILER_BLOCK_LEAVE(a) NOP
#define PROFILER_BLOCK_TRANSFER(a,b) NOP
#define PROFILER_BLOCK_LOST_CHECK(a) NOP
#define PROFILER_AUTO_BLOCK_DEFINE(A) NOP
#define PROFILER_AUTO_BLOCK_CHECK_DEFINE(a) NOP
#define PROFILER_NAMED_AUTO_BLOCK_DEFINE(a,b)
#define PROFILER_NAMED_AUTO_BLOCK_TRANSFER(a,b) NOP
#define PROFILER_GET_LAST_FRAME_DATA() ""
#endif
// ======================================================================
// Macro functions that stick around for all non-production builds.
// [NP = no/non-production]
// ======================================================================
#if (PRODUCTION == 0)
#define NP_PROFILER_BLOCK_DEFINE(a, b) ProfilerBlock a ( b )
#define NP_PROFILER_BLOCK_ENTER(a) a.enter()
#define NP_PROFILER_BLOCK_LEAVE(a) a.leave()
#define NP_PROFILER_BLOCK_TRANSFER(a,b) a.transfer(b)
#define NP_PROFILER_BLOCK_LOST_CHECK(a) a.adjustForLostBlocks()
#define NP_PABD_PASTE(a,b) a##b
#define NP_PABD_XPASTE(a,b) NP_PABD_PASTE(a,b)
#define NP_PROFILER_AUTO_BLOCK_DEFINE(a) ProfilerAutoBlock NP_PABD_XPASTE(profilerAutoBlock, __LINE__) ( a )
#define NP_PROFILER_AUTO_BLOCK_CHECK_DEFINE(a) ProfilerAutoBlockCheck NP_PABD_XPASTE(profilerAutoBlockCheck, __LINE__) ( a )
#define NP_PROFILER_NAMED_AUTO_BLOCK_DEFINE(a,b) ProfilerAutoBlock a ( b )
#define NP_PROFILER_NAMED_AUTO_BLOCK_TRANSFER(a,b) a.transfer(b)
#define NP_PROFILER_GET_LAST_FRAME_DATA() Profiler::getLastFrameData()
#else
#define NP_PROFILER_BLOCK_DEFINE(a, b)
#define NP_PROFILER_BLOCK_CHECK_DEFINE(a, b)
#define NP_PROFILER_BLOCK_ENTER(a) NOP
#define NP_PROFILER_BLOCK_LEAVE(a) NOP
#define NP_PROFILER_BLOCK_TRANSFER(a,b) NOP
#define NP_PROFILER_BLOCK_LOST_CHECK(a) NOP
#define NP_PROFILER_AUTO_BLOCK_DEFINE(A) NOP
#define NP_PROFILER_AUTO_BLOCK_CHECK_DEFINE(a) NOP
#define NP_PROFILER_NAMED_AUTO_BLOCK_DEFINE(a,b)
#define NP_PROFILER_NAMED_AUTO_BLOCK_TRANSFER(a,b) NOP
#define NP_PROFILER_GET_LAST_FRAME_DATA() ""
#endif
// ======================================================================
#endif
@@ -0,0 +1,783 @@
// ======================================================================
//
// RemoteDebug.cpp
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/RemoteDebug.h"
#include "sharedDebug/RemoteDebug_inner.h"
#include "sharedFoundation/ExitChain.h"
#include <string>
#include <list>
#include <map>
#include <cstdio>
#include <cstdarg>
// ----------------------------------------------------------------------
//static definitions
RemoteDebug::RemoveFunction RemoteDebug::ms_removeFunction;
RemoteDebug::OpenFunction RemoteDebug::ms_openFunction;
RemoteDebug::CloseFunction RemoteDebug::ms_closeFunction;
RemoteDebug::SendFunction RemoteDebug::ms_sendFunction;
RemoteDebug::IsReadyFunction RemoteDebug::ms_isReadyFunction;
RemoteDebug::StreamMap *RemoteDebug::ms_streams;
RemoteDebug::StaticViewMap *RemoteDebug::ms_staticViews;
RemoteDebug::VariableMap *RemoteDebug::ms_variables;
std::map<uint32, bool> *RemoteDebug::ms_squelchedStream;
std::map<uint32, bool> *RemoteDebug::ms_squelchedStatic;
RemoteDebug::VariableValueMap *RemoteDebug::ms_variableValues;
RemoteDebug::MovementFunctionMap *RemoteDebug::ms_upFunctionMap;
RemoteDebug::MovementFunctionMap *RemoteDebug::ms_downFunctionMap;
RemoteDebug::MovementFunctionMap *RemoteDebug::ms_leftFunctionMap;
RemoteDebug::MovementFunctionMap *RemoteDebug::ms_rightFunctionMap;
RemoteDebug::MovementFunctionMap *RemoteDebug::ms_enterFunctionMap;
bool RemoteDebug::ms_opened;
bool RemoteDebug::ms_installed;
char RemoteDebug::ms_buffer[MAX_BUFFER_SIZE];
char RemoteDebug::ms_varArgs_buffer[MAX_BUFFER_SIZE];
uint32 RemoteDebug::ms_nextStream;
uint32 RemoteDebug::ms_nextVariable;
uint32 RemoteDebug::ms_nextStaticView;
//-----------------------------------------------------------------
RemoteDebug::~RemoteDebug ()
{
}
// ======================================================================
void RemoteDebug::install(RemoveFunction rm, OpenFunction o, CloseFunction c, SendFunction s, IsReadyFunction irf)//, ReceiveFunction rc)
{
ms_streams = new StreamMap;
ms_staticViews = new StaticViewMap;
ms_variables = new VariableMap;
ms_squelchedStream = new std::map<uint32, bool>;
ms_squelchedStatic = new std::map<uint32, bool>;
ms_variableValues = new VariableValueMap;
ms_upFunctionMap = new MovementFunctionMap;
ms_downFunctionMap = new MovementFunctionMap;
ms_leftFunctionMap = new MovementFunctionMap;
ms_rightFunctionMap = new MovementFunctionMap;
ms_enterFunctionMap = new MovementFunctionMap;
ms_nextStream = 0;
ms_nextStaticView = 0;
ms_nextVariable = 0;
ms_removeFunction = rm;
ms_openFunction = o;
ms_closeFunction = c;
ms_sendFunction = s;
ms_isReadyFunction = irf;
ms_opened = false;
ms_installed = true;
}
// ----------------------------------------------------------------------
void RemoteDebug::remove(void)
{
if(!ms_installed)
{
DEBUG_FATAL(!ms_installed, ("not installed"));
return;
}
ms_removeFunction = NULL;
ms_openFunction = NULL;
ms_closeFunction = NULL;
ms_sendFunction = NULL;
//empty out session-level data
for (StreamMap::iterator it = ms_streams->begin(); it != ms_streams->end(); ++it)
delete it->second;
delete ms_streams;
for (StaticViewMap::iterator itr = ms_staticViews->begin(); itr != ms_staticViews->end(); ++itr)
delete itr->second;
delete ms_staticViews;
for (VariableMap::iterator iter = ms_variables->begin(); iter != ms_variables->end(); ++iter)
delete iter->second;
delete ms_variables;
for (VariableValueMap::iterator iterr = ms_variableValues->begin(); iterr != ms_variableValues->end(); ++iterr)
delete iterr->second;
delete ms_variableValues;
ms_nextStream = 0;
ms_nextStaticView = 0;
ms_nextVariable = 0;
delete ms_squelchedStream;
delete ms_squelchedStatic;
delete ms_upFunctionMap;
delete ms_downFunctionMap;
delete ms_leftFunctionMap;
delete ms_rightFunctionMap;
delete ms_enterFunctionMap;
// delete ms_sessions;
ms_installed = false;
}
// ----------------------------------------------------------------------
void RemoteDebug::open(const char* server, uint16 port)
{
DEBUG_FATAL(!ms_installed, ("remoteDebug not installed"));
DEBUG_FATAL(ms_opened, ("remoteDebug session already open"));
ms_openFunction(server, port);
}
// ----------------------------------------------------------------------
uint32 RemoteDebug::registerStream(const std::string& streamName)
{
DEBUG_FATAL(!ms_installed, ("remoteDebug not installed"));
uint32 streamNum = 0;
Channel *parent = NULL;
std::string base;
std::string rest = streamName;
//look for subchannels with a double backslash
uint32 baseIndex = 0;
uint32 restIndex = streamName.find('\\');
while(restIndex != std::string::npos)
{
//pass the '\'
++restIndex;
//break channel into the base and the rest
base = streamName.substr(baseIndex, restIndex-baseIndex-1);
rest = streamName.substr(restIndex, streamName.size());
//build the channel
std::string newBase = streamName.substr(0, restIndex-1);
int32 streamNumber = findStream(newBase);
//only add the channel if we don't have it yet
if (streamNumber == -1)
{
Channel *child = new Channel(newBase, parent);
if (parent)
parent->addChild(child);
parent = child;
(*ms_streams)[ms_nextStream] = child;
streamNum = ms_nextStream++;
//every new channel is not squelched by default
(*ms_squelchedStream)[streamNum] = false;
//make sure we send the new base channel to the clients
send(NEW_STREAM, newBase.c_str());
}
//look for any other subChannel
uint32 oldRestIndex = restIndex;
baseIndex = restIndex;
restIndex = rest.find('\\');
if (restIndex != std::string::npos)
restIndex += oldRestIndex;
}
//no more sub channels, add this channel
Channel *child = new Channel(streamName, parent);
if (parent)
parent->addChild(child);
(*ms_streams)[ms_nextStream] = child;
streamNum = ms_nextStream++;
//every new channel is not squelched by default
(*ms_squelchedStream)[streamNum] = false;
//return the new channelID
return streamNum;
}
// ----------------------------------------------------------------------
uint32 RemoteDebug::registerStaticView(const std::string& channelName)
{
DEBUG_FATAL(!ms_installed, ("remoteDebug not installed"));
uint32 staticViewNum = 0;
Channel *parent = NULL;
std::string base;
std::string rest = channelName;
//look for subchannels with a double backslash
uint32 baseIndex = 0;
uint32 restIndex = channelName.find('\\');
while(restIndex != std::string::npos)
{
//pass the '\'
++restIndex;
//break channel into the base and the rest
base = channelName.substr(baseIndex, restIndex-baseIndex-1);
rest = channelName.substr(restIndex, channelName.size());
//build the channel
std::string newBase = channelName.substr(0, restIndex-1);
int32 channelNumber = findStaticView(newBase);
//only add the channel if we don't have it yet
if (channelNumber == -1)
{
Channel *child = new Channel(newBase, parent);
if (parent)
parent->addChild(child);
parent = child;
(*ms_staticViews)[ms_nextStaticView] = child;
staticViewNum = ms_nextStaticView++;
//every new channel is not squelched by default
(*ms_squelchedStatic)[staticViewNum] = false;
//make sure we send the new base channel to the clients
send(NEW_STATIC, newBase.c_str());
}
//look for any other subChannel
uint32 oldRestIndex = restIndex;
baseIndex = restIndex;
restIndex = rest.find('\\');
if (restIndex != std::string::npos)
restIndex += oldRestIndex;
}
//no more sub channels, add this channel
Channel *child = new Channel(channelName, parent);
if (parent)
parent->addChild(child);
(*ms_staticViews)[ms_nextStaticView] = child;
staticViewNum = ms_nextStaticView++;
//every new static view is not by default
(*ms_squelchedStatic)[staticViewNum] = true;
//return the new channelID
return staticViewNum;
}
// ----------------------------------------------------------------------
/** This function is called via a globally-accessible macro, so we can't assume that
* the system is installed.
*/
bool RemoteDebug::registerUpFunction(const char* staticViewName, UpFunction func)
{
if (!ms_installed)
return false;
int32 chan = findStaticView(staticViewName);
if (chan == -1)
return false;
(*ms_upFunctionMap)[chan] = func;
return true;
}
// ----------------------------------------------------------------------
/** This function is called via a globally-accessible macro, so we can't assume that
* the system is installed.
*/
bool RemoteDebug::registerDownFunction(const char* staticViewName, UpFunction func)
{
if (!ms_installed)
return false;
int32 chan = findStaticView(staticViewName);
if (chan == -1)
return false;
(*ms_downFunctionMap)[chan] = func;
return true;
}
// ----------------------------------------------------------------------
/** This function is called via a globally-accessible macro, so we can't assume that
* the system is installed.
*/
bool RemoteDebug::registerLeftFunction(const char* staticViewName, UpFunction func)
{
if (!ms_installed)
return false;
int32 chan = findStaticView(staticViewName);
if (chan == -1)
return false;
(*ms_leftFunctionMap)[chan] = func;
return true;
}
// ----------------------------------------------------------------------
/** This function is called via a globally-accessible macro, so we can't assume that
* the system is installed.
*/
bool RemoteDebug::registerRightFunction(const char* staticViewName, UpFunction func)
{
if (!ms_installed)
return false;
int32 chan = findStaticView(staticViewName);
if (chan == -1)
return false;
(*ms_rightFunctionMap)[chan] = func;
return true;
}
// ----------------------------------------------------------------------
/** This function is called via a globally-accessible macro, so we can't assume that
* the system is installed.
*/
bool RemoteDebug::registerEnterFunction(const char* staticViewName, UpFunction func)
{
if (!ms_installed)
return false;
int32 chan = findStaticView(staticViewName);
if (chan == -1)
return false;
(*ms_enterFunctionMap)[static_cast<uint32>(chan)] = func;
return true;
}
// ----------------------------------------------------------------------
/** This function is called via a globally-accessible macro, so we can't assume that
* the system is installed.
*/
uint32 RemoteDebug::registerVariable(const char* variableName, void *memLoc, VARIABLE_TYPES type, bool sendToClients)
{
if (!ms_installed)
return 0;
std::string variable = variableName;
uint32 variableNum = 0;
Channel *parent = NULL;
std::string base;
std::string rest = variable;
//look for subchannels with a double backslash
uint32 baseIndex = 0;
uint32 restIndex = variable.find('\\');
while(restIndex != std::string::npos)
{
//pass the '\'
++restIndex;
//break channel into the base and the rest
base = variable.substr(baseIndex, restIndex-baseIndex-1);
rest = variable.substr(restIndex, variable.size());
//build the channel
std::string newBase = variable.substr(0, restIndex-1);
int32 variableNumber = findVariable(newBase);
//only add the variable if we don't have it yet
if (variableNumber == -1)
{
registerVariable(newBase.c_str(), NULL, BOOL, sendToClients);
}
//look for any other subChannel
uint32 oldRestIndex = restIndex;
baseIndex = restIndex;
restIndex = rest.find('\\');
if (restIndex != std::string::npos)
restIndex += oldRestIndex;
}
//don't register duplicates
if(findVariable(variable) != -1)
return 0;
//no more sub channels, add this channel
Channel *child = new Channel(variable, parent);
if (parent)
parent->addChild(child);
(*ms_variables)[ms_nextVariable] = child;
variableNum = ms_nextVariable++;
Variable *v = new Variable(variable, memLoc, type);
(*ms_variableValues)[variableNum] = v;
if(sendToClients)
{
send(NEW_VARIABLE, variable.c_str());
send(VARIABLE_TYPE, variable.c_str());
send(VARIABLE_VALUE, variable.c_str());
}
setVariableValue(variable.c_str(), memLoc, sendToClients);
//return the new channelID
return variableNum;
}
// ----------------------------------------------------------------------
void RemoteDebug::updateVariable(const char* variableName)
{
send(VARIABLE_VALUE, variableName);
}
// ----------------------------------------------------------------------
/** This function is called via a globally-accessible macro, so we can't assume that
* the system is installed.
*/
void RemoteDebug::setVariableValue(const char* variableName, void *newValue, bool sendToClients)
{
if(!ms_installed)
return;
int32 variableNum = findVariable(variableName);
Variable *v = (*ms_variableValues)[static_cast<uint32>(variableNum)];
if(!v)
{
DEBUG_FATAL(true, ("message on undefined variable"));
}
v->setValue(newValue);
if(sendToClients)
send(VARIABLE_VALUE, variableName);
}
// ----------------------------------------------------------------------
/** This function builds a remoteDebug packet and sends it to the registered sendFunction.
* For some of the messages, it assumes that the varArgs static buffer has been filled
* in with the appropriate data (done with translateVarArgs, and taken care of in the
* macros defined in the header file).
*/
void RemoteDebug::send(MESSAGE_TYPE type, const char* theName)
{
if (!ms_installed)
{
return;
}
if (!ms_opened)
{
return;
}
if(ExitChain::isFataling())
return;
const std::string name = theName;
//build a payload based on messagetype
char messageType = 0;
uint32 channelNumber = 0;
//use signed value to allow a negative value for failure in the search routines
int32 chan = -1;
// StreamMap::iterator it = ms_streams->begin();
//pack in the message type
messageType = static_cast<char>(type);
char scratchString[10];
Variable *v;
//this variable is used when we want to send 4 bytes of 0's etc, without doing a strlen on the buffer
int32 explicitMessageLength = 0;
Variable::VARIABLEVALUE val;
switch(type)
{
case STREAM:
chan = findStream(name);
if (chan == -1)
{
//add the channel, sending that packet first
channelNumber = registerStream(name);
send(NEW_STREAM, name.c_str());
}
else
{
channelNumber = static_cast<uint32>(chan);
}
//bail out if this channel is squelched
if ((*ms_squelchedStream)[static_cast<uint32>(chan)] == true)
return;
break;
case NEW_STREAM:
//get the registered int for the new channel
chan = findStream(name);
if (chan != -1)
channelNumber = static_cast<uint32>(chan);
else
{
channelNumber = registerStream(name);
}
strcpy(ms_varArgs_buffer, name.c_str());
break;
case STREAM_SQUELCH:
case STREAM_UNSQUELCH:
chan = findStream(name);
if (chan != -1)
channelNumber = static_cast<uint32>(chan);
else
{
DEBUG_FATAL(true, ("message on unregistered channel"));
}
break;
//end stream channel cases
/////
//begin variable cases
case NEW_VARIABLE:
//get the registered int for the new variable
chan = findVariable(name);
if (chan != -1)
channelNumber = static_cast<uint32>(chan);
else
{
DEBUG_FATAL(true, ("message on unregistered channel"));
channelNumber = 0; //lint !e527 unreachable code
}
strcpy(ms_varArgs_buffer, name.c_str());
break;
case VARIABLE_TYPE:
chan = findVariable(name);
if (chan != -1)
channelNumber = static_cast<uint32>(chan);
v = (*ms_variableValues)[channelNumber];
_itoa(v->type(), scratchString, 10);
strcpy(ms_varArgs_buffer, scratchString);
break;
case VARIABLE_VALUE:
chan = findVariable(name);
if (chan != -1)
channelNumber = static_cast<uint32>(chan);
else
{
DEBUG_FATAL(true, ("message on unregistered channel"));
channelNumber = 0; //lint !e527 unreachable code
}
v = (*ms_variableValues)[channelNumber];
if(!v)
{
DEBUG_FATAL(true, ("message on undefined variable"));
return; //lint !e527 unreachable code
}
val = v->value();
switch(v->type())
{
case INT:
memcpy(ms_varArgs_buffer, &val.intValue, sizeof(int32));
explicitMessageLength = sizeof(int32);
break;
case FLOAT:
memcpy(ms_varArgs_buffer, &val.floatValue, sizeof(float));
explicitMessageLength = sizeof(float);
break;
case CSTRING:
strcpy(ms_varArgs_buffer, val.stringValue);
explicitMessageLength = strlen(val.stringValue)+1;
break;
case BOOL:
memcpy(ms_varArgs_buffer, &val.boolValue, sizeof(int32));
explicitMessageLength = sizeof(int32);
break;
}
break;
//end variable cases
/////
//begin static view cases
case NEW_STATIC:
//get the registered int for the new channel
chan = findStaticView(name);
if (chan != -1)
channelNumber = static_cast<uint32>(chan);
else
{
DEBUG_FATAL(true, ("message on unregistered channel"));
channelNumber = 0; //lint !e527 unreachable code
}
strcpy(ms_varArgs_buffer, name.c_str());
break;
case STATIC_LINE:
chan = findStaticView(name);
if (chan == -1)
{
//add the channel, sending that packet first
channelNumber = registerStaticView(name);
send(NEW_STATIC, name.c_str());
send(STATIC_SQUELCH, name.c_str());
}
else
{
channelNumber = static_cast<uint32>(chan);
}
//bail out if this channel is squelched
if ((*ms_squelchedStatic)[static_cast<uint32>(chan)] == true)
return;
break;
case STATIC_SQUELCH:
case STATIC_UNSQUELCH:
chan = findStaticView(name);
if (chan != -1)
channelNumber = static_cast<uint32>(chan);
else
{
channelNumber = registerStaticView(name);
send(NEW_STATIC, name.c_str());
}
break;
case STATIC_INPUT_TARGET:
chan = findStaticView(name);
if (chan == -1)
return;
else
channelNumber = static_cast<uint32>(chan);
break;
case STATIC_BEGIN_FRAME:
case STATIC_END_FRAME:
chan = findStaticView(name);
if (chan != -1)
channelNumber = static_cast<uint32>(chan);
else
{
channelNumber = registerStaticView(name);
send(NEW_STATIC, name.c_str());
send(STATIC_SQUELCH, name.c_str());
}
//bail our if this channel is squelched
if ((*ms_squelchedStatic)[static_cast<uint32>(chan)] == true)
return;
break;
case RemoteDebug::STATIC_UP:
case RemoteDebug::STATIC_DOWN:
case RemoteDebug::STATIC_LEFT:
case RemoteDebug::STATIC_RIGHT:
case RemoteDebug::STATIC_ENTER:
case RemoteDebug::REQUEST_ALL_CHANNELS:
default:
break;
}
//get sizes for building the packet
int messageTypeLength = sizeof(messageType);
int channelNumberLength = sizeof(channelNumber);
uint32 messageLength = 0;
int messageLengthLength = 0;
if (explicitMessageLength != 0)
messageLength = explicitMessageLength;
else if (ms_varArgs_buffer)
{
//only grab buffer sizes if needed
messageLength = strlen(ms_varArgs_buffer)+1;
}
else
{
messageLength = strlen(ms_buffer)+1;
}
messageLengthLength = sizeof(messageLength);
//allocate the mem for the packet
uint32 packetLength = static_cast<uint32>(messageTypeLength + channelNumberLength + messageLengthLength + static_cast<int>(messageLength));
if (ms_varArgs_buffer)
{
//copy data into the packet
memcpy(ms_buffer, &messageType, static_cast<uint32>(messageTypeLength));
memcpy(ms_buffer + messageTypeLength, &channelNumber, static_cast<uint32>(channelNumberLength));
//only copy the buffer data if needed
memcpy(ms_buffer + messageTypeLength + channelNumberLength, &messageLength, static_cast<uint32>(messageLengthLength));
memcpy(ms_buffer + messageTypeLength + channelNumberLength + messageLengthLength, ms_varArgs_buffer, messageLength);
}
//send and clean up
ms_sendFunction(ms_buffer, packetLength);
//clear out varArgs buffer
ms_varArgs_buffer[0] = '\0';
}
// ----------------------------------------------------------------------
int32 RemoteDebug::findStream(const std::string& name)
{
for(StreamMap::iterator it = ms_streams->begin(); it != ms_streams->end(); ++it)
{
if (it->second->name().compare(name) == 0)
{
return static_cast<int32>(it->first);
}
}
return -1;
}
// ----------------------------------------------------------------------
int32 RemoteDebug::findStaticView(const std::string& name)
{
for(StaticViewMap::iterator it = ms_staticViews->begin(); it != ms_staticViews->end(); ++it)
{
if (it->second->name().compare(name) == 0)
{
return static_cast<int32>(it->first);
}
}
return -1;
}
// ----------------------------------------------------------------------
int32 RemoteDebug::findVariable(const std::string& name)
{
for(VariableMap::iterator it = ms_variables->begin(); it != ms_variables->end(); ++it)
{
if (it->second->name().compare(name) == 0)
{
return static_cast<int32>(it->first);
}
}
return -1;
}
// ----------------------------------------------------------------------
/** Format and print a debugging message.
*
* This function copies the va_formatted into plain text and stores it into a static buffer
*/
void RemoteDebug::vprintf(const char *format, va_list va)
{
// format the string
if (_vsnprintf(ms_varArgs_buffer, sizeof(ms_varArgs_buffer), format, va) < 0)
{
// handle overflow reasonably nicely
ms_varArgs_buffer[sizeof(ms_varArgs_buffer)-2] = '+';
ms_varArgs_buffer[sizeof(ms_varArgs_buffer)-1] = '\0';
}
}
// ----------------------------------------------------------------------
/**
* Format and print a debugging message.
*
* This function ends up filling a static buffer with the formatted message
*/
void RemoteDebug::translateVarArgs(const char *format, ...)
{
va_list va;
va_start(va, format);
//copy the data into a static buffer
vprintf(format, va);
va_end(va);
}
// ======================================================================
@@ -0,0 +1,254 @@
// ======================================================================
//
// RemoteDebug.h
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef REMOTE_DEBUG_H
#define REMOTE_DEBUG_H
// ======================================================================
/** This class is both a platform and network-protocol independent way of
* sending output and input to a remote application. It does not depend
* on any specific network layer, and output may even be sent to a file or
* other output. Since it cannot rely on a network layer, it must build
* its own packets. Below is the packet structure:
*
* 1 byte for message type (current six types, so values 0-5.
* 4 bytes for the channel or variable number (since ints are registered
* and used for the network.
* 4 bytes for the messagelength (if necessary, not all messages have a
* payload to send).
* messageLength bytes for the payload (if necessary, could be a channel
* message or a variable value).
*/
class RemoteDebug
{
protected:
//forward declare inner classes (defined in RemoteDebug_inner.h)
class Channel;
class Variable;
public:
///an enum of all the possible message types
enum MESSAGE_TYPE
{
STREAM,
NEW_STREAM,
STREAM_SQUELCH,
STREAM_UNSQUELCH,
NEW_VARIABLE,
VARIABLE_TYPE,
VARIABLE_VALUE,
NEW_STATIC,
STATIC_SQUELCH,
STATIC_UNSQUELCH,
STATIC_BEGIN_FRAME,
STATIC_END_FRAME,
STATIC_LINE,
STATIC_INPUT_TARGET,
STATIC_UP,
STATIC_DOWN,
STATIC_LEFT,
STATIC_RIGHT,
STATIC_ENTER,
REQUEST_ALL_CHANNELS
};
///an enum of all the possible variable types
enum VARIABLE_TYPES
{
INT, //32 bit signed int
FLOAT, //32 bit signed float
CSTRING, //null terminated char[]
BOOL //0 or 1 (could use an int, but useful for tools)
};
protected:
//define typdefs of function types
typedef void (*RemoveFunction)();
typedef void (*OpenFunction)(const char *server, uint16 port);
typedef void (*CloseFunction)();
typedef void (*SendFunction)(void *buffer, uint32 bufferLen);
typedef void (*IsReadyFunction)();
typedef void (*UpFunction)();
typedef UpFunction DownFunction;
typedef UpFunction LeftFunction;
typedef UpFunction RightFunction;
typedef UpFunction EnterFunction;
//end inner classes, enums, and typedefs needed for public interface
// ----------------------------------------------------------------------
//begin public interface
public:
virtual ~RemoteDebug () = 0;
public:
///install the module, using the client defined functions
static void install(RemoveFunction, OpenFunction, CloseFunction, SendFunction, IsReadyFunction);
///open a session
static void open(const char *server = NULL, uint16 port = 0);
///packs the data into a packet, and sends it using the client-defined SendFunction
static void send(MESSAGE_TYPE type, const char* name = "");
///emulate printf functionality specific to this class
static void translateVarArgs(const char *format, ...);
///register a variable with the system
static uint32 registerVariable(const char* variableName, void *memLoc, VARIABLE_TYPES type, bool sendToClients);
///send the variable value to the clients
static void updateVariable(const char* variableName);
///set the value of a variable (previously registered, so we know how to cast the void*)
static void setVariableValue(const char* variableName, void *newValue, bool sendToClients);
///register a function that the up key should call on the given static view
static bool registerUpFunction(const char* staticViewName, UpFunction);
///register a function that the down key should call on the given static view
static bool registerDownFunction(const char* staticViewName, DownFunction);
///register a function that the left key should call on the given static view
static bool registerLeftFunction(const char* staticViewName, LeftFunction);
///register a function that the right key should call on the given static view
static bool registerRightFunction(const char* staticViewName, RightFunction);
///register a function that the enter key should call on the given static view
static bool registerEnterFunction(const char* staticViewName, EnterFunction);
//end public interface
// ----------------------------------------------------------------------
//begin protected functions and data members
protected:
///can't use a const int because we want this value compiled into static arrays as their size
#define MAX_BUFFER_SIZE 8192
static void remove();
///store the stream in a map, use an int for network communication
static uint32 registerStream(const std::string& streamName);
///store the static view in a map, use an int for network communication
static uint32 registerStaticView(const std::string& staticViewName);
///find and return the stream number for a given stream name, -1 if not found
static int32 findStream(const std::string& name);
///find and return the static view number for a given static view name, -1 if not found
static int32 findStaticView(const std::string& name);
///find and return the variable number for a given variable name, -1 if not found
static int32 findVariable(const std::string& name);
///emulate printf functionality specific to this class
static void vprintf(const char *format, va_list va);
//bound functions used for the actual transfer of data (i.e. network calls)
static RemoveFunction ms_removeFunction;
static OpenFunction ms_openFunction;
static CloseFunction ms_closeFunction;
static SendFunction ms_sendFunction;
static IsReadyFunction ms_isReadyFunction;
typedef stdmap<uint32, Channel *>::fwd StreamMap;
///stream names
static StreamMap *ms_streams;
typedef stdmap<uint32, Channel *>::fwd VariableMap;
///What variables are registered
static VariableMap *ms_variables;
typedef stdmap<uint32, Channel *>::fwd StaticViewMap;
///StaticView names
static StaticViewMap *ms_staticViews;
///a static packet buffer to prevent per-message new and delete
static char ms_buffer[MAX_BUFFER_SIZE];
///a static buffer used to build a string from the translateVarArgs data
static char ms_varArgs_buffer[MAX_BUFFER_SIZE];
///true if system has been installed, false otherwise
static bool ms_installed;
///Whether the connection is open or not
static bool ms_opened;
///What streaming channels are squelched (i.e. don't send to client at all)
static stdmap<uint32, bool>::fwd *ms_squelchedStream;
///What static channels are squelched (i.e. don't send to client at all)
static stdmap<uint32, bool>::fwd *ms_squelchedStatic;
///the next stream number
static uint32 ms_nextStream;
///the next variable number
static uint32 ms_nextVariable;
///the next staticView number
static uint32 ms_nextStaticView;
typedef stdmap<uint32, Variable *>::fwd VariableValueMap;
static VariableValueMap *ms_variableValues;
typedef stdmap<uint32, UpFunction>::fwd MovementFunctionMap;
static MovementFunctionMap *ms_upFunctionMap;
static MovementFunctionMap *ms_downFunctionMap;
static MovementFunctionMap *ms_leftFunctionMap;
static MovementFunctionMap *ms_rightFunctionMap;
static MovementFunctionMap *ms_enterFunctionMap;
};
// ======================================================================
#define OUTPUT_CHANNEL(streamName, varArgs) (RemoteDebug::translateVarArgs varArgs, RemoteDebug::send(RemoteDebug::STREAM, streamName))
#define OUTPUT_REGISTER_VARIABLE(variableName, memLoc, type) RemoteDebug::registerVariable(variableName, memLoc, type, true)
#define OUTPUT_UPDATE_VARIABLE(variableName) RemoteDebug::updateVariable(variableName)
#define OUTPUT_STATIC_VIEW(staticViewName, varArgs) (RemoteDebug::translateVarArgs varArgs, RemoteDebug::send(RemoteDebug::STATIC_LINE, staticViewName))
#define OUTPUT_STATIC_VIEW_BEGINFRAME(staticViewName) RemoteDebug::send(RemoteDebug::STATIC_BEGIN_FRAME, staticViewName)
#define OUTPUT_STATIC_VIEW_ENDFRAME(staticViewName) RemoteDebug::send(RemoteDebug::STATIC_END_FRAME, staticViewName)
#define OUTPUT_STATIC_VIEW_UP(staticViewName, upFunction) RemoteDebug::registerUpFunction(staticViewName, upFunction)
#define OUTPUT_STATIC_VIEW_DOWN(staticViewName, downFunction) RemoteDebug::registerDownFunction(staticViewName, downFunction)
#define OUTPUT_STATIC_VIEW_LEFT(staticViewName, leftFunction) RemoteDebug::registerLeftFunction(staticViewName, leftFunction)
#define OUTPUT_STATIC_VIEW_RIGHT(staticViewName, rightFunction) RemoteDebug::registerRightFunction(staticViewName, rightFunction)
#define OUTPUT_STATIC_VIEW_ENTER(staticViewName, enterFunction) RemoteDebug::registerEnterFunction(staticViewName, enterFunction)
#ifdef _DEBUG
#define DEBUG_OUTPUT_CHANNEL(streamName, varArgs) OUTPUT_CHANNEL(streamName, varArgs)
#define DEBUG_OUTPUT_REGISTER_VARIABLE(variableName, memLoc, type) OUTPUT_REGISTER_VARIABLE(variableName, memLoc, type)
#define DEBUG_OUTPUT_UPDATE_VARIABLE(variableName) OUTPUT_UPDATE_VARIABLE(variableName)
#define DEBUG_OUTPUT_STATIC_VIEW(staticViewName, varArgs) OUTPUT_STATIC_VIEW(staticViewName, varArgs)
#define DEBUG_OUTPUT_STATIC_VIEW_BEGINFRAME(staticViewName) OUTPUT_STATIC_VIEW_BEGINFRAME(staticViewName)
#define DEBUG_OUTPUT_STATIC_VIEW_ENDFRAME(staticViewName) OUTPUT_STATIC_VIEW_ENDFRAME(staticViewName)
#define DEBUG_OUTPUT_STATIC_VIEW_UP(staticViewName, upFunction) OUTPUT_STATIC_VIEW_UP(staticViewName, upFunction)
#define DEBUG_OUTPUT_STATIC_VIEW_DOWN(staticViewName, downFunction) OUTPUT_STATIC_VIEW_DOWN(staticViewName, downFunction)
#define DEBUG_OUTPUT_STATIC_VIEW_LEFT(staticViewName, leftFunction) OUTPUT_STATIC_VIEW_LEFT(staticViewName, leftFunction)
#define DEBUG_OUTPUT_STATIC_VIEW_RIGHT(staticViewName, rightFunction) OUTPUT_STATIC_VIEW_RIGHT(staticViewName, rightFunction)
#define DEBUG_OUTPUT_STATIC_VIEW_ENTER(staticViewName, enterFunction) OUTPUT_STATIC_VIEW_ENTER(staticViewName, enterFunction)
#else //!_DEBUG
#define DEBUG_OUTPUT_CHANNEL(streamName, varArgs) NOP
#define DEBUG_OUTPUT_REGISTER_VARIABLE(variableName, memLoc, type) NOP
#define DEBUG_OUTPUT_VARIABLE(variableName, newValue) NOP
#define DEBUG_OUTPUT_STATIC_VIEW(staticViewName, varArgs) NOP
#define DEBUG_OUTPUT_STATIC_VIEW_BEGINFRAME(staticViewName) NOP
#define DEBUG_OUTPUT_STATIC_VIEW_ENDFRAME(staticViewName) NOP
#define DEBUG_OUTPUT_STATIC_VIEW_UP(staticViewName, upFunction) NOP
#define DEBUG_OUTPUT_STATIC_VIEW_DOWN(staticViewName, downFunction) NOP
#define DEBUG_OUTPUT_STATIC_VIEW_LEFT(staticViewName, leftFunction) NOP
#define DEBUG_OUTPUT_STATIC_VIEW_RIGHT(staticViewName, rightFunction) NOP
#define DEBUG_OUTPUT_STATIC_VIEW_ENTER(staticViewName, enterFunction) NOP
#endif // _DEBUG
#endif // REMOTE_DEBUG_H
@@ -0,0 +1,593 @@
// ======================================================================
//
// RemoteDebug_inner.cpp
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/RemoteDebug.h"
#include "sharedDebug/RemoteDebug_inner.h"
#include <string>
#include <list>
#include <map>
// ----------------------------------------------------------------------
RemoteDebugClient::NewStreamFunction RemoteDebugClient::ms_newStreamFunction;
RemoteDebugClient::StreamMessageFunction RemoteDebugClient::ms_streamMessageFunction;
RemoteDebugClient::NewVariableFunction RemoteDebugClient::ms_newVariableFunction;
RemoteDebugClient::VariableValueFunction RemoteDebugClient::ms_variableValueFunction;
RemoteDebugClient::VariableTypeFunction RemoteDebugClient::ms_variableTypeFunction;
RemoteDebugClient::BeginFrameFunction RemoteDebugClient::ms_beginFrameFunction;
RemoteDebugClient::EndFrameFunction RemoteDebugClient::ms_endFrameFunction;
RemoteDebugClient::NewStaticViewFunction RemoteDebugClient::ms_newStaticViewFunction;
RemoteDebugClient::LineFunction RemoteDebugClient::ms_lineFunction;
uint32 RemoteDebugServer::ms_inputTarget;
// ======================================================================
RemoteDebug::Channel::Channel(const std::string& name, Channel *parent)
: m_name(NULL),
m_parent(parent)
{
m_name = new std::string(name);
m_children = new NodeList;
}
// ----------------------------------------------------------------------
RemoteDebug::Channel::~Channel()
{
m_parent = NULL;
if(m_name)
{
delete m_name;
m_name = NULL;
}
if (m_children)
{
delete m_children;
m_children = NULL;
}
}
// ----------------------------------------------------------------------
void RemoteDebug::Channel::addChild(Channel *child)
{
m_children->push_back(child);
}
// ----------------------------------------------------------------------
const std::string& RemoteDebug::Channel::name()
{
return *m_name;
}
// ======================================================================
RemoteDebug::Variable::Variable(const std::string& name, void *memLoc, VARIABLE_TYPES type)
: m_memLoc(memLoc),
m_name(NULL),
m_type(type)
{
m_name = new std::string(name);
int32 i = 0;
float f = 0.0;
char s = '\0';
int32 b = 0;
switch(m_type)
{
case INT:
m_value.intValue = i;
break;
case FLOAT:
m_value.floatValue = f;
break;
case CSTRING:
m_value.stringValue = &s;
break;
case BOOL:
m_value.boolValue = b;
break;
}
}
// ----------------------------------------------------------------------
RemoteDebug::Variable::~Variable()
{
if(m_type == CSTRING)
if (m_value.stringValue != NULL)
delete m_value.stringValue;
if(m_name)
{
delete m_name;
m_name = NULL;
}
}
// ----------------------------------------------------------------------
void RemoteDebug::Variable::setValue(VARIABLEVALUE v)
{
switch(m_type)
{
case INT:
m_value.intValue = v.intValue;
break;
case FLOAT:
m_value.floatValue = v.floatValue;
break;
case CSTRING:
m_value.stringValue = v.stringValue;
break;
case BOOL:
m_value.boolValue = v.boolValue;
break;
}
}
// ----------------------------------------------------------------------
void RemoteDebug::Variable::setValue(void *memLoc)
{
if(memLoc)
{
switch(m_type)
{
case INT:
memcpy(&m_value.intValue, memLoc, sizeof(int32));
break;
case FLOAT:
memcpy(&m_value.floatValue, memLoc, sizeof(float));
break;
case CSTRING:
if (m_value.stringValue)
delete[] m_value.stringValue;
m_value.stringValue = new char[strlen(static_cast<char *>(memLoc))];
strcpy(m_value.stringValue, const_cast<const char *>(static_cast<char *>(memLoc)));
break;
case BOOL:
memcpy(&m_value.boolValue, memLoc, sizeof(int32));
break;
}
}
}
// ----------------------------------------------------------------------
RemoteDebug::Variable::VARIABLEVALUE RemoteDebug::Variable::value()
{
return m_value;
}
// ----------------------------------------------------------------------
const std::string& RemoteDebug::Variable::name()
{
return *m_name;
}
// ----------------------------------------------------------------------
void RemoteDebug::Variable::setType(VARIABLE_TYPES type)
{
m_type = type;
}
// ----------------------------------------------------------------------
void RemoteDebug::Variable::pushValue()
{
if (m_memLoc)
switch (m_type)
{
case BOOL:
case INT:
memcpy(m_memLoc, &m_value, sizeof(int32));
break;
case CSTRING:
strcpy(static_cast<char *>(m_memLoc), m_value.stringValue);
break;
case FLOAT:
memcpy(m_memLoc, &m_value, sizeof(float));
break;
}
}
// ----------------------------------------------------------------------
RemoteDebug::VARIABLE_TYPES RemoteDebug::Variable::type()
{
return m_type;
}
// ======================================================================
void RemoteDebugClient::install(RemoveFunction rf, OpenFunction of,
CloseFunction cf, SendFunction sf,
IsReadyFunction irf, NewStreamFunction ncf,
StreamMessageFunction cmf, NewVariableFunction nvf,
VariableValueFunction vvf, VariableTypeFunction vtf,
BeginFrameFunction bff, EndFrameFunction eff,
NewStaticViewFunction nsvf, LineFunction lf)
{
RemoteDebug::install(rf, of, cf, sf, irf);
ms_newStreamFunction = ncf;
ms_streamMessageFunction = cmf;
ms_newVariableFunction = nvf;
ms_variableValueFunction = vvf;
ms_variableTypeFunction = vtf;
ms_beginFrameFunction = bff;
ms_endFrameFunction = eff;
ms_newStaticViewFunction = nsvf;
ms_lineFunction = lf;
}
// ----------------------------------------------------------------------
void RemoteDebugClient::remove()
{
if (ms_opened)
close();
RemoteDebug::remove();
}
// ----------------------------------------------------------------------
void RemoteDebugClient::receive(const unsigned char * const message, const uint32 bufferLen)
{
UNREF(bufferLen);
//convert to a const char[] for conveinence
const char * const charMessage = reinterpret_cast<const char * const>(message);
//these values are known based on the packet protocol (see RemoteDebug.h for more info
const int sizeOfMessageType = 1;
const int sizeOfChannelNumber = 4;
const int sizeOfSizeofPayload = 4;
//this value is filled in from the packet
uint32 channelNumber = 0;
//this value if filled in from the packet
uint32 sizeOfPayload = 0;
//get the message type
RemoteDebug::MESSAGE_TYPE type = static_cast<RemoteDebug::MESSAGE_TYPE>(charMessage[0]);
//grab the channelNumber
memcpy(&channelNumber, charMessage + sizeOfMessageType, sizeOfChannelNumber);
//build the payload if needed
if (type == RemoteDebug::STREAM ||
type == RemoteDebug::STATIC_LINE ||
type == RemoteDebug::NEW_STATIC ||
type == RemoteDebug::NEW_STREAM ||
type == RemoteDebug::VARIABLE_TYPE ||
type == RemoteDebug::VARIABLE_VALUE ||
type == RemoteDebug::NEW_VARIABLE)
{
memcpy(&sizeOfPayload, charMessage + sizeOfMessageType + sizeOfChannelNumber, sizeOfSizeofPayload);
memcpy(ms_buffer, charMessage + sizeOfMessageType + sizeOfChannelNumber + sizeOfSizeofPayload, sizeOfPayload);
}
//can't have local variables defined within switch statements, so place them out here.
int32 t;
VARIABLE_TYPES varType;
std::string variableName;
switch(type)
{
case RemoteDebug::STREAM:
//see if we're redefining an already existing stream
if(ms_streamMessageFunction)
ms_streamMessageFunction(channelNumber, const_cast<const char*>(ms_buffer));
break;
case RemoteDebug::NEW_STREAM:
if (channelNumber < ms_nextStream)
return;
registerStream(ms_buffer);
if (ms_newStreamFunction)
ms_newStreamFunction(channelNumber, const_cast<const char*>(ms_buffer));
break;
case RemoteDebug::NEW_VARIABLE:
if (channelNumber < ms_nextVariable)
return;
//do not send value back to server (hence the "false")
registerVariable(ms_buffer, NULL, BOOL, false);
if (ms_newVariableFunction)
ms_newVariableFunction(channelNumber, const_cast<const char*>(ms_buffer));
break;
case RemoteDebug::VARIABLE_TYPE:
t = atoi(ms_buffer);
varType = static_cast<VARIABLE_TYPES>(t);
(*ms_variableValues)[channelNumber]->setType(varType);
if(ms_variableTypeFunction)
ms_variableTypeFunction(channelNumber, varType);
break;
case RemoteDebug::VARIABLE_VALUE:
(*ms_variableValues)[channelNumber]->setValue(ms_buffer);
if(ms_variableValueFunction)
ms_variableValueFunction(channelNumber, ms_buffer);
break;
case RemoteDebug::NEW_STATIC:
if (channelNumber < ms_nextStaticView)
return;
registerStaticView(ms_buffer);
if (ms_newStaticViewFunction)
ms_newStaticViewFunction(channelNumber, const_cast<const char*>(ms_buffer));
break;
case RemoteDebug::STATIC_LINE:
if (ms_lineFunction)
ms_lineFunction(channelNumber, const_cast<const char*>(ms_buffer));
break;
case RemoteDebug::STATIC_BEGIN_FRAME:
if (ms_beginFrameFunction)
ms_beginFrameFunction(channelNumber);
break;
case RemoteDebug::STATIC_END_FRAME:
if (ms_endFrameFunction)
ms_endFrameFunction(channelNumber);
break;
case RemoteDebug::STREAM_SQUELCH:
case RemoteDebug::STREAM_UNSQUELCH:
case RemoteDebug::STATIC_SQUELCH:
case RemoteDebug::STATIC_UNSQUELCH:
case RemoteDebug::STATIC_INPUT_TARGET:
case RemoteDebug::STATIC_UP:
case RemoteDebug::STATIC_DOWN:
case RemoteDebug::STATIC_LEFT:
case RemoteDebug::STATIC_RIGHT:
case RemoteDebug::STATIC_ENTER:
case RemoteDebug::REQUEST_ALL_CHANNELS:
default:
break;
}
}
// ----------------------------------------------------------------------
/** Called when the clinet closes a session. Since we don't want to maintain
* data between sessions, clear out all data.
*/
void RemoteDebugClient::close()
{
DEBUG_FATAL(!ms_installed, ("remoteDebug not installed"));
//don't need to do anything if we're already closed
if(!ms_opened)
return;
if (ms_closeFunction)
ms_closeFunction();
ms_opened = false;
//empty out session-level data
for (StreamMap::iterator it = ms_streams->begin(); it != ms_streams->end(); ++it)
delete it->second;
ms_streams->clear();
for (StaticViewMap::iterator itr = ms_staticViews->begin(); itr != ms_staticViews->end(); ++itr)
delete itr->second;
ms_staticViews->clear();
for (VariableMap::iterator iter = ms_variables->begin(); iter != ms_variables->end(); ++iter)
delete iter->second;
ms_variables->clear();
for (VariableValueMap::iterator iterr = ms_variableValues->begin(); iterr != ms_variableValues->end(); ++iterr)
delete iterr->second;
ms_variableValues->clear();
ms_squelchedStream->clear();
ms_squelchedStatic->clear();
ms_nextStream = 0;
ms_nextStaticView = 0;
ms_nextVariable = 0;
}
// ----------------------------------------------------------------------
void RemoteDebugClient::isReady()
{
ms_opened = true;
if (ms_isReadyFunction)
ms_isReadyFunction();
send(REQUEST_ALL_CHANNELS, "");
}
// ======================================================================
void RemoteDebugServer::install(RemoveFunction rmf, OpenFunction of ,
CloseFunction cf , SendFunction sf,
IsReadyFunction irf)
{
RemoteDebug::install(rmf, of, cf, sf, irf);
ms_inputTarget = 0;
}
// ----------------------------------------------------------------------
void RemoteDebugServer::remove()
{
if (ms_opened)
close();
RemoteDebug::remove();
}
// ----------------------------------------------------------------------
void RemoteDebugServer::isReady()
{
ms_opened = true;
if (ms_isReadyFunction)
ms_isReadyFunction();
}
// ----------------------------------------------------------------------
void RemoteDebugServer::receive(const unsigned char * const message, const uint32 bufferLen)
{
UNREF(bufferLen);
//convert to a const char[] for conveinence
const char * const charMessage = reinterpret_cast<const char * const>(message);
//these values are known based on the packet protocol (see RemoteDebug.h for more info
const int sizeOfMessageType = 1;
const int sizeOfChannelNumber = 4;
const int sizeOfSizeofPayload = 4;
//this value is filled in from the packet
uint32 channelNumber = 0;
//this value if filled in from the packet
uint32 sizeOfPayload = 0;
//get the message type
RemoteDebug::MESSAGE_TYPE type = static_cast<RemoteDebug::MESSAGE_TYPE>(charMessage[0]);
//grab the channelNumber
memcpy(&channelNumber, charMessage + sizeOfMessageType, sizeOfChannelNumber);
//build the payload if needed
if (type == RemoteDebug::STREAM ||
type == RemoteDebug::NEW_STREAM ||
type == RemoteDebug::VARIABLE_TYPE ||
type == RemoteDebug::VARIABLE_VALUE ||
type == RemoteDebug::NEW_VARIABLE)
{
memcpy(&sizeOfPayload, charMessage + sizeOfMessageType + sizeOfChannelNumber, sizeOfSizeofPayload);
memcpy(ms_buffer, charMessage + sizeOfMessageType + sizeOfChannelNumber + sizeOfSizeofPayload, sizeOfPayload);
}
Variable* v = NULL;
switch(type)
{
case STREAM:
case NEW_STREAM:
case VARIABLE_TYPE:
case NEW_VARIABLE:
break;
case STREAM_SQUELCH:
(*ms_squelchedStream)[channelNumber] = true;
break;
case STREAM_UNSQUELCH:
(*ms_squelchedStream)[channelNumber] = false;
break;
case VARIABLE_VALUE:
//set the new value into the variable on the server side
v = (*ms_variableValues)[channelNumber];
if(!v)
{
DEBUG_FATAL(true, ("message on undefined variable"));
return; //lint !e527 unreachable code
}
v->setValue(ms_buffer);
//put that new value back into the game object
v->pushValue();
break;
case STATIC_SQUELCH:
(*ms_squelchedStatic)[channelNumber] = true;
break;
case STATIC_UNSQUELCH:
(*ms_squelchedStatic)[channelNumber] = false;
break;
case REQUEST_ALL_CHANNELS:
sendAllChannels();
break;
case STATIC_INPUT_TARGET:
ms_inputTarget = channelNumber;
break;
case STATIC_UP:
if ((*ms_upFunctionMap)[ms_inputTarget] != NULL)
(*ms_upFunctionMap)[ms_inputTarget](); //lint !e10, !e522 ("expecting a function" and "expected void assignment)
break;
case STATIC_DOWN:
if ((*ms_downFunctionMap)[ms_inputTarget] != NULL)
(*ms_downFunctionMap)[ms_inputTarget](); //lint !e10, !e522 ("expecting a function" and "expected void assignment)
break;
case STATIC_LEFT:
if ((*ms_leftFunctionMap)[ms_inputTarget] != NULL)
(*ms_leftFunctionMap)[ms_inputTarget](); //lint !e10, !e522 ("expecting a function" and "expected void assignment)
break;
case STATIC_RIGHT:
if ((*ms_rightFunctionMap)[ms_inputTarget] != NULL)
(*ms_rightFunctionMap)[ms_inputTarget](); //lint !e10, !e522 ("expecting a function" and "expected void assignment)
break;
case STATIC_ENTER:
if ((*ms_enterFunctionMap)[ms_inputTarget] != NULL)
(*ms_enterFunctionMap)[ms_inputTarget](); //lint !e10, !e522 ("expecting a function" and "expected void assignment)
break;
case NEW_STATIC:
case STATIC_BEGIN_FRAME:
case STATIC_END_FRAME:
case STATIC_LINE:
default:
break;
}
}
// ----------------------------------------------------------------------
/** Called when a session is closed. Since this is the server side, and must
* maintain data between sessions, data is NOT cleared out.
*/
void RemoteDebugServer::close()
{
DEBUG_FATAL(!ms_installed, ("remoteDebug not installed"));
if (ms_closeFunction)
ms_closeFunction();
ms_opened = false;
}
// ----------------------------------------------------------------------
void RemoteDebugServer::sendAllChannels()
{
for(StreamMap::iterator it = ms_streams->begin(); it != ms_streams->end(); ++it)
send(NEW_STREAM, it->second->name().c_str());
for(VariableMap::iterator itr = ms_variables->begin(); itr != ms_variables->end(); ++itr)
{
send(NEW_VARIABLE, itr->second->name().c_str());
send(VARIABLE_TYPE, itr->second->name().c_str());
send(VARIABLE_VALUE, itr->second->name().c_str());
}
for(StaticViewMap::iterator iter = ms_staticViews->begin(); iter != ms_staticViews->end(); ++iter)
send(NEW_STATIC, iter->second->name().c_str());
}
// ======================================================================
@@ -0,0 +1,155 @@
// ======================================================================
//
// RemoteDebug_inner.h
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef REMOTE_DEBUG_INNER_H
#define REMOTE_DEBUG_INNER_H
#include "sharedDebug/RemoteDebug.h"
// ======================================================================
/** This inner class is used to maintain relationships between channels. It stores both its parent
* and child nodes, as well as it's fully qualified name (i.e. "Foundation\\MemoryManager\\MemoryMap")
*/
class RemoteDebug::Channel
{
public:
Channel(const std::string& name, Channel *parent);
~Channel();
void addChild(Channel *child);
const std::string& name();
private:
typedef stdlist<Channel *>::fwd NodeList;
///its children
NodeList* m_children;
///the fully qualified name of the channel
std::string* m_name;
///its parent (which is NULL for top-level nodes
Channel *m_parent;
};
/** This class stores data about a variable channel, both on the server (where the variable actually
* resides), and the client (which just displays it). The client simply creates Variable's with
* NULL'd out memLoc's, since it doesn't have direct access to the memory.
*/
class RemoteDebug::Variable
{
public:
union VARIABLEVALUE
{
int32 intValue;
float floatValue;
int32 boolValue;
char* stringValue;
};
Variable(const std::string& name, void *memLoc, VARIABLE_TYPES type);
~Variable();
void setValue(VARIABLEVALUE v);
void setValue(void *memLoc);
VARIABLEVALUE value();
const std::string& name();
void setType(VARIABLE_TYPES type);
VARIABLE_TYPES type();
void pushValue();
private:
///a data structure used to hold the current variable data
VARIABLEVALUE m_value;
void *m_memLoc;
std::string* m_name;
VARIABLE_TYPES m_type;
};
// ======================================================================
/** This derived class represents a client application that uses the RemoteDebug module.
* It receives messages and can do things like send messages to the app to clear the screen.
* It can also send squelch and unsquelch messages. This module would be used by a text-based,
* MFC, or Qt app for instance.
*/
class RemoteDebugClient : public RemoteDebug
{
protected:
typedef void (*NewStreamFunction)(uint32 streamNumber, const char *streamName);
typedef void (*StreamMessageFunction)(uint32 streamNumber, const char *message);
typedef void (*NewVariableFunction)(uint32 variableNumber, const char *variableName);
typedef void (*VariableTypeFunction)(uint32 variableNumber, VARIABLE_TYPES type);
typedef void (*VariableValueFunction)(uint32 variableNumber, const char *message);
typedef void (*BeginFrameFunction)(uint32 staticViewNumber);
typedef void (*EndFrameFunction)(uint32 staticViewNumber);
typedef void (*NewStaticViewFunction)(uint32 variableNumber, const char *variableName);
typedef void (*LineFunction)(uint32 staticViewNumber, const char *message);
static NewStreamFunction ms_newStreamFunction;
static StreamMessageFunction ms_streamMessageFunction;
static NewVariableFunction ms_newVariableFunction;
static VariableValueFunction ms_variableValueFunction;
static VariableTypeFunction ms_variableTypeFunction;
static BeginFrameFunction ms_beginFrameFunction;
static EndFrameFunction ms_endFrameFunction;
static NewStaticViewFunction ms_newStaticViewFunction;
static LineFunction ms_lineFunction;
public:
///used to initialize the client application
static void install(RemoveFunction rf, OpenFunction of, CloseFunction cf, SendFunction sf,
IsReadyFunction irf, NewStreamFunction ncf, StreamMessageFunction cmf,
NewVariableFunction nvf , VariableValueFunction vvf, VariableTypeFunction vtf,
BeginFrameFunction bff, EndFrameFunction eff, NewStaticViewFunction nsvf,
LineFunction lf);
///uninstall the module
static void remove();
static void close();
///receives and translates a packet, takes appropriate action
static void receive(const unsigned char * const buffer, const uint32 bufferLen);
///called when actually ready to transfer data (commonly called from an open ack)
static void isReady();
};
// ======================================================================
/** This derived class represents a server application that uses the RemoteDebug module.
* It sends messages and can do things like receive squelch and unsquelch messages.
* This module would be used by applications like gameserver, loginservers, and the game client.
*/
class RemoteDebugServer : public RemoteDebug
{
public:
///install the module, using the client defined functions
static void install(RemoveFunction rmf, OpenFunction of,
CloseFunction cf, SendFunction sf,
IsReadyFunction irf);
///uninstall the module
static void remove();
///receives and translates a packet, takes appropriate action
static void receive(const unsigned char * const message, const uint32 bufferLen);
static void close();
///called when actually ready to transfer data (commonly called from an open ack)
static void isReady();
protected:
///send all the channels to the client
static void sendAllChannels();
///stores the channel number of the static view that currently receives keyboard input
static uint32 ms_inputTarget;
};
// ======================================================================
#endif // REMOTE_DEBUG_INNER_H
@@ -0,0 +1,243 @@
// ======================================================================
//
// Report.cpp
// copyright 1999 Bootprint Entertainment
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/Report.h"
#include "sharedDebug/DebugFlags.h"
#include "sharedDebug/DebugMonitor.h"
#include "sharedFoundation/FloatingPointUnit.h"
#include "sharedFoundation/Os.h"
#include "sharedFoundation/PerThreadData.h"
#include "sharedFoundation/Production.h"
#include <cstdio>
#include <cstdarg>
// ======================================================================
namespace ReportNamespace
{
Report::Callback ms_logCallback;
Report::Callback ms_warningCallback;
Report::Callback ms_fatalCallback;
bool ms_logAllReports;
int ms_flags;
};
using namespace ReportNamespace;
// ======================================================================
void Report::install()
{
DebugFlags::registerFlag(ms_logAllReports, "SharedDebug", "logAllReports");
}
// ----------------------------------------------------------------------
void Report::bindLogCallback(Callback callback)
{
ms_logCallback = callback;
}
// ----------------------------------------------------------------------
void Report::bindWarningCallback(Callback callback)
{
ms_warningCallback = callback;
}
// ----------------------------------------------------------------------
void Report::bindFatalCallback(Callback callback)
{
ms_fatalCallback = callback;
}
// ======================================================================
/**
* Setup the debug print flags for the next debug print from this thread
*
* This routine should never be called directly, but only through the DEBUG_PRINT macros.
*
* @internal
*/
void Report::setFlags(int flags)
{
if (ms_logAllReports)
flags |= RF_log;
if (!PerThreadData::isThreadInstalled())
{
// if the per-thread-data isn't installed, then we know we're single-threaded and can use the static flags
ms_flags = flags;
}
else
PerThreadData::setDebugPrintFlags(flags);
}
// ----------------------------------------------------------------------
void Report::puts(const char *buffer)
{
int flags;
if (!PerThreadData::isThreadInstalled())
{
// if the per-thread-data isn't installed, then we know we're single-threaded and can use the static flags
flags = ms_flags;
}
else
flags = PerThreadData::getDebugPrintFlags();
// handle logging callback functions
if (flags & RF_fatal)
{
if (ms_fatalCallback)
(*ms_fatalCallback)(buffer);
}
else
if (flags & RF_warning)
{
if (ms_warningCallback)
(*ms_warningCallback)(buffer);
}
else
if (flags & RF_log)
{
if (ms_logCallback)
(*ms_logCallback)(buffer);
}
if (flags & RF_print)
{
#ifdef WIN32
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut)
{
DWORD bytesWritten;
WriteFile(hStdOut, buffer, strlen(buffer), &bytesWritten, 0);
}
#else
fputs(buffer, stdout);
#endif
}
#if PRODUCTION == 0
if (flags & RF_print)
{
DebugMonitor::print(buffer);
if (flags & (RF_fatal | RF_dialog))
DebugMonitor::print("\n");
}
#endif
if (flags & RF_log)
{
const WORD fp1 = FloatingPointUnit::getControlWord();
#ifdef WIN32
OutputDebugString(buffer);
if (flags & RF_console)
fputs(buffer, stderr);
#else
fputs(buffer, stderr);
#endif
// fatal strings and dialog messages do not have newlines on the end of them, but we want them in the logs
if (flags & (RF_fatal | RF_dialog))
{
#ifdef WIN32
OutputDebugString("\n");
if (flags & RF_console)
fputs("\n", stderr);
#else
fputs("\n", stderr);
#endif
}
const WORD fp2 = FloatingPointUnit::getControlWord();
// -qq- HACK this is an attempt to work around OutputDebugString resetting the FPU precision to 53 bits when running under the debugger
if (fp1 != fp2)
FloatingPointUnit::setControlWord(fp1);
}
// fatal strings should be made very obvious, so pop up a message box
if ((flags & RF_dialog) && Os::isMainThread())
{
const char *title = "Report";
if (flags & RF_fatal)
title = "Fatal Report";
MessageBox(NULL, buffer, title, MB_OK | MB_ICONEXCLAMATION);
}
}
// ----------------------------------------------------------------------
/**
* Format and print a debugging message.
*
* This routine should never be called directly, but only through the REPORT
* macros.
*
* This routine will send the specified string to the DebugMonitor. It will
* also be logged it to the debugger if the RF_log enum was specified. If
* the RF_fatal flag was specified, the routine will display a message box
* with the string in it as well.
*
* @internal
*/
void Report::vprintf(const char *format, va_list va)
{
char buffer[8 * 1024];
// make sure the buffer is always NULL terminated
buffer[sizeof(buffer)-1] = '\0';
// format the string
IGNORE_RETURN(vsnprintf(buffer, sizeof(buffer)-1, format, va));
// handle overflow reasonably nicely
if (strlen(buffer) == sizeof(buffer)-1)
{
buffer[sizeof(buffer)-3] = '+';
buffer[sizeof(buffer)-2] = '\n';
}
puts(buffer);
}
// ----------------------------------------------------------------------
/**
* Format and print a debugging message.
*
* This routine should never be called directly, but only through the REPORT
* macros.
*
* This routine will send the specified string to the DebugMonitor. It will
* also be logged it to the debugger if the RF_log enum was specified. If
* the RF_fatal flag was specified, the routine will display a message box
* with the string in it as well.
*
* @internal
*/
void Report::printf(const char *format, ...)
{
va_list va;
va_start(va, format);
vprintf(format, va);
va_end(va);
}
// ======================================================================
@@ -0,0 +1,71 @@
// ======================================================================
//
// Report.cpp
// copyright 1999 Bootprint Entertainment
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_Report_H
#define INCLUDED_Report_H
// ======================================================================
class Report
{
public:
enum
{
RF_print = BINARY2(0000,0001),
RF_log = BINARY2(0000,0010),
RF_warning = BINARY2(0000,0100),
RF_fatal = BINARY2(0000,1000),
RF_console = BINARY2(0001,0000),
RF_dialog = BINARY2(0010,0000)
};
public:
typedef void (*Callback)(char const *string);
public:
static void install();
static void bindLogCallback(Callback callback);
static void bindWarningCallback(Callback callback);
static void bindFatalCallback(Callback callback);
static DLLEXPORT void setFlags(int flags);
static void puts(const char *string);
static void vprintf(const char *format, va_list va);
static DLLEXPORT void printf(const char *format, ...);
};
// ======================================================================
#define REPORT(expr, flags, printf2) ((expr) ? Report::setFlags(flags), Report::printf printf2 : NOP)
#define REPORT_LOG(expr, printf) REPORT(expr, Report::RF_log, printf)
#define REPORT_PRINT(expr, printf) REPORT(expr, Report::RF_print, printf)
#define REPORT_LOG_PRINT(expr, printf) REPORT(expr, Report::RF_log | Report::RF_print, printf)
#ifdef _DEBUG
#define DEBUG_REPORT(expr, flags, printf) REPORT(expr, flags, printf)
#define DEBUG_REPORT_LOG(expr, printf) REPORT_LOG(expr, printf)
#define DEBUG_REPORT_PRINT(expr, printf) REPORT_PRINT(expr, printf)
#define DEBUG_REPORT_LOG_PRINT(expr,printf) REPORT_LOG_PRINT(expr, printf)
#else
#define DEBUG_REPORT(expr, flags, printf2) NOP
#define DEBUG_REPORT_LOG(expr, printf) NOP
#define DEBUG_REPORT_PRINT(expr, printf) NOP
#define DEBUG_REPORT_LOG_PRINT(expr, printf) NOP
#endif
// ======================================================================
#endif
@@ -0,0 +1,43 @@
// ======================================================================
//
// SetupSharedDebug.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/SetupSharedDebug.h"
#include "sharedDebug/CallStackCollector.h"
#include "sharedDebug/DebugMonitor.h"
#include "sharedDebug/PerformanceTimer.h"
#include "sharedDebug/PixCounter.h"
#include "sharedDebug/ProfilerTimer.h"
#include "sharedDebug/Profiler.h"
#include "sharedFoundation/Production.h"
#ifdef _WIN32
#include "sharedDebug/VTune.h"
#endif
// ======================================================================
void SetupSharedDebug::install(const int maxProfilerEntries)
{
Profiler::install();
UNREF(maxProfilerEntries);
ProfilerTimer::install();
PerformanceTimer::install();
CallStackCollector::install();
#if PRODUCTION == 0
PixCounter::install();
#ifdef _WIN32
VTune::install();
#endif
#endif
}
// ======================================================================
@@ -0,0 +1,27 @@
// ======================================================================
//
// SetupSharedDebug.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_SetupSharedDebug_H
#define INCLUDED_SetupSharedDebug_H
// ======================================================================
class SetupSharedDebug
{
public:
static void install(int maxProfilerEntries);
private:
SetupSharedDebug();
SetupSharedDebug(const SetupSharedDebug &);
SetupSharedDebug &operator =(const SetupSharedDebug &);
};
// ======================================================================
#endif
@@ -0,0 +1,670 @@
// ======================================================================
//
// DebugHelp.cpp
// copyright 2000 Verant Interactive
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/DebugHelp.h"
#include "sharedFoundation/WindowsWrapper.h"
#include <dbghelp.h>
#include <cstdio>
#include <cstring>
// ======================================================================
// ======================================================================
// This was done to keep the header file from having to include <windows.h> or <dbghelp.h>
namespace DebugHelpNamespace
{
static HINSTANCE library;
static HANDLE process;
struct CallbackData
{
const char *name;
bool loaded;
};
typedef DWORD (__stdcall *SymSetOptionsFP)(IN DWORD SymOptions);
typedef BOOL (__stdcall *SymInitializeFP)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess);
typedef BOOL (__stdcall *SymCleanupFP)(IN HANDLE hProcess);
typedef BOOL (__stdcall *StackWalk64FP)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
typedef BOOL (__stdcall *SymGetModuleInfo64FP)(IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PIMAGEHLP_MODULE64 ModuleInfo);
typedef DWORD64 (__stdcall *SymLoadModule64FP)(IN HANDLE hProcess, IN HANDLE hFile, IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll);
typedef BOOL (__stdcall *SymGetSymFromAddr64FP)(IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol);
typedef BOOL (__stdcall *SymGetLineFromAddr64FP)(IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line);
typedef PVOID (__stdcall *SymFunctionTableAccess64FP)(HANDLE hProcess, DWORD64 AddrBase);
typedef DWORD64 (__stdcall *SymGetModuleBase64FP)(IN HANDLE hProcess, IN DWORD64 dwAddr);
typedef BOOL (__stdcall *SymEnumerateModules64FP)(HANDLE hProcess, PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback, PVOID UserContext);
typedef BOOL (__stdcall *EnumerateLoadedModules64FP)(IN HANDLE hProcess, IN PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback, IN PVOID UserContext);
typedef BOOL (__stdcall *MiniDumpWriteDumpFP)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
static SymSetOptionsFP symSetOptions;
static SymInitializeFP symInitialize;
static SymCleanupFP symCleanup;
static StackWalk64FP stackWalk64;
static SymGetModuleInfo64FP symGetModuleInfo64;
static SymLoadModule64FP symLoadModule64;
static SymGetSymFromAddr64FP symGetSymFromAddr64;
static SymGetLineFromAddr64FP symGetLineFromAddr64;
static SymFunctionTableAccess64FP symFunctionTableAccess64;
static SymGetModuleBase64FP symGetModuleBase64;
static SymEnumerateModules64FP symEnumerateModules64;
static EnumerateLoadedModules64FP enumerateLoadedModules64;
static MiniDumpWriteDumpFP miniDumpWriteDump;
static CRITICAL_SECTION criticalSection;
// ----------------------------------------------------------------------
static BOOL CALLBACK loadSymbolsForDllCallback(PTSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext);
// ----------------------------------------------------------------------
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1; /* unsigned 1-byte quantities */
#define hashsize(n) ((ub4)1<<(n))
#define hashmask(n) (hashsize(n)-1)
/*
--------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
For every delta with one or two bits set, and the deltas of all three
high bits or all three low bits, whether the original value of a,b,c
is almost all zero or is uniformly distributed,
* If mix() is run forward or backward, at least 32 bits in a,b,c
have at least 1/4 probability of changing.
* If mix() is run forward, every bit of c will change between 1/3 and
2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
mix() was built out of 36 single-cycle latency instructions in a
structure that could supported 2x parallelism, like so:
a -= b;
a -= c; x = (c>>13);
b -= c; a ^= x;
b -= a; x = (a<<8);
c -= a; b ^= x;
c -= b; x = (b>>13);
...
Unfortunately, superscalar Pentiums and Sparcs can't take advantage
of that parallelism. They've also turned some of those single-cycle
latency instructions into multi-cycle latency instructions. Still,
this is the fastest good hash I could find. There were about 2^^68
to choose from. I only looked at a billion or so.
--------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
/*
--------------------------------------------------------------------
hash() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
len : the length of the key, counting by bytes
initval : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Every 1-bit and 2-bit delta achieves avalanche.
About 6*len+35 instructions.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (ub1 **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
By Bob Jenkins, 1996. [email protected]. You may use this
code any way you wish, private, educational, or commercial. It's free.
See http://burtleburtle.net/bob/hash/evahash.html
Use for hash table lookup, or anything where one collision in 2^^32 is
acceptable. Do NOT use for cryptographic purposes.
--------------------------------------------------------------------
*/
// k; /* the key */
// length; /* the length of the key */
// initval; /* the previous hash, or an arbitrary value */
#if 0
static ub4 hash(ub1 *k, const ub4 length, const ub4 initval)
{
ub4 a, b, c, len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = initval; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12)
{
a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
mix(a,b,c);
k += 12; len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += length;
switch(len) /* all the case statements fall through */
{
case 11: c+=((ub4)k[10]<<24);
case 10: c+=((ub4)k[9]<<16);
case 9 : c+=((ub4)k[8]<<8);
/* the first byte of c is reserved for the length */
case 8 : b+=((ub4)k[7]<<24);
case 7 : b+=((ub4)k[6]<<16);
case 6 : b+=((ub4)k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=((ub4)k[3]<<24);
case 3 : a+=((ub4)k[2]<<16);
case 2 : a+=((ub4)k[1]<<8);
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
mix(a,b,c);
/*-------------------------------------------- report the result */
return c;
}
#endif
// version optimized for 4 byte input.
static ub4 hash_DWORD(const DWORD in, const ub4 initval)
{
ub1 *const k = (ub1 *)&in;
ub4 a, b, c, len;
/* Set up the internal state */
len = 4;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = initval; /* the previous hash value */
/*------------------------------------- handle the last 11 bytes */
c += 4;
a+=((ub4)k[3]<<24);
a+=((ub4)k[2]<<16);
a+=((ub4)k[1]<<8);
a+=k[0];
mix(a,b,c);
/*-------------------------------------------- report the result */
return c;
}
// ----------------------------------------------------------------------
struct BaseAddressLookup
{
DWORD64 keyAddress; // key
DWORD64 baseAddress; // value
};
static BaseAddressLookup * s_baseAddressCache;
static inline unsigned _baseAddressCachePageBits() { return 8; }
static inline unsigned _baseAddressCacheBits() { return _baseAddressCachePageBits() + 12; }
static inline unsigned _baseAddressCacheSize() { return 1 << (_baseAddressCacheBits()); }
static inline unsigned _baseAddressCacheElements() { return _baseAddressCacheSize() / sizeof(*s_baseAddressCache); }
static inline unsigned _baseAddressCacheMask() { return _baseAddressCacheElements() - 1; }
static int s_baseAddressCacheMisses;
static int s_baseAddressCacheHits;
static int s_baseAddressElements;
static int s_baseAddressUsed;
/*
static void _baseAddressCacheAnalyze()
{
s_baseAddressElements=0;
s_baseAddressUsed=0;
unsigned i;
const unsigned count = _baseAddressCacheElements();
for (i=0;i<count;i++)
{
const BaseAddressLookup *lookup = s_baseAddressCache + i;
s_baseAddressElements++;
if (lookup->baseAddress)
{
s_baseAddressUsed++;
}
}
}
*/
static DWORD64 _baseAddressLookup(DWORD64 addr)
{
BaseAddressLookup *lookup;
unsigned long bits = _baseAddressCacheBits();
DWORD *addr32 = (DWORD *)&addr;
unsigned long hash32 = hash_DWORD(addr32[0], addr32[1]);
unsigned long hash = (hash32>>(32-bits)) ^ hash32;
unsigned long mask = _baseAddressCacheMask();
unsigned long index = hash & mask;
lookup = s_baseAddressCache + index;
if (lookup->keyAddress==addr)
{
s_baseAddressCacheHits++;
//DEBUG_FATAL(symGetModuleBase64(process, addr) != lookup->baseAddress, ("Cache failure.\n"));
return lookup->baseAddress;
}
else
{
s_baseAddressCacheMisses++;
DWORD64 baseAddress = symGetModuleBase64(process, addr);
lookup->keyAddress=addr;
lookup->baseAddress=baseAddress;
return baseAddress;
}
}
static DWORD64 __stdcall getModuleBase(HANDLE hProcess, DWORD64 dwAddr)
{
UNREF(hProcess);
DEBUG_FATAL(hProcess!=process, ("Wrong process handle for module base lookup.\n"));
return _baseAddressLookup(dwAddr);
}
// ----------------------------------------------------------------------
struct FunctionTableLookup
{
DWORD64 keyAddress; // key
PVOID functionTable; // value
};
static FunctionTableLookup * s_functionTableCache;
static inline unsigned _functionTableCachePageBits() { return 4; }
static inline unsigned _functionTableCacheBits() { return _functionTableCachePageBits() + 12; }
static inline unsigned _functionTableCacheSize() { return 1 << (_functionTableCacheBits()); }
static inline unsigned _functionTableCacheElements() { return _functionTableCacheSize() / sizeof(*s_functionTableCache); }
static inline unsigned _functionTableCacheMask() { return _functionTableCacheElements() - 1; }
static int s_functionTableCacheMisses;
static int s_functionTableCacheHits;
static PVOID _functionTableLookup(DWORD64 addr)
{
FunctionTableLookup *lookup;
unsigned long bits = _functionTableCacheBits();
DWORD *addr32 = (DWORD *)&addr;
unsigned long hash32 = hash_DWORD(addr32[0], addr32[1]);
unsigned long hash = (hash32>>(32-bits)) ^ hash32;
unsigned long mask = _functionTableCacheMask();
unsigned long index = hash & mask;
lookup = s_functionTableCache + index;
if (lookup->keyAddress==addr)
{
s_functionTableCacheHits++;
//DEBUG_FATAL(symFunctionTableAccess64(process, addr) != lookup->functionTable, ("Cache failure.\n"));
return lookup->functionTable;
}
else
{
s_functionTableCacheMisses++;
PVOID functionTable = symFunctionTableAccess64(process, addr);
lookup->keyAddress=addr;
lookup->functionTable=functionTable;
return functionTable;
}
}
static PVOID __stdcall functionTableAccess(HANDLE hProcess, DWORD64 dwAddr)
{
UNREF(hProcess);
DEBUG_FATAL(hProcess!=process, ("Wrong process handle for module base lookup.\n"));
return _functionTableLookup(DWORD(dwAddr));
}
// ----------------------------------------------------------------------
}
using namespace DebugHelpNamespace;
// ----------------------------------------------------------------------
BOOL CALLBACK DebugHelpNamespace::loadSymbolsForDllCallback(PTSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext)
{
if (!library)
return false;
CallbackData *callbackData = reinterpret_cast<CallbackData *>(UserContext);
// see if this is the right file module and if we can load its symbol information
if (_stricmp(ModuleName, callbackData->name) == 0 && symLoadModule64(process, NULL, ModuleName, 0, ModuleBase, ModuleSize) != 0)
{
callbackData->loaded = true;
return FALSE;
}
return TRUE;
}
// ======================================================================
void DebugHelp::install()
{
DEBUG_FATAL(library, ("DebugHelp already installed"));
library = LoadLibrary("dbghelp_6.3.17.0.dll");
if (library)
{
process = GetCurrentProcess();
#define GPA(a, b) a = reinterpret_cast<b##FP>(GetProcAddress(library, #b)); DEBUG_FATAL(!a, ("GetProcAddress failed for " #b))
GPA(symSetOptions, SymSetOptions);
GPA(symInitialize, SymInitialize);
GPA(symCleanup, SymCleanup);
GPA(stackWalk64, StackWalk64);
GPA(symGetModuleInfo64, SymGetModuleInfo64);
GPA(symLoadModule64, SymLoadModule64);
GPA(symGetSymFromAddr64, SymGetSymFromAddr64);
GPA(symGetLineFromAddr64, SymGetLineFromAddr64);
GPA(symFunctionTableAccess64, SymFunctionTableAccess64);
GPA(symGetModuleBase64, SymGetModuleBase64);
GPA(symEnumerateModules64, SymEnumerateModules64);
GPA(enumerateLoadedModules64, EnumerateLoadedModules64);
GPA(miniDumpWriteDump, MiniDumpWriteDump);
#undef GPA
IGNORE_RETURN(symSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES));
// get the path to the executable
char executableDirectory[MAX_PATH * 2];
const DWORD result = GetModuleFileName(NULL, executableDirectory, sizeof(executableDirectory));
FATAL(result == 0, ("GetModuleFileName failed"));
char * const slash = strrchr(executableDirectory, '\\');
DEBUG_FATAL(!slash, ("Executable path does not contain a slash"));
*slash = '\0';
const BOOL result1 = symInitialize(process, executableDirectory, TRUE);
UNREF(result1);
DEBUG_FATAL(!result1, ("SymInitialize failed"));
// -----------------------------------------------------------------------
s_baseAddressCache = (BaseAddressLookup *)VirtualAlloc(0, _baseAddressCacheSize(), MEM_COMMIT, PAGE_READWRITE);
s_functionTableCache = (FunctionTableLookup *)VirtualAlloc(0, _functionTableCacheSize(), MEM_COMMIT, PAGE_READWRITE);
// -----------------------------------------------------------------------
}
// Initialize the critical section one time only.
InitializeCriticalSection(&criticalSection);
}
// ----------------------------------------------------------------------
void DebugHelp::remove()
{
if (s_baseAddressCache)
{
VirtualFree(s_baseAddressCache, 0, MEM_RELEASE);
s_baseAddressCache=0;
}
if (s_functionTableCache)
{
VirtualFree(s_functionTableCache, 0, MEM_RELEASE);
s_functionTableCache=0;
}
if (library)
{
IGNORE_RETURN(symCleanup(process));
IGNORE_RETURN(FreeLibrary(library));
library = NULL;
process = NULL;
symSetOptions = NULL;
symInitialize = NULL;
symCleanup = NULL;
stackWalk64 = NULL;
symGetModuleInfo64 = NULL;
symLoadModule64 = NULL;
symGetSymFromAddr64 = NULL;
symGetLineFromAddr64 = NULL;
symFunctionTableAccess64 = NULL;
symGetModuleBase64 = NULL;
symEnumerateModules64 = NULL;
enumerateLoadedModules64 = NULL;
}
// Release resources used by the critical section object.
DeleteCriticalSection(&criticalSection);
}
// ----------------------------------------------------------------------
bool DebugHelp::loadSymbolsForDll(const char *name)
{
if (!library)
return false;
CallbackData callbackData = { name, false };
enumerateLoadedModules64(process, loadSymbolsForDllCallback, reinterpret_cast<void *>(&callbackData));
return callbackData.loaded;
}
// ----------------------------------------------------------------------
#pragma warning (disable: 4740 4748)
void DebugHelp::getCallStack(uint32 *callStack, int sizeOfCallStack)
{
{
for (int i = 0; i < sizeOfCallStack; ++i)
callStack[i] = 0;
}
if (!library)
return;
CONTEXT context;
Zero(context);
context.ContextFlags = CONTEXT_FULL;
// GetThreadContext returns invalid data when called from within the same thread
//if (!GetThreadContext(GetCurrentThread(), &context))
// return;
EnterCriticalSection(&criticalSection);
__asm
{
call GetEIP
GetEIP:
pop eax
mov context.Eip, eax
mov context.Esp, esp
mov context.Ebp, ebp
}
LeaveCriticalSection(&criticalSection);
STACKFRAME64 stackFrame;
Zero(stackFrame);
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrPC.Offset = context.Eip;
stackFrame.AddrStack.Offset = context.Esp;
stackFrame.AddrStack.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = context.Ebp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
for (int i = 0; i < sizeOfCallStack; ++i, ++callStack)
{
if (stackWalk64(IMAGE_FILE_MACHINE_I386, process, process, &stackFrame, &context, NULL, functionTableAccess, getModuleBase, NULL))
{
const DWORD64 Offset = stackFrame.AddrPC.Offset;
*callStack = DWORD(Offset);
}
}
}
// ----------------------------------------------------------------------
void DebugHelp::reportCallStack(int const maxStackDepth)
{
// look up the call stack information
int const callStackOffset = 2;
int const callStackSize = callStackOffset + maxStackDepth;
uint32 * callStack = static_cast<uint32 *>(_alloca((callStackOffset + maxStackDepth) * sizeof(uint32)));
getCallStack(callStack, callStackOffset + maxStackDepth);
// look up the caller's file and line
if (callStack[callStackOffset])
{
char lib[4 * 1024] = { '\0' };
char file[4 * 1024] = { '\0' };
int line = 0;
for (int i = callStackOffset; i < callStackSize; ++i)
{
if (callStack[i])
{
if (lookupAddress(callStack[i], lib, file, sizeof(file), line))
REPORT_LOG(true, ("\t%s(%d) : caller %d\n", file, line, i-callStackOffset));
else
REPORT_LOG(true, ("\tunknown(0x%08X) : caller %d\n", static_cast<int>(callStack[i]), i-callStackOffset));
}
}
}
}
// ----------------------------------------------------------------------
bool DebugHelp::lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line)
{
UNREF(libName);
if (!library)
return false;
// make sure the image is loaded
IMAGEHLP_MODULE64 imageHelpModule;
Zero(imageHelpModule);
imageHelpModule.SizeOfStruct = sizeof(imageHelpModule);
if (!symGetModuleInfo64(process, address, &imageHelpModule))
return false;
// look up the symbol
const int MaxNameLength = 256;
char buffer[sizeof(IMAGEHLP_SYMBOL64) + MaxNameLength];
memset(buffer, 0, sizeof(buffer));
IMAGEHLP_SYMBOL64 *imageHelpSymbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(buffer);
imageHelpSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
imageHelpSymbol->Address = address;
imageHelpSymbol->MaxNameLength = MaxNameLength;
{
DWORD64 displacement = 0;
if (!symGetSymFromAddr64(process, address, &displacement, imageHelpSymbol))
{
return false;
}
}
// look up the source file name and line number
IMAGEHLP_LINE64 imageHelpLine;
Zero(imageHelpLine);
imageHelpLine.SizeOfStruct = sizeof(imageHelpLine);
{
DWORD displacement = 0;
if (!symGetLineFromAddr64(process, address, &displacement, &imageHelpLine))
{
return false;
}
}
// return the results
strncpy(fileName, imageHelpLine.FileName, static_cast<uint>(fileNameLength));
line = static_cast<int>(imageHelpLine.LineNumber);
return true;
}
// ----------------------------------------------------------------------
bool DebugHelp::writeMiniDump(char const *miniDumpFileName, PEXCEPTION_POINTERS exceptionPointers)
{
if (!miniDumpWriteDump)
return false;
char buffer[256];
if (!miniDumpFileName)
{
// get the program name
char programName[512];
DWORD result = GetModuleFileName(NULL, programName, sizeof(programName));
if (result == 0)
return false;
// get the file name without the path
const char *shortProgramName = strrchr(programName, '\\');
if (shortProgramName)
++shortProgramName;
else
shortProgramName = programName;
// lop off the extension
char *dot = const_cast<char *>(strchr(shortProgramName, '.'));
if (dot)
*dot = '\0';
// create a reasonable minidump filename
snprintf(buffer, sizeof(buffer), "%s_%d.mdmp", shortProgramName, static_cast<int>(GetCurrentProcessId()));
miniDumpFileName = buffer;
}
// create the file
HANDLE const file = CreateFile(miniDumpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL);
if (file == INVALID_HANDLE_VALUE)
return false;
// create the exception information
MINIDUMP_EXCEPTION_INFORMATION exceptionInformationData;
MINIDUMP_EXCEPTION_INFORMATION *exceptionInformation = 0;
if (exceptionPointers)
{
exceptionInformationData.ThreadId = GetCurrentThreadId();
exceptionInformationData.ExceptionPointers = exceptionPointers;
exceptionInformationData.ClientPointers = true;
exceptionInformation = &exceptionInformationData;
}
// @todo make the minidump style modifiable
BOOL const result = miniDumpWriteDump(process, GetCurrentProcessId(), file, MiniDumpNormal, exceptionInformation, NULL, NULL);
// close the file
CloseHandle(file);
return result ? true : false;
}
// ======================================================================
@@ -0,0 +1,35 @@
// ======================================================================
//
// DebugHelp.h
// copyright 2000 Verant Interactive
//
// ======================================================================
#ifndef DEBUG_HELP_H
#define DEBUG_HELP_H
// ======================================================================
typedef unsigned long uint32;
// ======================================================================
class DebugHelp
{
public:
static void install();
static void remove();
static bool loadSymbolsForDll(const char *name);
static void getCallStack(uint32 *callStack, int sizeOfCallStack);
static void reportCallStack(int const maxStackDepth = 4);
static bool lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line);
static bool writeMiniDump(char const *miniDumpFileName=0, PEXCEPTION_POINTERS exceptionPointers=0);
};
// ======================================================================
#endif
@@ -0,0 +1,321 @@
// ======================================================================
//
// DebugMonitor.cpp
// copyright 1998 Bootprint Entertainment
// copyright 2001-2004 Sony Online Entertainment
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/DebugMonitor.h"
#if PRODUCTION == 0
#include "sharedDebug/DebugFlags.h"
#include "sharedFoundation/ConfigFile.h"
// ======================================================================
namespace DebugMonitorNamespace
{
typedef void (*ChangedWindowCallback)(int x, int y, int width, int height);
typedef bool (*InstallFunction)(int x, int y, int width, int height);
typedef void (*RemoveFunction)();
typedef void (*ShowFunction)();
typedef void (*HideFunction)();
typedef void (*SetChangedWindowCallback)(ChangedWindowCallback);
typedef void (*SetBehindWindowFunction)(HWND window);
typedef void (*ClearScreenFunction)();
typedef void (*ClearToCursorFunction)();
typedef void (*GotoXYFunction)(int x, int y);
typedef void (*PrintFunction)(const char *string);
void changedWindowCallback(int x, int y, int width, int height);
HINSTANCE dll;
HKEY registryKey = HKEY_CLASSES_ROOT;
RemoveFunction removeFunction;
ShowFunction showFunction;
HideFunction hideFunction;
SetBehindWindowFunction setBehindWindowFunction;
ClearScreenFunction clearScreenFunction;
ClearToCursorFunction clearToCursorFunction;
GotoXYFunction gotoXYFunction;
PrintFunction printFunction;
bool noClear;
int GetRegistryValue(char const * name, int defaultValue)
{
int value;
DWORD type = 0;
DWORD size = sizeof(DWORD);
LONG result = RegQueryValueEx(registryKey, name, NULL, &type, reinterpret_cast<LPBYTE>(&value), &size);
if (result != ERROR_SUCCESS || type != REG_DWORD && size != sizeof(int))
value = defaultValue;
return value;
}
void SetRegistryValue(char const * name, int value)
{
RegSetValueEx(registryKey, name, NULL, REG_DWORD, reinterpret_cast<const LPBYTE>(&value), sizeof(int));
}
}
using namespace DebugMonitorNamespace;
// ======================================================================
// Install the debug monitor subsystem
//
// Remarks:
//
// This routine will first attempt to install the selected debug monitor.
void DebugMonitor::install()
{
dll = LoadLibrary("debugWindow.dll");
if (dll)
{
InstallFunction installFunction = reinterpret_cast<InstallFunction>(GetProcAddress(dll, "install"));
RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Sony Online Entertainment\\DebugWindow", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &registryKey, NULL);
int const x = ConfigFile::getKeyInt("SharedDebug", "debugWindowX", GetRegistryValue("x", 0));
int const y = ConfigFile::getKeyInt("SharedDebug", "debugWindowY", GetRegistryValue("y", 0));
int const width = ConfigFile::getKeyInt("SharedDebug", "debugWindowWidth", GetRegistryValue("width", 80));
int const height = ConfigFile::getKeyInt("SharedDebug", "debugWindowHeight", GetRegistryValue("height", 50));
if (installFunction && installFunction(x, y, width, height))
{
showFunction = reinterpret_cast<ShowFunction>(GetProcAddress(dll, "showWindow"));
hideFunction = reinterpret_cast<ShowFunction>(GetProcAddress(dll, "hideWindow"));
removeFunction = reinterpret_cast<RemoveFunction>(GetProcAddress(dll, "remove"));
setBehindWindowFunction = reinterpret_cast<SetBehindWindowFunction>(GetProcAddress(dll, "setBehindWindow"));
clearScreenFunction = reinterpret_cast<ClearScreenFunction>(GetProcAddress(dll, "clearScreen"));
clearToCursorFunction = reinterpret_cast<ClearToCursorFunction>(GetProcAddress(dll, "clearToCursor"));
gotoXYFunction = reinterpret_cast<GotoXYFunction>(GetProcAddress(dll, "gotoXY"));
printFunction = reinterpret_cast<PrintFunction>(GetProcAddress(dll, "print"));
SetChangedWindowCallback setChangedWindowCallback = reinterpret_cast<SetChangedWindowCallback>(GetProcAddress(dll, "setChangedWindowCallback"));
if (setChangedWindowCallback)
(*setChangedWindowCallback)(changedWindowCallback);
DebugFlags::registerFlag(noClear, "SharedDebug", "noDebugMonitorClear");
if (ConfigFile::getKeyBool("SharedDebug", "debugWindow", false))
show();
}
else
{
installFunction = NULL;
const BOOL result = FreeLibrary(dll);
dll = NULL;
UNREF(result);
DEBUG_FATAL(!result, ("FreeLibrary failed"));
}
}
}
// ----------------------------------------------------------------------
/**
* Remove the debug monitor subsystem.
*/
void DebugMonitor::remove()
{
if (removeFunction)
removeFunction();
removeFunction = NULL;
setBehindWindowFunction = NULL;
clearScreenFunction = NULL;
clearToCursorFunction = NULL;
gotoXYFunction = NULL;
printFunction = NULL;
if (dll)
{
const BOOL result = FreeLibrary(dll);
UNREF(result);
DEBUG_FATAL(!result, ("FreeLibrary failed"));
dll = NULL;
if (registryKey != HKEY_CLASSES_ROOT)
{
RegCloseKey(registryKey);
registryKey = HKEY_CLASSES_ROOT;
}
}
}
// ----------------------------------------------------------------------
void DebugMonitorNamespace::changedWindowCallback(int const x, int const y, int const width, int const height)
{
SetRegistryValue("x", x);
SetRegistryValue("y", y);
SetRegistryValue("width", width);
SetRegistryValue("height", height);
}
// ----------------------------------------------------------------------
void DebugMonitor::show()
{
if (showFunction)
(*showFunction)();
}
// ----------------------------------------------------------------------
void DebugMonitor::hide()
{
if (hideFunction)
(*hideFunction)();
}
// ----------------------------------------------------------------------
/**
* Set the debug window's z-order.
*/
void DebugMonitor::setBehindWindow(HWND window)
{
if (setBehindWindowFunction)
setBehindWindowFunction(window);
}
// ----------------------------------------------------------------------
/**
* Clear the debug monitor and home the cursor.
*
* If the mono monitor is not installed, this routine does nothing.
*
* This routine will clear the contents of the debug monitor, reset the screen
* offset to 0, and move the cursor to the upper left corner of the screen.
*
* @see DebugMonitor::home(), DebugMonitor::clearToCursor()
*/
void DebugMonitor::clearScreen()
{
if (noClear)
return;
if (clearScreenFunction)
clearScreenFunction();
}
// ----------------------------------------------------------------------
/**
* Clear the debug monitor to the current cursor position and home the cursor.
*
* If the debug monitor is not installed, this routine does nothing.
*
* This routine will clear the contents of the debug monitor only up to the
* cursor position. If the cursor is not very far down on the screen,
* this routine may be significantly more efficient clearing the screen.
*
* It will also move the cursor to the upper left corner of the screen.
*
* @see DebugMonitor::clearScreen(), DebugMonitor::home()
*/
void DebugMonitor::clearToCursor()
{
if (clearToCursorFunction)
clearToCursorFunction();
else
clearScreen();
}
// ======================================================================
// Move the cursor to the upper left hand corner of the mono monitor screen
//
// Remarks:
//
// If the debug monitor is not installed, this routine does nothing.
//
// All printing happens at the cursor position.
//
// This routine is identical to calling gotoXY(0,0);
//
// See Also:
//
// DebugMonitor::gotoXY()
void DebugMonitor::home()
{
gotoXY(0,0);
}
// ----------------------------------------------------------------------
/**
* Position the cursor on the debug monitor screen.
*
* If the debug monitor is not installed, this routine does nothing.
*
* All printing happens at the cursor position.
*
* @param x New X position for the cursor
* @param y New Y position for the cursor
*/
void DebugMonitor::gotoXY(int x, int y)
{
if (gotoXYFunction)
gotoXYFunction(x, y);
}
// ----------------------------------------------------------------------
/**
* Display a string on the debug monitor.
*
* If the debug monitor is not installed, this routine does nothing.
*
* Printing occurs from the cursor position.
*
* Newline characters '\n' will cause the cursor position to advance to the
* beginning of the next line. If the cursor is already on the last line of
* the screen, the screen will scroll up one line and the cursor will move to
* the beginning of the last line.
*
* The backspace character '\b' will cause the cursor to move one character
* backwards. If at the beginning of the line, the cursor will move to the
* end of the previous line. If already on the first line of the screen, the
* cursor position and screen contents will be unchanged.
*
* All other characters are placed directly into the text frame buffer.
* After each character, the cursor will be logically advanced one
* character forward. If the cursor was on the last column, it will advance
* to the next line. If the cursor was already on the last line, the screen
* will be scrolled up one line and the cursor will move to the beginning of
* the last line.
*
* @param string String to display on the debug monitor
*/
void DebugMonitor::print(const char *string)
{
if (printFunction)
printFunction(string);
}
// ----------------------------------------------------------------------
/**
* Ensure all changes to the DebugMonitor have taken effect by the time
* this function returns.
*
* Note: some platforms may do nothing here. The Win32 platform does not
* require flushing. The Linux platform does. Call it assuming
* that it is needed. It will be a no-op when not required.
*/
void DebugMonitor::flushOutput()
{
// Win32 debug monitors don't need to do anything here.
}
// ======================================================================
#endif
@@ -0,0 +1,48 @@
// ======================================================================
//
// DebugMonitor.h
//
// Portions copyright 1998 Bootprint Entertainment
// Portions copyright 2002-2004 Sony Online Entertainment
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_DebugMonitor_H
#define INCLUDED_DebugMonitor_H
// ======================================================================
#include "sharedFoundation/Production.h"
// ======================================================================
#if PRODUCTION == 0
class DebugMonitor
{
public:
static void install();
static void remove();
static void setBehindWindow(HWND window);
static void show();
static void hide();
static void clearScreen();
static void clearToCursor();
static void home();
static void gotoXY(int x, int y);
static void print(const char *string);
static void flushOutput();
};
#endif
// ======================================================================
#endif
@@ -0,0 +1,8 @@
// ======================================================================
//
// FirstDebug.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "shareddebug/FirstSharedDebug.h"
@@ -0,0 +1,105 @@
//
// PerformanceTimer.cpp
// Copyright 2000-2004 Sony Online Entertainment
//
//-------------------------------------------------------------------
#include "shareddebug/FirstSharedDebug.h"
#include "shareddebug/PerformanceTimer.h"
//-------------------------------------------------------------------
#include <cstdio>
//-------------------------------------------------------------------
__int64 PerformanceTimer::ms_frequency;
//-------------------------------------------------------------------
void PerformanceTimer::install()
{
BOOL result = QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&ms_frequency));
FATAL(!result, ("PerformanceTimer::install QPF failed"));
}
//-------------------------------------------------------------------
PerformanceTimer::PerformanceTimer() :
m_startTime (0),
m_stopTime (0)
{
DEBUG_FATAL (ms_frequency == 0.f, ("PerformanceTimer not installed"));
}
//-------------------------------------------------------------------
PerformanceTimer::~PerformanceTimer()
{
}
//-------------------------------------------------------------------
void PerformanceTimer::start()
{
//-- get the current time
BOOL result = QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&m_startTime));
DEBUG_FATAL(!result, ("PerformanceTimer::start QPC failed"));
UNREF (result);
}
//-------------------------------------------------------------------
void PerformanceTimer::resume()
{
__int64 delta = m_stopTime - m_startTime;
start();
m_startTime -= delta;
}
//-------------------------------------------------------------------
void PerformanceTimer::stop ()
{
//-- get the current time
BOOL result = QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&m_stopTime));
DEBUG_FATAL(!result, ("PerformanceTimer::stop QPC failed"));
UNREF (result);
}
//-------------------------------------------------------------------
float PerformanceTimer::getElapsedTime() const
{
return static_cast<float> (m_stopTime - m_startTime) / static_cast<float> (ms_frequency);
}
// ----------------------------------------------------------------------
float PerformanceTimer::getSplitTime() const
{
__int64 currentTime;
BOOL result = QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&currentTime));
UNREF(result);
DEBUG_FATAL(!result, ("PerformanceTimer::getSplitTime QPC failed"));
return static_cast<float> (currentTime - m_startTime) / static_cast<float> (ms_frequency);
}
//-------------------------------------------------------------------
void PerformanceTimer::logElapsedTime(const char* string) const
{
UNREF (string);
#ifdef _DEBUG
static char buffer [1000];
sprintf (buffer, "%s : %1.5f seconds\n", string ? string : "null", getElapsedTime());
DEBUG_REPORT_LOG_PRINT (true, ("%s", buffer));
DEBUG_OUTPUT_CHANNEL("Foundation\\PerformanceTimer", ("%s", buffer));
#endif
}
//-------------------------------------------------------------------
@@ -0,0 +1,49 @@
//
// PerformanceTimer.h
// Copyright 2000-2004 Sony Online Entertainment
//
//-------------------------------------------------------------------
#ifndef INCLUDED_PerformanceTimer_H
#define INCLUDED_PerformanceTimer_H
//-------------------------------------------------------------------
class PerformanceTimer
{
public:
static void install();
public:
DLLEXPORT PerformanceTimer();
DLLEXPORT ~PerformanceTimer();
void DLLEXPORT start();
void DLLEXPORT resume();
void DLLEXPORT stop();
float DLLEXPORT getElapsedTime() const;
float getSplitTime() const; // Get the time since the timer was started without stopping the timer.
void logElapsedTime(const char* string) const;
private:
PerformanceTimer(PerformanceTimer const &);
PerformanceTimer & operator=(PerformanceTimer const &);
private:
static __int64 ms_frequency;
private:
__int64 m_startTime;
__int64 m_stopTime;
};
//-------------------------------------------------------------------
#endif
@@ -0,0 +1,90 @@
// ======================================================================
//
// ProfilerTimer.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "shareddebug/FirstSharedDebug.h"
#include "shareddebug/ProfilerTimer.h"
#include "shareddebug/DebugFlags.h"
#include "sharedFoundation/WindowsWrapper.h"
// ======================================================================
namespace ProfilerTimerNamespace
{
ProfilerTimer::Type ms_qpcFrequency;
float ms_floatQpcFrequency;
__int64 ms_rdtsc;
__int64 ms_qpc;
bool ms_useRdtsc;
}
using namespace ProfilerTimerNamespace;
// ======================================================================
static __int64 __declspec(naked) __stdcall readTimeStampCounter()
{
__asm
{
rdtsc;
ret;
}
}
// ======================================================================
void ProfilerTimer::install()
{
IGNORE_RETURN(QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&ms_qpc)));
ms_rdtsc = readTimeStampCounter();
IGNORE_RETURN(QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&ms_qpcFrequency)));
ms_floatQpcFrequency = static_cast<float>(ms_qpcFrequency);
DebugFlags::registerFlag(ms_useRdtsc, "SharedDebug/Profiler", "useRdtsc");
}
// ----------------------------------------------------------------------
void ProfilerTimer::getTime(Type &time)
{
if (ms_useRdtsc)
time = readTimeStampCounter();
else
IGNORE_RETURN(QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&time)));
}
// ----------------------------------------------------------------------
void ProfilerTimer::getCalibratedTime(Type &time, Type &frequency)
{
if (ms_useRdtsc)
{
__int64 qpc;
IGNORE_RETURN(QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&qpc)));
__int64 rdtsc = readTimeStampCounter();
float const t = static_cast<float>(qpc - ms_qpc) / ms_floatQpcFrequency;
frequency = static_cast<__int64>(static_cast<float>(rdtsc - ms_rdtsc) / t);
time = rdtsc;
ms_qpc = qpc;
ms_rdtsc = time;
}
else
{
IGNORE_RETURN(QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&time)));
frequency = ms_qpcFrequency;
}
}
void ProfilerTimer::getFrequency(Type &frequency)
{
frequency = ms_qpcFrequency;
}
// ======================================================================
@@ -0,0 +1,29 @@
// ======================================================================
//
// ProfilerTimer.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_ProfilerTimer_H
#define INCLUDED_ProfilerTimer_H
// ======================================================================
class ProfilerTimer
{
public:
typedef __int64 Type;
public:
static void install();
static void getTime(Type &time);
static void getCalibratedTime(Type &time, Type &frequency);
static void getFrequency(Type &frequency);
};
// ======================================================================
#endif
@@ -0,0 +1,142 @@
// ======================================================================
//
// VTune.cpp
// Copyright 2000-01, Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedDebug/VTune.h"
#if PRODUCTION == 0
#include "sharedDebug/DebugFlags.h"
#include <vtune/vtuneapi.h>
// ======================================================================
HMODULE VTune::ms_module;
VTune::PauseFunction VTune::ms_pauseFunction;
VTune::ResumeFunction VTune::ms_resumeFunction;
VTune::State VTune::ms_state;
bool VTune::ms_resumeNextFrame;
bool VTune::ms_pauseNextFrame;
bool VTune::ms_debugReport;
// ======================================================================
void VTune::install()
{
DEBUG_FATAL(ms_module, ("vtune already installed"));
ms_module = LoadLibrary("VTuneAPI");
if (!ms_module)
return;
ms_pauseFunction = reinterpret_cast<PauseFunction>(GetProcAddress(ms_module, "VTPause"));
ms_resumeFunction = reinterpret_cast<PauseFunction>(GetProcAddress(ms_module, "VTResume"));
ms_state = S_default;
#if PRODUCTION == 0
DebugFlags::registerFlag(ms_debugReport, "SharedDebug", "vtuneState", debugReport);
#endif
}
// ----------------------------------------------------------------------
void VTune::remove()
{
if (ms_module)
{
FreeLibrary(ms_module);
ms_pauseFunction = 0;
ms_resumeFunction = 0;
}
}
// ----------------------------------------------------------------------
void VTune::debugReport()
{
switch (ms_state)
{
case S_default:
REPORT_PRINT(true, ("Vtune state unknown\n"));
break;
case S_sampling:
REPORT_PRINT(true, ("Vtune is sampling\n"));
break;
case S_paused:
REPORT_PRINT(true, ("Vtune is NOT sampling\n"));
break;
default:
DEBUG_FATAL(true, ("bad case"));
}
}
// ----------------------------------------------------------------------
void VTune::resume()
{
if (ms_module && ms_resumeFunction)
{
MessageBeep(MB_OK);
(*ms_resumeFunction)();
ms_state = S_sampling;
}
}
// ----------------------------------------------------------------------
void VTune::pause()
{
if (ms_module && ms_pauseFunction)
{
(*ms_pauseFunction)();
MessageBeep(MB_ICONEXCLAMATION);
ms_state = S_paused;
}
}
// ----------------------------------------------------------------------
void VTune::pauseNextFrame()
{
ms_pauseNextFrame = true;
ms_resumeNextFrame = false;
}
// ----------------------------------------------------------------------
void VTune::resumeNextFrame()
{
ms_pauseNextFrame = false;
ms_resumeNextFrame = true;
}
// ----------------------------------------------------------------------
void VTune::beginFrame()
{
if (ms_pauseNextFrame)
{
pause();
ms_pauseNextFrame = false;
}
if (ms_resumeNextFrame)
{
resume();
ms_resumeNextFrame = false;
}
}
// ======================================================================
#endif // PRODUCTION == 0
@@ -0,0 +1,65 @@
// ======================================================================
//
// VTune.h
// Copyright 2000-01, Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_VTune_H
#define INCLUDED_VTune_H
// ======================================================================
#include "sharedFoundation/Production.h"
// ======================================================================
#if PRODUCTION == 0
class VTune
{
public:
static void install();
static void resume();
static void pause();
static void resumeNextFrame();
static void pauseNextFrame();
static void beginFrame();
private:
static void remove();
static void debugReport();
private:
enum State
{
S_default,
S_sampling,
S_paused
};
typedef void (__cdecl *PauseFunction)(void);
typedef void (__cdecl *ResumeFunction)(void);
private:
static HMODULE ms_module;
static PauseFunction ms_pauseFunction;
static ResumeFunction ms_resumeFunction;
static State ms_state;
static bool ms_resumeNextFrame;
static bool ms_pauseNextFrame;
static bool ms_debugReport;
};
#endif // PRODUCTION == 0
// ======================================================================
#endif
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 2.8)
project(sharedFoundationTypes)
if(WIN32)
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public)
add_subdirectory(src)
@@ -0,0 +1,27 @@
set(SHARED_SOURCES
shared/FoundationTypes.h
)
if(WIN32)
set(PLATFORM_SOURCES
win32/FoundationTypesWin32.h
)
set(EXCLUDE_PROJECT "")
else()
set(PLATFORM_SOURCES
linux/FoundationTypesLinux.h
)
set(EXCLUDE_PROJECT "EXCLUDE_FROM_ALL")
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared)
add_library(sharedFoundationTypes STATIC ${EXCLUDE_PROJECT}
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
set_target_properties(sharedFoundationTypes PROPERTIES LINKER_LANGUAGE CXX)
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 2.8)
project(sharedMemoryManager)
if(WIN32)
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public)
add_subdirectory(src)
@@ -0,0 +1,7 @@
#if defined(PLATFORM_WIN32)
#include "../../src/win32/OsMemory.h"
#elif defined(PLATFORM_LINUX)
#include "../../src/linux/OsMemory.h"
#else
#error unsupported platform
#endif
@@ -0,0 +1 @@
#include "../../src/shared/FirstSharedMemoryManager.h"
@@ -0,0 +1 @@
#include "../../src/shared/MemoryManager.h"
@@ -0,0 +1,7 @@
#if defined(PLATFORM_WIN32)
#include "../../src/win32/OsNewDel.h"
#elif defined(PLATFORM_LINUX)
#include "../../src/linux/OsNewDel.h"
#else
#error unsupported platform
#endif
@@ -0,0 +1,37 @@
set(SHARED_SOURCES
shared/FirstSharedMemoryManager.cpp
shared/FirstSharedMemoryManager.h
shared/MemoryManager.cpp
shared/MemoryManager.h
)
if(WIN32)
set(PLATFORM_SOURCES
win32/OsMemory.cpp
win32/OsMemory.h
win32/OsNewDel.cpp
win32/OsNewDel.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32)
else()
set(PLATFORM_SOURCES
linux/OsMemory.cpp
linux/OsMemory.h
linux/OsNewDel.cpp
linux/OsNewDel.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/linux)
endif()
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/shared
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
)
add_library(sharedMemoryManager STATIC
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
@@ -0,0 +1,40 @@
// ======================================================================
//
// OsMemory.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
#include "sharedMemoryManager/OsMemory.h"
// ======================================================================
void OsMemory::install()
{
}
// ----------------------------------------------------------------------
void OsMemory::remove()
{
}
// ----------------------------------------------------------------------
void *OsMemory::commit(void *, size_t bytes)
{
return ::malloc(bytes);
}
// ----------------------------------------------------------------------
bool OsMemory::free(void *addr, size_t)
{
::free(addr);
return true;
}
// ======================================================================
@@ -0,0 +1,29 @@
// ======================================================================
//
// OsMemory.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_OsMemory_H
#define INCLUDED_OsMemory_H
// ======================================================================
class OsMemory
{
public:
static void install();
static void remove();
static void * reserve(size_t bytes);
static void * commit(void *addr, size_t bytes);
static bool free(void *addr, size_t bytes);
static bool protect(void *addr, size_t bytes, bool allowAccess);
};
// ======================================================================
#endif // INCLUDED_OsMemory_H
@@ -0,0 +1,134 @@
// ======================================================================
//
// OsNewDel.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
#include "sharedMemoryManager/MemoryManager.h"
#include "sharedMemoryManager/OsNewDel.h"
#include <malloc.h>
#include <unistd.h>
#include <sys/mman.h>
static MemoryManager memoryManager __attribute__ ((init_priority (101)));
#define USE_LIBC_MALLOC_HOOKS 0
#if USE_LIBC_MALLOC_HOOKS
extern "C"
{
void memoryManagerFreeHook(__malloc_ptr_t __ptr, __const __malloc_ptr_t)
{
delete[] (char *)__ptr;
}
__malloc_ptr_t memoryManagerMallocHook(size_t __size, const __malloc_ptr_t)
{
return new char[__size];
}
__malloc_ptr_t memoryManagerReallocHook(__malloc_ptr_t __ptr, size_t size, __const __malloc_ptr_t)
{
if(! __ptr)
return new char[size];
return MemoryManager::reallocate(__ptr, size);
}
__malloc_ptr_t memoryManagerMemAlignHook(size_t alignment, size_t size, __const __malloc_ptr_t)
{
DEBUG_FATAL(true, ("memalign not implemented!"));
return new char[size];
}
static void memoryManagerMallocInitializeHook(void)
{
__free_hook = memoryManagerFreeHook;
__malloc_hook = memoryManagerMallocHook;
__realloc_hook = memoryManagerReallocHook;
__memalign_hook = memoryManagerMemAlignHook;
}
void (*__malloc_initialize_hook) (void) = memoryManagerMallocInitializeHook;
}
#endif//USE_LIBC_MALLOC_HOOKS
// ======================================================================
void *operator new(size_t size, MemoryManagerNotALeak) throw (std::bad_alloc)
{
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), false, false);
}
// ----------------------------------------------------------------------
void *operator new(size_t size) throw (std::bad_alloc)
{
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), false, true);
}
// ----------------------------------------------------------------------
void *operator new[](size_t size) throw (std::bad_alloc)
{
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), true, true);
}
// ----------------------------------------------------------------------
void *operator new(size_t size, const char *file, int line) throw (std::bad_alloc)
{
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), false, true);
}
// ----------------------------------------------------------------------
void *operator new[](size_t size, const char *file, int line) throw (std::bad_alloc)
{
return MemoryManager::allocate(size, reinterpret_cast<uint32>(__builtin_return_address(0)), true, true);
}
// ----------------------------------------------------------------------
void operator delete(void *pointer) throw()
{
if (pointer)
MemoryManager::free(pointer, false);
}
// ----------------------------------------------------------------------
void operator delete[](void *pointer) throw()
{
if (pointer)
MemoryManager::free(pointer, true);
}
// ----------------------------------------------------------------------
void operator delete(void *pointer, const char *file, int line) throw()
{
UNREF(file);
UNREF(line);
if (pointer)
MemoryManager::free(pointer, false);
}
// ----------------------------------------------------------------------
void operator delete[](void *pointer, const char *file, int line) throw()
{
UNREF(file);
UNREF(line);
if (pointer)
MemoryManager::free(pointer, true);
}
// ======================================================================
@@ -0,0 +1,33 @@
// ======================================================================
//
// OsNewDel.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_OsNewDel_H
#define INCLUDED_OsNewDel_H
// ======================================================================
enum MemoryManagerNotALeak
{
MM_notALeak
};
void *operator new(size_t size, MemoryManagerNotALeak) throw(std::bad_alloc);
void *operator new(size_t size) throw(std::bad_alloc);
void *operator new[](size_t size) throw(std::bad_alloc);
void *operator new(size_t size, char const *file, int line) throw(std::bad_alloc);
void *operator new[](size_t size, char const *file, int line) throw(std::bad_alloc);
void operator delete(void *pointer) throw();
void operator delete[](void *pointer) throw();
void operator delete(void *pointer, char const *file, int line) throw();
void operator delete[](void *pointer, char const *file, int line) throw();
// ======================================================================
#endif // INCLUDED_OsNewDel_H
@@ -0,0 +1,8 @@
// ======================================================================
//
// FirstMemoryManager.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
@@ -0,0 +1,19 @@
// ======================================================================
//
// FirstMemoryManager.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_FirstMemoryManager_H
#define INCLUDED_FirstMemoryManager_H
// ======================================================================
#include "sharedFoundationTypes/FoundationTypes.h"
#include "sharedDebug/FirstSharedDebug.h"
#include "sharedFoundation/FirstSharedFoundation.h"
// ======================================================================
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,84 @@
// ======================================================================
//
// MemoryManager.h
// Portions copyright 1998 Bootprint Entertainment
// Portions copyright 2002 Sony Online Entertainment
// All Rights Reserved
//
// ======================================================================
#ifndef INCLUDED_MemoryManager_H
#define INCLUDED_MemoryManager_H
// ======================================================================
#include "sharedDebug/DebugHelp.h"
// ======================================================================
#include <new>
#include "sharedMemoryManager/OsNewDel.h"
// ======================================================================
// Memory manager class.
//
// This class API is multi-thread safe.
//
// This class provides extensive debugging features for applications, including
// overwrite guard bands, initialize pattern fills, free pattern fills, and
// memory tracking.
class MemoryManager
{
public:
MemoryManager();
~MemoryManager();
static void setLimit(int megabytes, bool hardLimit, bool preallocate);
static int getLimit();
static bool isHardLimit();
static void registerDebugFlags();
static void debugReport();
static void debugReportMap();
static bool reportToFile(const char * fileName, bool leak);
static int getCurrentNumberOfAllocations();
static unsigned long getCurrentNumberOfBytesAllocated(const int processId = 0);
static unsigned long getCurrentNumberOfBytesAllocatedNoLeakTest();
static int getMaximumNumberOfAllocations();
static unsigned long getMaximumNumberOfBytesAllocated();
static int getSystemMemoryAllocatedMegabytes();
#ifndef _WIN32
static int getProcessVmSizeKBytes(const int processId = 0);
#endif
static DLLEXPORT void *allocate(size_t size, uint32 owner, bool array, bool leakTest);
static DLLEXPORT void free(void *pointer, bool array);
static DLLEXPORT void own(void *pointer);
static void * reallocate(void *userPointer, size_t newSize);
static void verify(bool guardPatterns, bool freePatterns);
static void setReportAllocations(bool reportAllocations);
static void report();
private:
// disabled
MemoryManager(MemoryManager const &);
MemoryManager &operator =(MemoryManager const &);
};
// ======================================================================
#ifdef _DEBUG
#define MEM_OWN(a) MemoryManager::own(a)
#else
#define MEM_OWN(a) UNREF(a)
#endif
// ======================================================================
#endif
@@ -0,0 +1,56 @@
// ======================================================================
//
// OsMemory.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
#include "sharedMemoryManager/OsMemory.h"
// ======================================================================
void OsMemory::install()
{
}
// ----------------------------------------------------------------------
void OsMemory::remove()
{
}
// ----------------------------------------------------------------------
void *OsMemory::reserve(size_t bytes)
{
return VirtualAlloc(0, bytes, MEM_RESERVE, PAGE_READWRITE);
}
// ----------------------------------------------------------------------
void *OsMemory::commit(void *addr, size_t bytes)
{
return VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE);
}
// ----------------------------------------------------------------------
bool OsMemory::free(void *addr, size_t bytes)
{
UNREF(bytes);
return VirtualFree(addr, 0, MEM_RELEASE) ? true : false;
}
// ----------------------------------------------------------------------
bool OsMemory::protect(void *addr, size_t bytes, bool allowAccess)
{
DWORD old;
BOOL result = VirtualProtect(addr, bytes, allowAccess ? PAGE_READWRITE : PAGE_NOACCESS, &old);
return result ? true : false;
}
// ======================================================================
@@ -0,0 +1,29 @@
// ======================================================================
//
// OsMemory.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_OsMemory_H
#define INCLUDED_OsMemory_H
// ======================================================================
class OsMemory
{
public:
static void install();
static void remove();
static void * reserve(size_t bytes);
static void * commit(void *addr, size_t bytes);
static bool free(void *addr, size_t bytes);
static bool protect(void *addr, size_t bytes, bool allowAccess);
};
// ======================================================================
#endif INCLUDED_OsMemory_H
@@ -0,0 +1,211 @@
// ======================================================================
//
// OsNewDel.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
#include "sharedMemoryManager/OsNewDel.h"
// ======================================================================
// this is here because MSVC won't call MemoryManager::allocate() from asm directly
static void * __cdecl localAllocate(size_t size, uint32 owner, bool array, bool leakTest)
{
return MemoryManager::allocate(size, owner, array, leakTest);
}
// ----------------------------------------------------------------------
// We are using the arguments (except for file and line), but MSVC can't tell that.
#pragma warning(disable: 4100)
// ----------------------------------------------------------------------
__declspec(naked) void *operator new(size_t size, MemoryManagerNotALeak)
{
_asm
{
// setup local call stack
push ebp
mov ebp, esp
// MemoryManager::alloc(size, [return address], false, false)
push 0
push 0
mov eax, dword ptr [ebp+4]
push eax
mov eax, dword ptr [ebp+8]
push eax
call localAllocate
add esp, 12
mov esp, ebp
pop ebp
ret
}
}
// ----------------------------------------------------------------------
__declspec(naked) void *operator new(size_t size)
{
_asm
{
// setup local call stack
push ebp
mov ebp, esp
// MemoryManager::alloc(size, [return address], false, true)
push 1
push 0
mov eax, dword ptr [ebp+4]
push eax
mov eax, dword ptr [ebp+8]
push eax
call localAllocate
add esp, 12
mov esp, ebp
pop ebp
ret
}
}
// ----------------------------------------------------------------------
__declspec(naked) void *operator new[](size_t size)
{
_asm
{
// setup local call stack
push ebp
mov ebp, esp
// MemoryManager::alloc(size, [return address], true, true)
push 1
push 1
mov eax, dword ptr [ebp+4]
push eax
mov eax, dword ptr [ebp+8]
push eax
call localAllocate
add esp, 12
mov esp, ebp
pop ebp
ret
}
}
// ----------------------------------------------------------------------
__declspec(naked) void *operator new(size_t size, const char *file, int line)
{
_asm
{
// setup local call stack
push ebp
mov ebp, esp
// MemoryManager::alloc(size, [return address], false, true)
push 1
push 0
mov eax, dword ptr [ebp+4]
push eax
mov eax, dword ptr [ebp+8]
push eax
call localAllocate
add esp, 12
mov esp, ebp
pop ebp
ret
}
}
// ----------------------------------------------------------------------
__declspec(naked) void *operator new[](size_t size, const char *file, int line)
{
_asm
{
// setup local call stack
push ebp
mov ebp, esp
// MemoryManager::alloc(size, [return address], true, true)
push 1
push 1
mov eax, dword ptr [ebp+4]
push eax
mov eax, dword ptr [ebp+8]
push eax
call localAllocate
add esp, 12
mov esp, ebp
pop ebp
ret
}
}
// ----------------------------------------------------------------------
#pragma warning(default: 4100)
// ----------------------------------------------------------------------
void operator delete(void *pointer)
{
if (pointer)
MemoryManager::free(pointer, false);
}
// ----------------------------------------------------------------------
void operator delete[](void *pointer)
{
if (pointer)
MemoryManager::free(pointer, true);
}
// ----------------------------------------------------------------------
void operator delete(void *pointer, const char *file, int line)
{
UNREF(file);
UNREF(line);
if (pointer)
MemoryManager::free(pointer, false);
}
// ----------------------------------------------------------------------
void operator delete[](void *pointer, const char *file, int line)
{
UNREF(file);
UNREF(line);
if (pointer)
MemoryManager::free(pointer, true);
}
// ======================================================================
// WARNING!!!!!!!
//
// The init_seg pragma command is used to create certain static objects first, before other static objects are created.
// However, multiple static variables that use the same init_seg category(i.e. compiler) are not guaranteed to destroy in any
// particular order. It is completely random based on how all the linking of static objects occurs. Since this command is being
// used on our memory manager(to overwrite new/delete) - NO OTHER STATIC SHOULD EVER USE INIT_SEG(COMPILER)!!!! This static object
// *MUST* be the final static object that is destroyed.
//
#pragma warning(disable: 4074)
#pragma init_seg(compiler) // ^-Read warning above.-^
static MemoryManager memoryManager;
// ======================================================================
@@ -0,0 +1,52 @@
// ======================================================================
//
// OsNewDel.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_OsNewDel_H
#define INCLUDED_OsNewDel_H
// ======================================================================
enum MemoryManagerNotALeak
{
MM_notALeak
};
void * __cdecl operator new(size_t size, MemoryManagerNotALeak);
void * __cdecl operator new(size_t size);
void * __cdecl operator new[](size_t size);
void * __cdecl operator new(size_t size, char const *file, int line);
void * __cdecl operator new[](size_t size, char const *file, int line);
void * __cdecl operator new(size_t size, void *placement);
void operator delete(void *pointer);
void operator delete[](void *pointer);
void operator delete(void *pointer, char const *file, int line);
void operator delete[](void *pointer, char const *file, int line);
void operator delete(void *pointer, void *placement);
#ifndef __PLACEMENT_NEW_INLINE
#define __PLACEMENT_NEW_INLINE
inline void *operator new(size_t size, void *placement)
{
static_cast<void>(size);
return placement;
}
inline void operator delete(void *pointer, void *placement)
{
static_cast<void>(pointer);
static_cast<void>(placement);
}
#endif // __PLACEMENT_NEW_INLINE
// ======================================================================
#endif INCLUDED_OsNewDel_H