tmp
This commit is contained in:
parent
b8bcf58a29
commit
afab59eb21
34 changed files with 288 additions and 264 deletions
|
|
@ -5,11 +5,11 @@ file(GLOB SOURCES "./private/*.cpp")
|
|||
file(GLOB HEADERS "./public/*.hpp")
|
||||
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Utils)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Callstack)
|
||||
|
||||
### -------------------------- Tests -------------------------- ###
|
||||
enable_testing()
|
||||
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
||||
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
|
||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
||||
add_executable(Tests${PROJECT_NAME} ${TEST_SOURCES})
|
||||
target_link_libraries(Tests${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
|
||||
add_test(NAME Tests${PROJECT_NAME} COMMAND Tests${PROJECT_NAME})
|
||||
|
|
@ -13,9 +13,11 @@ static bool init(const tp::ModuleManifest* self) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void deinit(const tp::ModuleManifest* self) { tp::HeapAllocGlobal::checkLeaks(); }
|
||||
static void deinit(const tp::ModuleManifest* self) {
|
||||
tp::HeapAllocGlobal::checkLeaks();
|
||||
}
|
||||
|
||||
static tp::ModuleManifest* sModuleDependencies[] = { &tp::gModuleUtils, nullptr };
|
||||
static tp::ModuleManifest* sModuleDependencies[] = { nullptr };
|
||||
tp::ModuleManifest tp::gModuleAllocators = ModuleManifest("Allocators", init, deinit, sModuleDependencies);
|
||||
|
||||
void* operator new(size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "HeapAllocatorGlobal.hpp"
|
||||
#include "PrivateConfig.hpp"
|
||||
|
||||
#include "Debugging.hpp"
|
||||
#include "Callstack.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
|
|
@ -33,6 +33,10 @@ tp::ualni tp::HeapAllocGlobal::mNumAllocations = 0;
|
|||
std::mutex tp::HeapAllocGlobal::mMutex;
|
||||
bool tp::HeapAllocGlobal::mIgnore = true;
|
||||
|
||||
#ifdef MEM_STACK_TRACE
|
||||
tp::CallStackCapture tp::HeapAllocGlobal::mCallstack;
|
||||
#endif
|
||||
|
||||
// ----------------------- Debug Implementation ---------------------------- //
|
||||
// |----------------|
|
||||
// | MemHead |
|
||||
|
|
@ -105,8 +109,7 @@ ALLOCATE:
|
|||
// 3) Trace the stack
|
||||
#ifdef MEM_STACK_TRACE
|
||||
// check if somewhat decides to call new within static variable initialization
|
||||
if (gCSCapture) head->mCallStack = gCSCapture->getSnapshot();
|
||||
else head->mCallStack = nullptr;
|
||||
head->mCallStack = mCallstack.getSnapshot();
|
||||
#endif
|
||||
|
||||
mMutex.unlock();
|
||||
|
|
@ -146,12 +149,16 @@ void HeapAllocGlobal::deallocate(void* aPtr) {
|
|||
if (!head->mIgnored) {
|
||||
// 3) Check the wrap
|
||||
if (memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL)) {
|
||||
CallStackCapture::printSnapshot(head->mCallStack);
|
||||
#ifdef MEM_STACK_TRACE
|
||||
mCallstack.printSnapshot(head->mCallStack);
|
||||
#endif
|
||||
ASSERT(!"Allocated Block Wrap Corrupted!")
|
||||
}
|
||||
|
||||
if (memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL)) {
|
||||
CallStackCapture::printSnapshot(head->mCallStack);
|
||||
#ifdef MEM_STACK_TRACE
|
||||
mCallstack.printSnapshot(head->mCallStack);
|
||||
#endif
|
||||
ASSERT(!"Allocated Block Wrap Corrupted!")
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +183,7 @@ bool HeapAllocGlobal::checkLeaks() {
|
|||
|
||||
#ifdef MEM_STACK_TRACE
|
||||
for (auto iter = mEntry; iter; iter = iter->mPrev) {
|
||||
if (!iter->mIgnored) CallStackCapture::printSnapshot(iter->mCallStack);
|
||||
if (!iter->mIgnored) mCallstack.printSnapshot(iter->mCallStack);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "Module.hpp"
|
||||
#include "Callstack.hpp"
|
||||
#include <mutex>
|
||||
|
||||
namespace tp {
|
||||
|
|
@ -12,6 +12,9 @@ namespace tp {
|
|||
static struct MemHead* mEntry;
|
||||
static std::mutex mMutex;
|
||||
static bool mIgnore;
|
||||
#ifdef MEM_STACK_TRACE // Save stack on allocation call
|
||||
static CallStackCapture mCallstack;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -6,5 +6,4 @@
|
|||
#define MEM_CLEAR_ON_DEALLOC // Clear data on free
|
||||
#define MEM_CLEAR_ON_DEALLOC_VAL 0xAA // Clear data on free
|
||||
#define MEM_CLEAR_ON_ALLOC_VAL 0xCC // Clear data on free
|
||||
#define MEM_STACK_TRACE // Save stack on allocation call
|
||||
#define MEM_STACK_TRACE_MAX_DEPTH 32 // Call stack max depth
|
||||
|
|
@ -234,7 +234,7 @@ SUITE(Allocators) {
|
|||
|
||||
int main() {
|
||||
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, &tp::gModuleUtils, nullptr };
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, nullptr };
|
||||
tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
|
||||
|
||||
if (!testModule.initialize()) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ project(ModulesRoot)
|
|||
include(CMakeOptions.txt)
|
||||
|
||||
add_subdirectory(Modules)
|
||||
add_subdirectory(Utils)
|
||||
add_subdirectory(Callstack)
|
||||
add_subdirectory(Containers)
|
||||
add_subdirectory(Math)
|
||||
add_subdirectory(Allocators)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
option(MODULES_MEMORY_DEBUG "Debug memory" ON)
|
||||
option(MODULES_MEMORY_DEBUG_STACK_TRACE "Record stack info on memory debug" ON)
|
||||
|
||||
set(WINDOWS_LIBRARIES "../../ModulesWindowsLibraries" CACHE STRING "Svn repository with windows libraries https://svn.riouxsvn.com/moduleswindowsl")
|
||||
|
||||
|
|
@ -6,4 +7,8 @@ if (MODULES_MEMORY_DEBUG)
|
|||
add_compile_definitions(MEM_DEBUG)
|
||||
endif ()
|
||||
|
||||
if (MODULES_MEMORY_DEBUG_STACK_TRACE)
|
||||
add_compile_definitions(MEM_STACK_TRACE)
|
||||
endif ()
|
||||
|
||||
enable_testing()
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
project(Utils)
|
||||
project(Callstack)
|
||||
|
||||
### ---------------------- Static Library --------------------- ###
|
||||
file(GLOB SOURCES "./private/*.cpp")
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||
|
||||
### ---------------------- Dependencies --------------------- ###
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Containers)
|
||||
|
||||
### -------------------------- Tests -------------------------- ###
|
||||
enable_testing()
|
||||
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
||||
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
|
||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
||||
add_executable(Tests${PROJECT_NAME} ${TEST_SOURCES})
|
||||
target_link_libraries(Tests${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
|
||||
add_test(NAME Tests${PROJECT_NAME} COMMAND Tests${PROJECT_NAME})
|
||||
|
|
@ -1,19 +1,15 @@
|
|||
|
||||
#include "Debugging.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "Callstack.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace tp;
|
||||
|
||||
CallStackCapture* tp::gCSCapture = nullptr;
|
||||
|
||||
void initializeCallStackCapture() { gCSCapture = new (malloc(sizeof(CallStackCapture))) CallStackCapture(); }
|
||||
|
||||
void deinitializeCallStackCapture() {
|
||||
gCSCapture->~CallStackCapture();
|
||||
free(gCSCapture);
|
||||
gCSCapture = nullptr;
|
||||
// frame to reference on no sapce left
|
||||
static void errorNoSpaceLeft() {
|
||||
// to disable optimization of function
|
||||
static int dummy;
|
||||
dummy = 10;
|
||||
}
|
||||
|
||||
ualni CallStackCapture::CallStack::getDepth() const {
|
||||
|
|
@ -24,14 +20,7 @@ ualni CallStackCapture::CallStack::getDepth() const {
|
|||
}
|
||||
len++;
|
||||
}
|
||||
ualni stripedLen = 0;
|
||||
for (auto i = FRAMES_TO_SKIP_START; i < len - FRAMES_TO_SKIP_END; i++) {
|
||||
if (!frames[i]) {
|
||||
break;
|
||||
}
|
||||
stripedLen++;
|
||||
}
|
||||
return stripedLen;
|
||||
return len++;
|
||||
}
|
||||
|
||||
ualni CallStackCapture::hashCallStack(CallStackKey key) {
|
||||
|
|
@ -44,7 +33,7 @@ ualni CallStackCapture::hashCallStack(CallStackKey key) {
|
|||
}
|
||||
|
||||
bool CallStackCapture::CallStackKey::operator==(const CallStackCapture::CallStackKey& in) const {
|
||||
for (auto i : Range(MAX_CALL_DEPTH_CAPTURE)) {
|
||||
for (ualni i = 0; i < MAX_CALL_DEPTH_CAPTURE; i++) {
|
||||
if (cs->frames[i] != in.cs->frames[i]) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -60,26 +49,26 @@ CallStackCapture::CallStackCapture() {
|
|||
static_assert(MAX_CALL_DEPTH_CAPTURE >= 1);
|
||||
static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB > 0);
|
||||
static_assert(MAX_DEBUG_INFO_LEN > sizeof("unresolved"));
|
||||
static_assert(FRAMES_TO_SKIP_END >= 0 && FRAMES_TO_SKIP_START >= 0);
|
||||
static_assert(MAX_CALL_DEPTH_CAPTURE > FRAMES_TO_SKIP_START + FRAMES_TO_SKIP_END);
|
||||
static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024 > sizeof(CallStack));
|
||||
|
||||
MODULE_SANITY_CHECK(gModuleUtils)
|
||||
mBuffLoad = 0;
|
||||
mBuffLen = (MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024) / sizeof(CallStack);
|
||||
mBuffLen = STACKS_LENGTH;
|
||||
mBuff = (CallStack*) malloc(mBuffLen * sizeof(CallStack));
|
||||
|
||||
mErrorSnapshot.frames[0] = (alni) & errorNoSpaceLeft;
|
||||
|
||||
|
||||
platformInit();
|
||||
}
|
||||
|
||||
const CallStackCapture::CallStack* CallStackCapture::getSnapshot() {
|
||||
MODULE_SANITY_CHECK(gModuleUtils)
|
||||
|
||||
if (mBuffLoad > mBuffLen) {
|
||||
static CallStack cs;
|
||||
cs.frames[0] = 0;
|
||||
return &cs;
|
||||
return &mErrorSnapshot;
|
||||
}
|
||||
|
||||
CallStack* cs = &mBuff[mBuffLoad];
|
||||
|
||||
platformWriteStackTrace(cs);
|
||||
|
||||
auto idx = mSnapshots.presents({ cs });
|
||||
|
|
@ -213,7 +202,7 @@ void CallStackCapture::printSnapshot(const CallStack* snapshot) {
|
|||
printf("CallStack: \n");
|
||||
if (snapshot) {
|
||||
for (auto frame : *snapshot) {
|
||||
auto symbols = gCSCapture->getSymbols(frame.getFrame());
|
||||
auto symbols = getSymbols(frame.getFrame());
|
||||
printf(" %s ----- %s:%llu\n", symbols->getFunc(), symbols->getFile(), symbols->getLine());
|
||||
}
|
||||
}
|
||||
|
|
@ -227,15 +216,112 @@ void CallStackCapture::logAll() {
|
|||
}
|
||||
|
||||
#else
|
||||
void CallStackCapture::platformWriteStackTrace(CallStack* stack) { stack->frames[0] = 0; }
|
||||
void CallStackCapture::platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out) {
|
||||
std::strcpy(out->file, "unresolved");
|
||||
std::strcpy(out->function, "unresolved");
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
||||
void CallStackCapture::platformInit() {
|
||||
HANDLE process = GetCurrentProcess();
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
}
|
||||
|
||||
void CallStackCapture::platformDeinit() {
|
||||
HANDLE process = GetCurrentProcess();
|
||||
SymCleanup(process);
|
||||
}
|
||||
|
||||
void CallStackCapture::platformWriteStackTrace(CallStack* stack) {
|
||||
DWORD hash;
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(CONTEXT));
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
STACKFRAME64 stackFrame;
|
||||
memset(&stackFrame, 0, sizeof(STACKFRAME64));
|
||||
#ifdef _M_IX86
|
||||
hash = IMAGE_FILE_MACHINE_I386;
|
||||
stackFrame.AddrPC.Offset = context.Eip;
|
||||
stackFrame.AddrPC.Mode = AddrModeFlat;
|
||||
stackFrame.AddrFrame.Offset = context.Ebp;
|
||||
stackFrame.AddrFrame.Mode = AddrModeFlat;
|
||||
stackFrame.AddrStack.Offset = context.Esp;
|
||||
stackFrame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_X64
|
||||
hash = IMAGE_FILE_MACHINE_AMD64;
|
||||
stackFrame.AddrPC.Offset = context.Rip;
|
||||
stackFrame.AddrPC.Mode = AddrModeFlat;
|
||||
stackFrame.AddrFrame.Offset = context.Rbp;
|
||||
stackFrame.AddrFrame.Mode = AddrModeFlat;
|
||||
stackFrame.AddrStack.Offset = context.Rsp;
|
||||
stackFrame.AddrStack.Mode = AddrModeFlat;
|
||||
#endif
|
||||
|
||||
for (int frameIndex = 0; frameIndex < MAX_CALL_DEPTH_CAPTURE; ++frameIndex) {
|
||||
if (!StackWalk64(
|
||||
hash,
|
||||
GetCurrentProcess(),
|
||||
GetCurrentThread(),
|
||||
&stackFrame,
|
||||
&context,
|
||||
NULL,
|
||||
SymFunctionTableAccess64,
|
||||
SymGetModuleBase64,
|
||||
NULL
|
||||
)) {
|
||||
|
||||
stack->frames[frameIndex] = 0;
|
||||
break;
|
||||
}
|
||||
stack->frames[frameIndex] = (alni) (void*) stackFrame.AddrPC.Offset;
|
||||
}
|
||||
stack->frames[MAX_CALL_DEPTH_CAPTURE - 1] = 0;
|
||||
}
|
||||
|
||||
void CallStackCapture::platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out) {
|
||||
HANDLE process = GetCurrentProcess();
|
||||
|
||||
IMAGEHLP_LINE64 lineInfo;
|
||||
DWORD displacement;
|
||||
lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
if (SymGetLineFromAddr64(process, (DWORD64) frame, &displacement, &lineInfo)) {
|
||||
strcpy(out->file, lineInfo.FileName);
|
||||
out->line = lineInfo.LineNumber;
|
||||
} else {
|
||||
strcpy(out->file, "unresolved");
|
||||
out->line = 0;
|
||||
}
|
||||
|
||||
DWORD64 displacementSym = 0;
|
||||
char symbolBuffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH] = { 0 };
|
||||
IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*) symbolBuffer;
|
||||
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
symbol->MaxNameLength = MAX_PATH;
|
||||
|
||||
if (SymGetSymFromAddr64(process, (DWORD64) frame, &displacementSym, symbol)) {
|
||||
strcpy(out->function, symbol->Name);
|
||||
} else {
|
||||
strcpy(out->function, "unresolved");
|
||||
}
|
||||
}
|
||||
|
||||
void CallStackCapture::printSnapshot(const CallStack* snapshot) {
|
||||
printf("CallStack: \n");
|
||||
printf("Call stack debugging is not supported on this platform");
|
||||
if (snapshot) {
|
||||
for (int i = 0; i < snapshot->getDepth(); ++i) {
|
||||
DebugSymbols symbols;
|
||||
platformWriteDebugSymbols(snapshot->frames[i], &symbols);
|
||||
printf(" %s ----- %s:%lu\n", symbols.function, symbols.file, symbols.line);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
void CallStackCapture::logAll() { printf("Call stack debugging is not supported on this platform"); }
|
||||
|
||||
void CallStackCapture::logAll() {
|
||||
for (auto cs : *this) {
|
||||
printSnapshot(cs.getCallStack());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -3,18 +3,18 @@
|
|||
#include "Environment.hpp"
|
||||
#include "Map.hpp"
|
||||
|
||||
#define MAX_CALL_DEPTH_CAPTURE 128
|
||||
#define MAX_CALL_CAPTURES_MEM_SIZE_MB 16
|
||||
#define MAX_DEBUG_INFO_LEN 63
|
||||
#define FRAMES_TO_SKIP_START 2
|
||||
#define FRAMES_TO_SKIP_END 3
|
||||
|
||||
namespace tp {
|
||||
|
||||
class CallStackCapture {
|
||||
public:
|
||||
typedef tp::alni FramePointer;
|
||||
|
||||
enum {
|
||||
MAX_CALL_DEPTH_CAPTURE = 16,
|
||||
MAX_CALL_CAPTURES_MEM_SIZE_MB = 32,
|
||||
MAX_DEBUG_INFO_LEN = 64,
|
||||
};
|
||||
|
||||
class CallStack {
|
||||
friend CallStackCapture;
|
||||
FramePointer frames[MAX_CALL_DEPTH_CAPTURE];
|
||||
|
|
@ -26,18 +26,19 @@ namespace tp {
|
|||
const FramePointer* mFrame;
|
||||
|
||||
public:
|
||||
explicit Iterator(const FramePointer* frame) :
|
||||
mFrame(frame){};
|
||||
explicit Iterator(const FramePointer* frame) : mFrame(frame){};
|
||||
FramePointer getFrame() { return *mFrame; }
|
||||
bool operator==(const Iterator& in) const { return in.mFrame == mFrame; }
|
||||
void operator++() { mFrame++; }
|
||||
const Iterator& operator*() const { return *this; }
|
||||
};
|
||||
|
||||
[[nodiscard]] Iterator begin() const { return Iterator(frames + FRAMES_TO_SKIP_START); }
|
||||
[[nodiscard]] Iterator end() const { return Iterator(frames + FRAMES_TO_SKIP_START + getDepth()); }
|
||||
[[nodiscard]] Iterator begin() const { return Iterator(frames); }
|
||||
[[nodiscard]] Iterator end() const { return Iterator(frames + getDepth()); }
|
||||
};
|
||||
|
||||
enum { STACKS_LENGTH = (MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024) / sizeof(CallStack) };
|
||||
|
||||
class DebugSymbols {
|
||||
friend CallStackCapture;
|
||||
char function[MAX_DEBUG_INFO_LEN + 1] = { 0 };
|
||||
|
|
@ -57,44 +58,15 @@ namespace tp {
|
|||
[[nodiscard]] const CallStack* getSnapshot();
|
||||
const DebugSymbols* getSymbols(FramePointer fp);
|
||||
|
||||
static void printSnapshot(const CallStack* snapshot);
|
||||
void printSnapshot(const CallStack* snapshot);
|
||||
void logAll();
|
||||
|
||||
public:
|
||||
template <class Saver>
|
||||
void write(Saver& file) {
|
||||
file.write(mBuffLoad);
|
||||
for (auto cs : *this) {
|
||||
file.write(cs.getCallStack()->getDepth());
|
||||
for (auto frame : *cs.getCallStack()) {
|
||||
file.write((ualni) frame.getFrame());
|
||||
}
|
||||
}
|
||||
file.write(mSymbols);
|
||||
}
|
||||
|
||||
// independent of the configuration
|
||||
template <class Loader>
|
||||
void read(Loader& file) {
|
||||
clear();
|
||||
ualni loadLen;
|
||||
file.read(loadLen);
|
||||
for (auto cs = loadLen; cs; cs--) {
|
||||
ualni callStackLen;
|
||||
file.read(callStackLen);
|
||||
for (auto fp = callStackLen; fp; fp--) {
|
||||
// --
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
class Iterator {
|
||||
const CallStack* mSnapshot;
|
||||
|
||||
public:
|
||||
explicit Iterator(const CallStack* start) :
|
||||
mSnapshot(start){};
|
||||
explicit Iterator(const CallStack* start) : mSnapshot(start) {};
|
||||
const CallStack* getCallStack() { return mSnapshot; }
|
||||
bool operator==(const Iterator& in) const { return in.mSnapshot == mSnapshot; }
|
||||
void operator++() { mSnapshot++; }
|
||||
|
|
@ -113,16 +85,19 @@ namespace tp {
|
|||
static void platformWriteStackTrace(CallStack* stack);
|
||||
static void platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out);
|
||||
[[nodiscard]] static ualni hashCallStack(CallStackKey key);
|
||||
void platformInit();
|
||||
void platformDeinit();
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
CallStack mErrorSnapshot;
|
||||
|
||||
ualni mBuffLen;
|
||||
ualni mBuffLoad;
|
||||
CallStack* mBuff;
|
||||
|
||||
Map<CallStackKey, CallStack*, DefaultAllocator, hashCallStack> mSnapshots;
|
||||
Map<FramePointer, DebugSymbols> mSymbols;
|
||||
};
|
||||
|
||||
extern CallStackCapture* gCSCapture;
|
||||
}
|
||||
44
Callstack/tests/Test.cpp
Normal file
44
Callstack/tests/Test.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
#include "UnitTest++/UnitTest++.h"
|
||||
|
||||
#include "Callstack.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
using namespace tp;
|
||||
|
||||
void common(CallStackCapture& cs) { auto tmp = cs.getSnapshot(); }
|
||||
|
||||
void first(CallStackCapture& cs) {
|
||||
common(cs);
|
||||
common(cs);
|
||||
common(cs);
|
||||
}
|
||||
|
||||
void second(CallStackCapture& cs) {
|
||||
common(cs);
|
||||
common(cs);
|
||||
common(cs);
|
||||
common(cs);
|
||||
}
|
||||
|
||||
void third(CallStackCapture& cs) {
|
||||
common(cs);
|
||||
common(cs);
|
||||
}
|
||||
|
||||
void root(CallStackCapture& cs) {
|
||||
first(cs);
|
||||
second(cs);
|
||||
third(cs);
|
||||
}
|
||||
|
||||
SUITE(Utils) {
|
||||
TEST(CallStackCapture) {
|
||||
CallStackCapture callstack;
|
||||
root(callstack);
|
||||
callstack.logAll();
|
||||
}
|
||||
}
|
||||
|
||||
int main() { return UnitTest::RunAllTests(); }
|
||||
|
|
@ -8,8 +8,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
|||
target_link_libraries(${PROJECT_NAME} PUBLIC Modules)
|
||||
|
||||
### -------------------------- Tests -------------------------- ###
|
||||
enable_testing()
|
||||
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
||||
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Allocators UnitTest++)
|
||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
||||
add_executable(Tests${PROJECT_NAME} ${TEST_SOURCES})
|
||||
target_link_libraries(Tests${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
|
||||
add_test(NAME Tests${PROJECT_NAME} COMMAND Tests${PROJECT_NAME})
|
||||
|
|
@ -5,9 +5,6 @@
|
|||
|
||||
namespace tp {
|
||||
|
||||
static ModuleManifest* sModuleDependencies[] = { &gModuleBase, nullptr };
|
||||
ModuleManifest gModuleContainers = ModuleManifest("Containers", nullptr, nullptr, sModuleDependencies);
|
||||
|
||||
void* DefaultAllocator::allocate(ualni size) { return malloc(size); }
|
||||
|
||||
void DefaultAllocator::deallocate(void* p) { free(p); }
|
||||
|
|
|
|||
|
|
@ -13,7 +13,12 @@ namespace tp {
|
|||
class Buffer2D {
|
||||
public:
|
||||
typedef ualni Index;
|
||||
typedef Pair<Index, Index> Index2D;
|
||||
|
||||
struct Index2D {
|
||||
Index x = 0;
|
||||
Index y = 0;
|
||||
};
|
||||
|
||||
typedef SelectValueOrReference<tType> tTypeArg;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include "Module.hpp"
|
||||
|
||||
namespace tp {
|
||||
extern ModuleManifest gModuleContainers;
|
||||
|
||||
class DefaultAllocator {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -164,7 +164,6 @@ namespace tp {
|
|||
|
||||
public:
|
||||
Map() {
|
||||
MODULE_SANITY_CHECK(gModuleContainers)
|
||||
mNSlots = next2pow(uhalni(tTableInitialSize - 1));
|
||||
mTable = newTable(mNSlots);
|
||||
}
|
||||
|
|
@ -243,7 +242,13 @@ namespace tp {
|
|||
if (this == &in) {
|
||||
return *this;
|
||||
}
|
||||
removeAll();
|
||||
|
||||
for (ualni i = 0; i < mNSlots; i++) {
|
||||
if (mTable[i] && !isDeletedNode(mTable[i])) {
|
||||
deleteNode(mTable[i]);
|
||||
}
|
||||
}
|
||||
mNEntries = 0;
|
||||
mNSlots = in.mNSlots;
|
||||
deleteTable(mTable);
|
||||
mTable = newTable(mNSlots);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace tp {
|
|||
};
|
||||
|
||||
public:
|
||||
AvlTree() { MODULE_SANITY_CHECK(gModuleContainers) }
|
||||
AvlTree() {}
|
||||
~AvlTree() { removeAll(); }
|
||||
|
||||
[[nodiscard]] ualni size() const { return mSize; }
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
#include "Buffer2D.hpp"
|
||||
#include "Tests.hpp"
|
||||
|
||||
#include "HeapAllocator.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
const ualni size = 1000;
|
||||
|
||||
SUITE(Buffer2D) {
|
||||
TEST(Simple) {
|
||||
Buffer2D<int, tp::HeapAlloc> buff;
|
||||
Buffer2D<int, TestAllocator> buff;
|
||||
buff.reserve({ 4, 4 });
|
||||
buff.set({ 2, 2 }, 5);
|
||||
CHECK(buff.get({ 2, 2 }) == 5);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const ualni size = 1000;
|
|||
|
||||
SUITE(Buffer) {
|
||||
TEST(Simple1) {
|
||||
Buffer<TestClass, tp::HeapAlloc> buff;
|
||||
Buffer<TestClass, TestAllocator> buff;
|
||||
CHECK(buff.size() == 0);
|
||||
for (auto i : Range(size * 10)) {
|
||||
buff.append(TestClass(i));
|
||||
|
|
@ -19,7 +19,7 @@ SUITE(Buffer) {
|
|||
}
|
||||
|
||||
TEST(Simple2) {
|
||||
Buffer<TestClass, tp::HeapAlloc> buff(size);
|
||||
Buffer<TestClass, TestAllocator> buff(size);
|
||||
CHECK(buff.size() == size);
|
||||
for (auto i : Range(size * 10))
|
||||
buff.append(TestClass(i));
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ SUITE(IntervalTree) {
|
|||
ualni numFound = 0;
|
||||
ualni lastDataFound = 0;
|
||||
|
||||
[[nodiscard]] bool isSingleData(ualni aData) const { return numFound == 1 & lastDataFound == aData; }
|
||||
[[nodiscard]] bool isSingleData(ualni aData) const { return numFound == 1 && lastDataFound == aData; }
|
||||
[[nodiscard]] bool notFound() const { return numFound == 0; }
|
||||
[[nodiscard]] bool found(ualni num) const { return numFound == num; }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using namespace tp;
|
|||
SUITE(DoubleLinkedList) {
|
||||
|
||||
TEST(SimpleReference) {
|
||||
tp::List<TestClass, tp::HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
|
||||
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
|
||||
|
||||
list.pushBack(TestClass(5));
|
||||
list.pushFront(TestClass(0));
|
||||
|
|
@ -24,7 +24,9 @@ SUITE(DoubleLinkedList) {
|
|||
}
|
||||
|
||||
TEST(SimplePointer) {
|
||||
tp::List<TestClass*, tp::HeapAlloc> list = { new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4) };
|
||||
tp::List<TestClass*, TestAllocator> list = {
|
||||
new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4)
|
||||
};
|
||||
|
||||
list.pushBack(new TestClass(5));
|
||||
list.pushFront(new TestClass(0));
|
||||
|
|
@ -45,8 +47,8 @@ SUITE(DoubleLinkedList) {
|
|||
}
|
||||
|
||||
TEST(Copy) {
|
||||
tp::List<TestClass, tp::HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
|
||||
tp::List<TestClass, tp::HeapAlloc> list2 = list;
|
||||
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
|
||||
tp::List<TestClass, TestAllocator> list2 = list;
|
||||
|
||||
CHECK(list == list2);
|
||||
|
||||
|
|
@ -55,7 +57,7 @@ SUITE(DoubleLinkedList) {
|
|||
}
|
||||
|
||||
TEST(Serialization) {
|
||||
tp::List<TestClass, tp::HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
|
||||
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
|
||||
|
||||
ArchiverExample<1024, false> write;
|
||||
ArchiverExample<1024, true> read;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using namespace tp;
|
|||
|
||||
SUITE(HashTable) {
|
||||
TEST(SimpleReference) {
|
||||
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
|
||||
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
||||
|
||||
for (auto i : Range(1000, 100000)) {
|
||||
map.put(i, TestClass(i));
|
||||
|
|
@ -40,7 +40,7 @@ SUITE(HashTable) {
|
|||
}
|
||||
|
||||
TEST(SimplePointer) {
|
||||
tp::Map<tp::ualni, TestClass*, tp::HeapAlloc> map;
|
||||
tp::Map<tp::ualni, TestClass*, TestAllocator> map;
|
||||
|
||||
for (auto i : Range(1000)) {
|
||||
map.put(i, new TestClass(i));
|
||||
|
|
@ -78,13 +78,13 @@ SUITE(HashTable) {
|
|||
}
|
||||
|
||||
TEST(Copy) {
|
||||
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
|
||||
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
||||
|
||||
for (auto i : Range(10)) {
|
||||
map.put(i, TestClass(i));
|
||||
}
|
||||
|
||||
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map2 = map;
|
||||
tp::Map<tp::ualni, TestClass, TestAllocator> map2 = map;
|
||||
|
||||
CHECK(map == map2);
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ SUITE(HashTable) {
|
|||
}
|
||||
|
||||
TEST(SaveLoad) {
|
||||
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
|
||||
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
||||
|
||||
for (auto i : Range(10)) {
|
||||
map.put(i, TestClass(i));
|
||||
|
|
|
|||
|
|
@ -2,18 +2,23 @@
|
|||
#include "Tests.hpp"
|
||||
#include "UnitTest++/UnitTest++.h"
|
||||
|
||||
void* TestAllocator::allocate(tp::ualni size) {
|
||||
count++;
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void TestAllocator::deallocate(void* p) {
|
||||
if (p) {
|
||||
free(p);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TestAllocator::~TestAllocator() {
|
||||
ASSERT(!count);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, &tp::gModuleAllocators, nullptr };
|
||||
tp::ModuleManifest testModule("ContainersTest", nullptr, nullptr, deps);
|
||||
|
||||
if (!testModule.initialize()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool res = UnitTest::RunAllTests();
|
||||
|
||||
testModule.deinitialize();
|
||||
|
||||
return res;
|
||||
return UnitTest::RunAllTests();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,20 @@
|
|||
|
||||
#include "UnitTest++/UnitTest++.h"
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
// counting number of allocations and deallocations
|
||||
struct TestAllocator {
|
||||
TestAllocator() { count = 0; };
|
||||
|
||||
tp::ualni count = 0;
|
||||
|
||||
void* allocate(tp::ualni size);
|
||||
void deallocate(void*);
|
||||
|
||||
~TestAllocator();
|
||||
};
|
||||
|
||||
class TestClass {
|
||||
tp::ualni val2 = 0;
|
||||
tp::ualni val1;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using namespace tp;
|
|||
|
||||
SUITE(AvlTree) {
|
||||
TEST(Simple) {
|
||||
AvlTree<AvlNumericKey<alni>, TestClass, tp::HeapAlloc> tree;
|
||||
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
|
||||
|
||||
CHECK(tree.size() == 0);
|
||||
CHECK(tree.head() == nullptr);
|
||||
|
|
@ -22,7 +22,7 @@ SUITE(AvlTree) {
|
|||
}
|
||||
|
||||
TEST(Persistance) {
|
||||
AvlTree<AvlNumericKey<alni>, TestClass, tp::HeapAlloc> tree;
|
||||
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
|
||||
|
||||
const auto size = 1000;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,6 @@
|
|||
|
||||
using namespace tp;
|
||||
|
||||
static bool init(const ModuleManifest* self) {
|
||||
gEnvironment.log();
|
||||
return true;
|
||||
}
|
||||
|
||||
static ModuleManifest* deps[] = { nullptr };
|
||||
ModuleManifest tp::gModuleBase = ModuleManifest("Common", init, nullptr, deps);
|
||||
|
||||
ModuleManifest::ModuleManifest(const char* aModuleName, ModuleInit aInit, ModuleDeinit aDeinit, ModuleManifest** aDependencies) {
|
||||
mInit = aInit;
|
||||
mDeinit = aDeinit;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ namespace tp {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO remove
|
||||
float Timer::easeIn(time_ms pDuration) {
|
||||
if (!pDuration) {
|
||||
pDuration = mDuration;
|
||||
|
|
@ -55,6 +56,7 @@ namespace tp {
|
|||
return clamp((1.1f * x) / (x + 0.1f), 0.f, 1.f);
|
||||
}
|
||||
|
||||
// TODO remove
|
||||
float Timer::easeOut(time_ms pDuration) {
|
||||
if (!pDuration) {
|
||||
pDuration = mDuration;
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include "ContainersCommon.hpp"
|
||||
|
||||
#include <ctime>
|
||||
#include <random>
|
||||
|
||||
|
|
@ -21,12 +19,7 @@ static void deinitialize(const tp::ModuleManifest*) {
|
|||
|
||||
namespace tp {
|
||||
|
||||
static ModuleManifest* sModuleUtilsDeps[] = { &gModuleContainers, nullptr };
|
||||
ModuleManifest gModuleUtils = ModuleManifest("Utils", initialize, deinitialize, sModuleUtilsDeps);
|
||||
|
||||
void memSetVal(void* p, uhalni byteSize, uint1 val) {
|
||||
// MODULE_SANITY_CHECK(gModuleBase)
|
||||
|
||||
alni alignedVal = val;
|
||||
alignedVal = (alignedVal << 8) | alignedVal;
|
||||
alignedVal = (alignedVal << 16) | alignedVal;
|
||||
|
|
@ -44,8 +37,6 @@ namespace tp {
|
|||
}
|
||||
|
||||
void memCopy(void* left, const void* right, uhalni len) {
|
||||
MODULE_SANITY_CHECK(gModuleBase)
|
||||
|
||||
ualni alignedLen = len / sizeof(alni);
|
||||
for (ualni idx = 0; idx < alignedLen; idx++) {
|
||||
((alni*) left)[idx] = ((alni*) right)[idx];
|
||||
|
|
@ -58,7 +49,6 @@ namespace tp {
|
|||
}
|
||||
|
||||
int1 memCompare(const void* left, const void* right, uhalni len) {
|
||||
MODULE_SANITY_CHECK(gModuleBase)
|
||||
if (!len) return 0;
|
||||
|
||||
ualni alignedLength = len / sizeof(alni);
|
||||
|
|
@ -88,7 +78,6 @@ namespace tp {
|
|||
bool memEqual(const void* left, const void* right, uhalni len) { return memCompare(left, right, len) == 0; }
|
||||
|
||||
int1 memCompareVal(const void* left, uhalni len, uint1 val) {
|
||||
MODULE_SANITY_CHECK(gModuleBase)
|
||||
if (!len) return 0;
|
||||
|
||||
alni valAligned = val;
|
||||
|
|
@ -30,6 +30,4 @@ namespace tp {
|
|||
uhalni mInitCount = 0;
|
||||
void* mCustomData = nullptr;
|
||||
};
|
||||
|
||||
extern ModuleManifest gModuleBase;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@
|
|||
#define MEMBER_OFFSET(s, m) (alni(&(((s*) 0)->m)))
|
||||
|
||||
namespace tp {
|
||||
|
||||
extern ModuleManifest gModuleUtils;
|
||||
|
||||
void memSetVal(void* p, uhalni byteSize, uint1 val);
|
||||
void memCopy(void* left, const void* right, uhalni len);
|
||||
int1 memCompare(const void* left, const void* right, uhalni len);
|
||||
|
|
@ -22,35 +19,6 @@ namespace tp {
|
|||
|
||||
namespace tp {
|
||||
|
||||
template <typename T1, typename T2>
|
||||
class Pair {
|
||||
public:
|
||||
Pair() = default;
|
||||
|
||||
template <typename U1, typename U2>
|
||||
Pair(U1 t1, U2 t2) :
|
||||
head(static_cast<T1>(t1)),
|
||||
tail(static_cast<T2>(t2)) {}
|
||||
|
||||
union {
|
||||
T1 t1;
|
||||
T1 head;
|
||||
T1 x;
|
||||
T1 first;
|
||||
};
|
||||
|
||||
union {
|
||||
T2 t2;
|
||||
T2 tail;
|
||||
T2 y;
|
||||
T2 second;
|
||||
};
|
||||
|
||||
bool operator==(const Pair& in) const { return in.t1 == t1 && in.t2 == t2; }
|
||||
|
||||
bool operator!=(const Pair& in) const { return !this->operator==(in); }
|
||||
};
|
||||
|
||||
template <typename Type = alni>
|
||||
class Bits {
|
||||
Type mFlags = 0;
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
|
||||
#include "UnitTest++/UnitTest++.h"
|
||||
|
||||
#include "Debugging.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
using namespace tp;
|
||||
|
||||
void printSnapshot(const tp::CallStackCapture::CallStack* snapshot) {
|
||||
printf("CallStack: \n");
|
||||
for (auto frame : *snapshot) {
|
||||
auto symbols = gCSCapture->getSymbols(frame.getFrame());
|
||||
printf(" %s ----- %s:%llu\n", symbols->getFunc(), symbols->getFile(), symbols->getLine());
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void common() { auto tmp = gCSCapture->getSnapshot(); }
|
||||
|
||||
void first() {
|
||||
common();
|
||||
common();
|
||||
common();
|
||||
}
|
||||
|
||||
void second() {
|
||||
common();
|
||||
common();
|
||||
common();
|
||||
common();
|
||||
}
|
||||
|
||||
void third() {
|
||||
common();
|
||||
common();
|
||||
}
|
||||
|
||||
void root() {
|
||||
first();
|
||||
second();
|
||||
third();
|
||||
}
|
||||
|
||||
SUITE(Utils) {
|
||||
TEST(CallStackCapture) {
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr };
|
||||
tp::ModuleManifest testModule("UtilsTest", nullptr, nullptr, deps);
|
||||
|
||||
REQUIRE CHECK(testModule.initialize());
|
||||
|
||||
root();
|
||||
|
||||
gCSCapture->logAll();
|
||||
|
||||
testModule.deinitialize();
|
||||
}
|
||||
|
||||
TEST(CAllStackCaptureContent) {
|
||||
CHECK(false);
|
||||
}
|
||||
}
|
||||
|
||||
int main() { return UnitTest::RunAllTests(); }
|
||||
Loading…
Add table
Add a link
Reference in a new issue