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")
|
file(GLOB HEADERS "./public/*.hpp")
|
||||||
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC Utils)
|
target_link_libraries(${PROJECT_NAME} PUBLIC Callstack)
|
||||||
|
|
||||||
### -------------------------- Tests -------------------------- ###
|
### -------------------------- Tests -------------------------- ###
|
||||||
enable_testing()
|
enable_testing()
|
||||||
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
||||||
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
add_executable(Tests${PROJECT_NAME} ${TEST_SOURCES})
|
||||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
|
target_link_libraries(Tests${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
|
||||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
add_test(NAME Tests${PROJECT_NAME} COMMAND Tests${PROJECT_NAME})
|
||||||
|
|
@ -13,9 +13,11 @@ static bool init(const tp::ModuleManifest* self) {
|
||||||
return true;
|
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);
|
tp::ModuleManifest tp::gModuleAllocators = ModuleManifest("Allocators", init, deinit, sModuleDependencies);
|
||||||
|
|
||||||
void* operator new(size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
|
void* operator new(size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "HeapAllocatorGlobal.hpp"
|
#include "HeapAllocatorGlobal.hpp"
|
||||||
#include "PrivateConfig.hpp"
|
#include "PrivateConfig.hpp"
|
||||||
|
|
||||||
#include "Debugging.hpp"
|
#include "Callstack.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
@ -33,7 +33,11 @@ tp::ualni tp::HeapAllocGlobal::mNumAllocations = 0;
|
||||||
std::mutex tp::HeapAllocGlobal::mMutex;
|
std::mutex tp::HeapAllocGlobal::mMutex;
|
||||||
bool tp::HeapAllocGlobal::mIgnore = true;
|
bool tp::HeapAllocGlobal::mIgnore = true;
|
||||||
|
|
||||||
// ----------------------- Debug Implementation ---------------------------- //
|
#ifdef MEM_STACK_TRACE
|
||||||
|
tp::CallStackCapture tp::HeapAllocGlobal::mCallstack;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ----------------------- Debug Implementation ---------------------------- //
|
||||||
// |----------------|
|
// |----------------|
|
||||||
// | MemHead |
|
// | MemHead |
|
||||||
// |----------------|
|
// |----------------|
|
||||||
|
|
@ -105,8 +109,7 @@ ALLOCATE:
|
||||||
// 3) Trace the stack
|
// 3) Trace the stack
|
||||||
#ifdef MEM_STACK_TRACE
|
#ifdef MEM_STACK_TRACE
|
||||||
// check if somewhat decides to call new within static variable initialization
|
// check if somewhat decides to call new within static variable initialization
|
||||||
if (gCSCapture) head->mCallStack = gCSCapture->getSnapshot();
|
head->mCallStack = mCallstack.getSnapshot();
|
||||||
else head->mCallStack = nullptr;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mMutex.unlock();
|
mMutex.unlock();
|
||||||
|
|
@ -146,12 +149,16 @@ void HeapAllocGlobal::deallocate(void* aPtr) {
|
||||||
if (!head->mIgnored) {
|
if (!head->mIgnored) {
|
||||||
// 3) Check the wrap
|
// 3) Check the wrap
|
||||||
if (memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL)) {
|
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!")
|
ASSERT(!"Allocated Block Wrap Corrupted!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL)) {
|
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!")
|
ASSERT(!"Allocated Block Wrap Corrupted!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,7 +183,7 @@ bool HeapAllocGlobal::checkLeaks() {
|
||||||
|
|
||||||
#ifdef MEM_STACK_TRACE
|
#ifdef MEM_STACK_TRACE
|
||||||
for (auto iter = mEntry; iter; iter = iter->mPrev) {
|
for (auto iter = mEntry; iter; iter = iter->mPrev) {
|
||||||
if (!iter->mIgnored) CallStackCapture::printSnapshot(iter->mCallStack);
|
if (!iter->mIgnored) mCallstack.printSnapshot(iter->mCallStack);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Module.hpp"
|
#include "Callstack.hpp"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace tp {
|
namespace tp {
|
||||||
|
|
@ -12,6 +12,9 @@ namespace tp {
|
||||||
static struct MemHead* mEntry;
|
static struct MemHead* mEntry;
|
||||||
static std::mutex mMutex;
|
static std::mutex mMutex;
|
||||||
static bool mIgnore;
|
static bool mIgnore;
|
||||||
|
#ifdef MEM_STACK_TRACE // Save stack on allocation call
|
||||||
|
static CallStackCapture mCallstack;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,4 @@
|
||||||
#define MEM_CLEAR_ON_DEALLOC // Clear data on free
|
#define MEM_CLEAR_ON_DEALLOC // Clear data on free
|
||||||
#define MEM_CLEAR_ON_DEALLOC_VAL 0xAA // 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_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
|
#define MEM_STACK_TRACE_MAX_DEPTH 32 // Call stack max depth
|
||||||
|
|
@ -234,7 +234,7 @@ SUITE(Allocators) {
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, &tp::gModuleUtils, nullptr };
|
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, nullptr };
|
||||||
tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
|
tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
|
||||||
|
|
||||||
if (!testModule.initialize()) {
|
if (!testModule.initialize()) {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ project(ModulesRoot)
|
||||||
include(CMakeOptions.txt)
|
include(CMakeOptions.txt)
|
||||||
|
|
||||||
add_subdirectory(Modules)
|
add_subdirectory(Modules)
|
||||||
add_subdirectory(Utils)
|
add_subdirectory(Callstack)
|
||||||
add_subdirectory(Containers)
|
add_subdirectory(Containers)
|
||||||
add_subdirectory(Math)
|
add_subdirectory(Math)
|
||||||
add_subdirectory(Allocators)
|
add_subdirectory(Allocators)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
option(MODULES_MEMORY_DEBUG "Debug memory" ON)
|
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")
|
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)
|
add_compile_definitions(MEM_DEBUG)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (MODULES_MEMORY_DEBUG_STACK_TRACE)
|
||||||
|
add_compile_definitions(MEM_STACK_TRACE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
project(Utils)
|
project(Callstack)
|
||||||
|
|
||||||
### ---------------------- Static Library --------------------- ###
|
### ---------------------- Static Library --------------------- ###
|
||||||
file(GLOB SOURCES "./private/*.cpp")
|
file(GLOB SOURCES "./private/*.cpp")
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
||||||
|
|
||||||
### ---------------------- Dependencies --------------------- ###
|
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC Containers)
|
target_link_libraries(${PROJECT_NAME} PUBLIC Containers)
|
||||||
|
|
||||||
### -------------------------- Tests -------------------------- ###
|
### -------------------------- Tests -------------------------- ###
|
||||||
enable_testing()
|
|
||||||
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
||||||
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
add_executable(Tests${PROJECT_NAME} ${TEST_SOURCES})
|
||||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
|
target_link_libraries(Tests${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
|
||||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
add_test(NAME Tests${PROJECT_NAME} COMMAND Tests${PROJECT_NAME})
|
||||||
|
|
@ -1,19 +1,15 @@
|
||||||
|
|
||||||
#include "Debugging.hpp"
|
#include "Callstack.hpp"
|
||||||
#include "Utils.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace tp;
|
using namespace tp;
|
||||||
|
|
||||||
CallStackCapture* tp::gCSCapture = nullptr;
|
// frame to reference on no sapce left
|
||||||
|
static void errorNoSpaceLeft() {
|
||||||
void initializeCallStackCapture() { gCSCapture = new (malloc(sizeof(CallStackCapture))) CallStackCapture(); }
|
// to disable optimization of function
|
||||||
|
static int dummy;
|
||||||
void deinitializeCallStackCapture() {
|
dummy = 10;
|
||||||
gCSCapture->~CallStackCapture();
|
|
||||||
free(gCSCapture);
|
|
||||||
gCSCapture = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ualni CallStackCapture::CallStack::getDepth() const {
|
ualni CallStackCapture::CallStack::getDepth() const {
|
||||||
|
|
@ -24,14 +20,7 @@ ualni CallStackCapture::CallStack::getDepth() const {
|
||||||
}
|
}
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
ualni stripedLen = 0;
|
return len++;
|
||||||
for (auto i = FRAMES_TO_SKIP_START; i < len - FRAMES_TO_SKIP_END; i++) {
|
|
||||||
if (!frames[i]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
stripedLen++;
|
|
||||||
}
|
|
||||||
return stripedLen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ualni CallStackCapture::hashCallStack(CallStackKey key) {
|
ualni CallStackCapture::hashCallStack(CallStackKey key) {
|
||||||
|
|
@ -44,7 +33,7 @@ ualni CallStackCapture::hashCallStack(CallStackKey key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CallStackCapture::CallStackKey::operator==(const CallStackCapture::CallStackKey& in) const {
|
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]) {
|
if (cs->frames[i] != in.cs->frames[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -60,26 +49,26 @@ CallStackCapture::CallStackCapture() {
|
||||||
static_assert(MAX_CALL_DEPTH_CAPTURE >= 1);
|
static_assert(MAX_CALL_DEPTH_CAPTURE >= 1);
|
||||||
static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB > 0);
|
static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB > 0);
|
||||||
static_assert(MAX_DEBUG_INFO_LEN > sizeof("unresolved"));
|
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));
|
static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024 > sizeof(CallStack));
|
||||||
|
|
||||||
MODULE_SANITY_CHECK(gModuleUtils)
|
|
||||||
mBuffLoad = 0;
|
mBuffLoad = 0;
|
||||||
mBuffLen = (MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024) / sizeof(CallStack);
|
mBuffLen = STACKS_LENGTH;
|
||||||
mBuff = (CallStack*) malloc(mBuffLen * sizeof(CallStack));
|
mBuff = (CallStack*) malloc(mBuffLen * sizeof(CallStack));
|
||||||
|
|
||||||
|
mErrorSnapshot.frames[0] = (alni) & errorNoSpaceLeft;
|
||||||
|
|
||||||
|
|
||||||
|
platformInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CallStackCapture::CallStack* CallStackCapture::getSnapshot() {
|
const CallStackCapture::CallStack* CallStackCapture::getSnapshot() {
|
||||||
MODULE_SANITY_CHECK(gModuleUtils)
|
|
||||||
|
|
||||||
if (mBuffLoad > mBuffLen) {
|
if (mBuffLoad > mBuffLen) {
|
||||||
static CallStack cs;
|
return &mErrorSnapshot;
|
||||||
cs.frames[0] = 0;
|
|
||||||
return &cs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CallStack* cs = &mBuff[mBuffLoad];
|
CallStack* cs = &mBuff[mBuffLoad];
|
||||||
|
|
||||||
platformWriteStackTrace(cs);
|
platformWriteStackTrace(cs);
|
||||||
|
|
||||||
auto idx = mSnapshots.presents({ cs });
|
auto idx = mSnapshots.presents({ cs });
|
||||||
|
|
@ -213,7 +202,7 @@ void CallStackCapture::printSnapshot(const CallStack* snapshot) {
|
||||||
printf("CallStack: \n");
|
printf("CallStack: \n");
|
||||||
if (snapshot) {
|
if (snapshot) {
|
||||||
for (auto frame : *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());
|
printf(" %s ----- %s:%llu\n", symbols->getFunc(), symbols->getFile(), symbols->getLine());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -227,15 +216,112 @@ void CallStackCapture::logAll() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
void CallStackCapture::platformWriteStackTrace(CallStack* stack) { stack->frames[0] = 0; }
|
#include <windows.h>
|
||||||
void CallStackCapture::platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out) {
|
#include <dbghelp.h>
|
||||||
std::strcpy(out->file, "unresolved");
|
#include <stdio.h>
|
||||||
std::strcpy(out->function, "unresolved");
|
|
||||||
|
#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) {
|
void CallStackCapture::printSnapshot(const CallStack* snapshot) {
|
||||||
printf("CallStack: \n");
|
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");
|
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
|
#endif
|
||||||
|
|
@ -3,18 +3,18 @@
|
||||||
#include "Environment.hpp"
|
#include "Environment.hpp"
|
||||||
#include "Map.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 {
|
namespace tp {
|
||||||
|
|
||||||
class CallStackCapture {
|
class CallStackCapture {
|
||||||
public:
|
public:
|
||||||
typedef tp::alni FramePointer;
|
typedef tp::alni FramePointer;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAX_CALL_DEPTH_CAPTURE = 16,
|
||||||
|
MAX_CALL_CAPTURES_MEM_SIZE_MB = 32,
|
||||||
|
MAX_DEBUG_INFO_LEN = 64,
|
||||||
|
};
|
||||||
|
|
||||||
class CallStack {
|
class CallStack {
|
||||||
friend CallStackCapture;
|
friend CallStackCapture;
|
||||||
FramePointer frames[MAX_CALL_DEPTH_CAPTURE];
|
FramePointer frames[MAX_CALL_DEPTH_CAPTURE];
|
||||||
|
|
@ -26,18 +26,19 @@ namespace tp {
|
||||||
const FramePointer* mFrame;
|
const FramePointer* mFrame;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Iterator(const FramePointer* frame) :
|
explicit Iterator(const FramePointer* frame) : mFrame(frame){};
|
||||||
mFrame(frame){};
|
|
||||||
FramePointer getFrame() { return *mFrame; }
|
FramePointer getFrame() { return *mFrame; }
|
||||||
bool operator==(const Iterator& in) const { return in.mFrame == mFrame; }
|
bool operator==(const Iterator& in) const { return in.mFrame == mFrame; }
|
||||||
void operator++() { mFrame++; }
|
void operator++() { mFrame++; }
|
||||||
const Iterator& operator*() const { return *this; }
|
const Iterator& operator*() const { return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] Iterator begin() const { return Iterator(frames + FRAMES_TO_SKIP_START); }
|
[[nodiscard]] Iterator begin() const { return Iterator(frames); }
|
||||||
[[nodiscard]] Iterator end() const { return Iterator(frames + FRAMES_TO_SKIP_START + getDepth()); }
|
[[nodiscard]] Iterator end() const { return Iterator(frames + getDepth()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum { STACKS_LENGTH = (MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024) / sizeof(CallStack) };
|
||||||
|
|
||||||
class DebugSymbols {
|
class DebugSymbols {
|
||||||
friend CallStackCapture;
|
friend CallStackCapture;
|
||||||
char function[MAX_DEBUG_INFO_LEN + 1] = { 0 };
|
char function[MAX_DEBUG_INFO_LEN + 1] = { 0 };
|
||||||
|
|
@ -57,44 +58,15 @@ namespace tp {
|
||||||
[[nodiscard]] const CallStack* getSnapshot();
|
[[nodiscard]] const CallStack* getSnapshot();
|
||||||
const DebugSymbols* getSymbols(FramePointer fp);
|
const DebugSymbols* getSymbols(FramePointer fp);
|
||||||
|
|
||||||
static void printSnapshot(const CallStack* snapshot);
|
void printSnapshot(const CallStack* snapshot);
|
||||||
void logAll();
|
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:
|
public:
|
||||||
class Iterator {
|
class Iterator {
|
||||||
const CallStack* mSnapshot;
|
const CallStack* mSnapshot;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Iterator(const CallStack* start) :
|
explicit Iterator(const CallStack* start) : mSnapshot(start) {};
|
||||||
mSnapshot(start){};
|
|
||||||
const CallStack* getCallStack() { return mSnapshot; }
|
const CallStack* getCallStack() { return mSnapshot; }
|
||||||
bool operator==(const Iterator& in) const { return in.mSnapshot == mSnapshot; }
|
bool operator==(const Iterator& in) const { return in.mSnapshot == mSnapshot; }
|
||||||
void operator++() { mSnapshot++; }
|
void operator++() { mSnapshot++; }
|
||||||
|
|
@ -113,16 +85,19 @@ namespace tp {
|
||||||
static void platformWriteStackTrace(CallStack* stack);
|
static void platformWriteStackTrace(CallStack* stack);
|
||||||
static void platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out);
|
static void platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out);
|
||||||
[[nodiscard]] static ualni hashCallStack(CallStackKey key);
|
[[nodiscard]] static ualni hashCallStack(CallStackKey key);
|
||||||
|
void platformInit();
|
||||||
|
void platformDeinit();
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
CallStack mErrorSnapshot;
|
||||||
|
|
||||||
ualni mBuffLen;
|
ualni mBuffLen;
|
||||||
ualni mBuffLoad;
|
ualni mBuffLoad;
|
||||||
CallStack* mBuff;
|
CallStack* mBuff;
|
||||||
|
|
||||||
Map<CallStackKey, CallStack*, DefaultAllocator, hashCallStack> mSnapshots;
|
Map<CallStackKey, CallStack*, DefaultAllocator, hashCallStack> mSnapshots;
|
||||||
Map<FramePointer, DebugSymbols> mSymbols;
|
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)
|
target_link_libraries(${PROJECT_NAME} PUBLIC Modules)
|
||||||
|
|
||||||
### -------------------------- Tests -------------------------- ###
|
### -------------------------- Tests -------------------------- ###
|
||||||
enable_testing()
|
|
||||||
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
file(GLOB TEST_SOURCES "./tests/*.cpp")
|
||||||
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
|
add_executable(Tests${PROJECT_NAME} ${TEST_SOURCES})
|
||||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Allocators UnitTest++)
|
target_link_libraries(Tests${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
|
||||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
add_test(NAME Tests${PROJECT_NAME} COMMAND Tests${PROJECT_NAME})
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
|
|
||||||
namespace tp {
|
namespace tp {
|
||||||
|
|
||||||
static ModuleManifest* sModuleDependencies[] = { &gModuleBase, nullptr };
|
|
||||||
ModuleManifest gModuleContainers = ModuleManifest("Containers", nullptr, nullptr, sModuleDependencies);
|
|
||||||
|
|
||||||
void* DefaultAllocator::allocate(ualni size) { return malloc(size); }
|
void* DefaultAllocator::allocate(ualni size) { return malloc(size); }
|
||||||
|
|
||||||
void DefaultAllocator::deallocate(void* p) { free(p); }
|
void DefaultAllocator::deallocate(void* p) { free(p); }
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,12 @@ namespace tp {
|
||||||
class Buffer2D {
|
class Buffer2D {
|
||||||
public:
|
public:
|
||||||
typedef ualni Index;
|
typedef ualni Index;
|
||||||
typedef Pair<Index, Index> Index2D;
|
|
||||||
|
struct Index2D {
|
||||||
|
Index x = 0;
|
||||||
|
Index y = 0;
|
||||||
|
};
|
||||||
|
|
||||||
typedef SelectValueOrReference<tType> tTypeArg;
|
typedef SelectValueOrReference<tType> tTypeArg;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
#include "Module.hpp"
|
#include "Module.hpp"
|
||||||
|
|
||||||
namespace tp {
|
namespace tp {
|
||||||
extern ModuleManifest gModuleContainers;
|
|
||||||
|
|
||||||
class DefaultAllocator {
|
class DefaultAllocator {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,6 @@ namespace tp {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Map() {
|
Map() {
|
||||||
MODULE_SANITY_CHECK(gModuleContainers)
|
|
||||||
mNSlots = next2pow(uhalni(tTableInitialSize - 1));
|
mNSlots = next2pow(uhalni(tTableInitialSize - 1));
|
||||||
mTable = newTable(mNSlots);
|
mTable = newTable(mNSlots);
|
||||||
}
|
}
|
||||||
|
|
@ -243,7 +242,13 @@ namespace tp {
|
||||||
if (this == &in) {
|
if (this == &in) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
removeAll();
|
|
||||||
|
for (ualni i = 0; i < mNSlots; i++) {
|
||||||
|
if (mTable[i] && !isDeletedNode(mTable[i])) {
|
||||||
|
deleteNode(mTable[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mNEntries = 0;
|
||||||
mNSlots = in.mNSlots;
|
mNSlots = in.mNSlots;
|
||||||
deleteTable(mTable);
|
deleteTable(mTable);
|
||||||
mTable = newTable(mNSlots);
|
mTable = newTable(mNSlots);
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ namespace tp {
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AvlTree() { MODULE_SANITY_CHECK(gModuleContainers) }
|
AvlTree() {}
|
||||||
~AvlTree() { removeAll(); }
|
~AvlTree() { removeAll(); }
|
||||||
|
|
||||||
[[nodiscard]] ualni size() const { return mSize; }
|
[[nodiscard]] ualni size() const { return mSize; }
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
#include "Buffer2D.hpp"
|
#include "Buffer2D.hpp"
|
||||||
#include "Tests.hpp"
|
#include "Tests.hpp"
|
||||||
|
|
||||||
#include "HeapAllocator.hpp"
|
|
||||||
|
|
||||||
using namespace tp;
|
using namespace tp;
|
||||||
|
|
||||||
const ualni size = 1000;
|
const ualni size = 1000;
|
||||||
|
|
||||||
SUITE(Buffer2D) {
|
SUITE(Buffer2D) {
|
||||||
TEST(Simple) {
|
TEST(Simple) {
|
||||||
Buffer2D<int, tp::HeapAlloc> buff;
|
Buffer2D<int, TestAllocator> buff;
|
||||||
buff.reserve({ 4, 4 });
|
buff.reserve({ 4, 4 });
|
||||||
buff.set({ 2, 2 }, 5);
|
buff.set({ 2, 2 }, 5);
|
||||||
CHECK(buff.get({ 2, 2 }) == 5);
|
CHECK(buff.get({ 2, 2 }) == 5);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const ualni size = 1000;
|
||||||
|
|
||||||
SUITE(Buffer) {
|
SUITE(Buffer) {
|
||||||
TEST(Simple1) {
|
TEST(Simple1) {
|
||||||
Buffer<TestClass, tp::HeapAlloc> buff;
|
Buffer<TestClass, TestAllocator> buff;
|
||||||
CHECK(buff.size() == 0);
|
CHECK(buff.size() == 0);
|
||||||
for (auto i : Range(size * 10)) {
|
for (auto i : Range(size * 10)) {
|
||||||
buff.append(TestClass(i));
|
buff.append(TestClass(i));
|
||||||
|
|
@ -19,7 +19,7 @@ SUITE(Buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Simple2) {
|
TEST(Simple2) {
|
||||||
Buffer<TestClass, tp::HeapAlloc> buff(size);
|
Buffer<TestClass, TestAllocator> buff(size);
|
||||||
CHECK(buff.size() == size);
|
CHECK(buff.size() == size);
|
||||||
for (auto i : Range(size * 10))
|
for (auto i : Range(size * 10))
|
||||||
buff.append(TestClass(i));
|
buff.append(TestClass(i));
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ SUITE(IntervalTree) {
|
||||||
ualni numFound = 0;
|
ualni numFound = 0;
|
||||||
ualni lastDataFound = 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 notFound() const { return numFound == 0; }
|
||||||
[[nodiscard]] bool found(ualni num) const { return numFound == num; }
|
[[nodiscard]] bool found(ualni num) const { return numFound == num; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ using namespace tp;
|
||||||
SUITE(DoubleLinkedList) {
|
SUITE(DoubleLinkedList) {
|
||||||
|
|
||||||
TEST(SimpleReference) {
|
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.pushBack(TestClass(5));
|
||||||
list.pushFront(TestClass(0));
|
list.pushFront(TestClass(0));
|
||||||
|
|
@ -24,7 +24,9 @@ SUITE(DoubleLinkedList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SimplePointer) {
|
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.pushBack(new TestClass(5));
|
||||||
list.pushFront(new TestClass(0));
|
list.pushFront(new TestClass(0));
|
||||||
|
|
@ -45,8 +47,8 @@ SUITE(DoubleLinkedList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Copy) {
|
TEST(Copy) {
|
||||||
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) };
|
||||||
tp::List<TestClass, tp::HeapAlloc> list2 = list;
|
tp::List<TestClass, TestAllocator> list2 = list;
|
||||||
|
|
||||||
CHECK(list == list2);
|
CHECK(list == list2);
|
||||||
|
|
||||||
|
|
@ -55,7 +57,7 @@ SUITE(DoubleLinkedList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Serialization) {
|
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, false> write;
|
||||||
ArchiverExample<1024, true> read;
|
ArchiverExample<1024, true> read;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using namespace tp;
|
||||||
|
|
||||||
SUITE(HashTable) {
|
SUITE(HashTable) {
|
||||||
TEST(SimpleReference) {
|
TEST(SimpleReference) {
|
||||||
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
|
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
||||||
|
|
||||||
for (auto i : Range(1000, 100000)) {
|
for (auto i : Range(1000, 100000)) {
|
||||||
map.put(i, TestClass(i));
|
map.put(i, TestClass(i));
|
||||||
|
|
@ -40,7 +40,7 @@ SUITE(HashTable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SimplePointer) {
|
TEST(SimplePointer) {
|
||||||
tp::Map<tp::ualni, TestClass*, tp::HeapAlloc> map;
|
tp::Map<tp::ualni, TestClass*, TestAllocator> map;
|
||||||
|
|
||||||
for (auto i : Range(1000)) {
|
for (auto i : Range(1000)) {
|
||||||
map.put(i, new TestClass(i));
|
map.put(i, new TestClass(i));
|
||||||
|
|
@ -78,13 +78,13 @@ SUITE(HashTable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Copy) {
|
TEST(Copy) {
|
||||||
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
|
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
||||||
|
|
||||||
for (auto i : Range(10)) {
|
for (auto i : Range(10)) {
|
||||||
map.put(i, TestClass(i));
|
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);
|
CHECK(map == map2);
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ SUITE(HashTable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SaveLoad) {
|
TEST(SaveLoad) {
|
||||||
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
|
tp::Map<tp::ualni, TestClass, TestAllocator> map;
|
||||||
|
|
||||||
for (auto i : Range(10)) {
|
for (auto i : Range(10)) {
|
||||||
map.put(i, TestClass(i));
|
map.put(i, TestClass(i));
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,23 @@
|
||||||
#include "Tests.hpp"
|
#include "Tests.hpp"
|
||||||
#include "UnitTest++/UnitTest++.h"
|
#include "UnitTest++/UnitTest++.h"
|
||||||
|
|
||||||
int main() {
|
void* TestAllocator::allocate(tp::ualni size) {
|
||||||
|
count++;
|
||||||
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, &tp::gModuleAllocators, nullptr };
|
return malloc(size);
|
||||||
tp::ModuleManifest testModule("ContainersTest", nullptr, nullptr, deps);
|
}
|
||||||
|
|
||||||
if (!testModule.initialize()) {
|
void TestAllocator::deallocate(void* p) {
|
||||||
return 1;
|
if (p) {
|
||||||
}
|
free(p);
|
||||||
|
count--;
|
||||||
bool res = UnitTest::RunAllTests();
|
}
|
||||||
|
}
|
||||||
testModule.deinitialize();
|
|
||||||
|
|
||||||
return res;
|
TestAllocator::~TestAllocator() {
|
||||||
|
ASSERT(!count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return UnitTest::RunAllTests();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,20 @@
|
||||||
|
|
||||||
#include "UnitTest++/UnitTest++.h"
|
#include "UnitTest++/UnitTest++.h"
|
||||||
|
|
||||||
#include "Allocators.hpp"
|
|
||||||
#include "Utils.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 {
|
class TestClass {
|
||||||
tp::ualni val2 = 0;
|
tp::ualni val2 = 0;
|
||||||
tp::ualni val1;
|
tp::ualni val1;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ using namespace tp;
|
||||||
|
|
||||||
SUITE(AvlTree) {
|
SUITE(AvlTree) {
|
||||||
TEST(Simple) {
|
TEST(Simple) {
|
||||||
AvlTree<AvlNumericKey<alni>, TestClass, tp::HeapAlloc> tree;
|
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
|
||||||
|
|
||||||
CHECK(tree.size() == 0);
|
CHECK(tree.size() == 0);
|
||||||
CHECK(tree.head() == nullptr);
|
CHECK(tree.head() == nullptr);
|
||||||
|
|
@ -22,7 +22,7 @@ SUITE(AvlTree) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Persistance) {
|
TEST(Persistance) {
|
||||||
AvlTree<AvlNumericKey<alni>, TestClass, tp::HeapAlloc> tree;
|
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
|
||||||
|
|
||||||
const auto size = 1000;
|
const auto size = 1000;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,6 @@
|
||||||
|
|
||||||
using namespace tp;
|
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) {
|
ModuleManifest::ModuleManifest(const char* aModuleName, ModuleInit aInit, ModuleDeinit aDeinit, ModuleManifest** aDependencies) {
|
||||||
mInit = aInit;
|
mInit = aInit;
|
||||||
mDeinit = aDeinit;
|
mDeinit = aDeinit;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ namespace tp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove
|
||||||
float Timer::easeIn(time_ms pDuration) {
|
float Timer::easeIn(time_ms pDuration) {
|
||||||
if (!pDuration) {
|
if (!pDuration) {
|
||||||
pDuration = mDuration;
|
pDuration = mDuration;
|
||||||
|
|
@ -55,6 +56,7 @@ namespace tp {
|
||||||
return clamp((1.1f * x) / (x + 0.1f), 0.f, 1.f);
|
return clamp((1.1f * x) / (x + 0.1f), 0.f, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove
|
||||||
float Timer::easeOut(time_ms pDuration) {
|
float Timer::easeOut(time_ms pDuration) {
|
||||||
if (!pDuration) {
|
if (!pDuration) {
|
||||||
pDuration = mDuration;
|
pDuration = mDuration;
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
|
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
|
||||||
#include "ContainersCommon.hpp"
|
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
|
@ -21,12 +19,7 @@ static void deinitialize(const tp::ModuleManifest*) {
|
||||||
|
|
||||||
namespace tp {
|
namespace tp {
|
||||||
|
|
||||||
static ModuleManifest* sModuleUtilsDeps[] = { &gModuleContainers, nullptr };
|
|
||||||
ModuleManifest gModuleUtils = ModuleManifest("Utils", initialize, deinitialize, sModuleUtilsDeps);
|
|
||||||
|
|
||||||
void memSetVal(void* p, uhalni byteSize, uint1 val) {
|
void memSetVal(void* p, uhalni byteSize, uint1 val) {
|
||||||
// MODULE_SANITY_CHECK(gModuleBase)
|
|
||||||
|
|
||||||
alni alignedVal = val;
|
alni alignedVal = val;
|
||||||
alignedVal = (alignedVal << 8) | alignedVal;
|
alignedVal = (alignedVal << 8) | alignedVal;
|
||||||
alignedVal = (alignedVal << 16) | alignedVal;
|
alignedVal = (alignedVal << 16) | alignedVal;
|
||||||
|
|
@ -44,8 +37,6 @@ namespace tp {
|
||||||
}
|
}
|
||||||
|
|
||||||
void memCopy(void* left, const void* right, uhalni len) {
|
void memCopy(void* left, const void* right, uhalni len) {
|
||||||
MODULE_SANITY_CHECK(gModuleBase)
|
|
||||||
|
|
||||||
ualni alignedLen = len / sizeof(alni);
|
ualni alignedLen = len / sizeof(alni);
|
||||||
for (ualni idx = 0; idx < alignedLen; idx++) {
|
for (ualni idx = 0; idx < alignedLen; idx++) {
|
||||||
((alni*) left)[idx] = ((alni*) right)[idx];
|
((alni*) left)[idx] = ((alni*) right)[idx];
|
||||||
|
|
@ -58,7 +49,6 @@ namespace tp {
|
||||||
}
|
}
|
||||||
|
|
||||||
int1 memCompare(const void* left, const void* right, uhalni len) {
|
int1 memCompare(const void* left, const void* right, uhalni len) {
|
||||||
MODULE_SANITY_CHECK(gModuleBase)
|
|
||||||
if (!len) return 0;
|
if (!len) return 0;
|
||||||
|
|
||||||
ualni alignedLength = len / sizeof(alni);
|
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; }
|
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) {
|
int1 memCompareVal(const void* left, uhalni len, uint1 val) {
|
||||||
MODULE_SANITY_CHECK(gModuleBase)
|
|
||||||
if (!len) return 0;
|
if (!len) return 0;
|
||||||
|
|
||||||
alni valAligned = val;
|
alni valAligned = val;
|
||||||
|
|
@ -30,6 +30,4 @@ namespace tp {
|
||||||
uhalni mInitCount = 0;
|
uhalni mInitCount = 0;
|
||||||
void* mCustomData = nullptr;
|
void* mCustomData = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ModuleManifest gModuleBase;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,6 @@
|
||||||
#define MEMBER_OFFSET(s, m) (alni(&(((s*) 0)->m)))
|
#define MEMBER_OFFSET(s, m) (alni(&(((s*) 0)->m)))
|
||||||
|
|
||||||
namespace tp {
|
namespace tp {
|
||||||
|
|
||||||
extern ModuleManifest gModuleUtils;
|
|
||||||
|
|
||||||
void memSetVal(void* p, uhalni byteSize, uint1 val);
|
void memSetVal(void* p, uhalni byteSize, uint1 val);
|
||||||
void memCopy(void* left, const void* right, uhalni len);
|
void memCopy(void* left, const void* right, uhalni len);
|
||||||
int1 memCompare(const 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 {
|
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>
|
template <typename Type = alni>
|
||||||
class Bits {
|
class Bits {
|
||||||
Type mFlags = 0;
|
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