flatten 20260225
This commit is contained in:
42
tjp/core/debug/Allocations.cpp
Executable file
42
tjp/core/debug/Allocations.cpp
Executable file
@@ -0,0 +1,42 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include "Allocations.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace tjp::core::debug {
|
||||
|
||||
void Allocations::onAllocation (const type_index &t)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
allocations[t.name()].count++;
|
||||
}
|
||||
|
||||
void Allocations::onDeallocation (const type_index &t)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
allocations[t.name()].count--;
|
||||
}
|
||||
|
||||
String Allocations::log ()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for (auto &[id, a]: allocations)
|
||||
{
|
||||
if (a.count)
|
||||
ss << id << ": " << a.count << std::endl;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
Allocations *Allocations::shared()
|
||||
{
|
||||
static Allocations *allocations = new Allocations();
|
||||
return allocations;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
58
tjp/core/debug/Allocations.h
Executable file
58
tjp/core/debug/Allocations.h
Executable file
@@ -0,0 +1,58 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Debug.h"
|
||||
#include <typeinfo>
|
||||
#include "../containers/Map.h"
|
||||
#include "../string/String.h"
|
||||
#include "../threads/Lock.hpp"
|
||||
#include "../algorithm/ExecuteOnDestruct.hpp"
|
||||
#include "../rtti/RTTI.hpp"
|
||||
|
||||
namespace tjp::core::debug {
|
||||
|
||||
struct Allocations
|
||||
{
|
||||
struct Allocation {
|
||||
int count = 0;
|
||||
} ;
|
||||
|
||||
Mutex mutex;
|
||||
Map<String, Allocation> allocations;
|
||||
|
||||
void onAllocation (const type_index &t);
|
||||
void onDeallocation (const type_index &t);
|
||||
String log ();
|
||||
|
||||
static Allocations *shared();
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(_DEBUG)
|
||||
|
||||
#define ALLOC_RECORD(x) \
|
||||
tjp::core::debug::Allocations::shared()->onAllocation(type_id(*x))
|
||||
#define DEALLOC_RECORD(x) \
|
||||
tjp::core::debug::Allocations::shared()->onDeallocation(type_id(*x))
|
||||
|
||||
#define SCOPE_RECORD(x) \
|
||||
struct __ALLOC__##x __alloc__ {}; \
|
||||
ALLOC_RECORD(&__alloc_); \
|
||||
tjp::core::ExecuteOnDestruct __dealloc__([&]() { DEALLOC_RECORD(&__alloc__)); \
|
||||
|
||||
#define ALLOC_LOG() \
|
||||
sLogRelease("alloc", tjp::core::debug::Allocations::shared()->log())
|
||||
|
||||
#else
|
||||
|
||||
#define ALLOC_RECORD(x)
|
||||
#define DEALLOC_RECORD(x)
|
||||
#define SCOPE_RECORD(x)
|
||||
|
||||
#define ALLOC_LOG()
|
||||
|
||||
#endif
|
||||
25
tjp/core/debug/Allocations.hpp
Normal file
25
tjp/core/debug/Allocations.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../system/Debug.h"
|
||||
#include <typeinfo>
|
||||
#include "../containers/Map.h"
|
||||
#include "../string/String.h"
|
||||
#include "../threads/Lock.hpp"
|
||||
|
||||
namespace timprepscius::core::debug {
|
||||
|
||||
struct Allocations
|
||||
{
|
||||
Mutex mutex;
|
||||
Map<String, int> allocations;
|
||||
|
||||
void onAllocation (const std::type_info &t);
|
||||
void onDeallocation (const std::type_info &t);
|
||||
|
||||
static Allocations *shared();
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
|
||||
14
tjp/core/debug/CompileTimeSizeOf.h
Executable file
14
tjp/core/debug/CompileTimeSizeOf.h
Executable file
@@ -0,0 +1,14 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
template<typename T, unsigned int N>
|
||||
struct CompileTimeSizeOf_
|
||||
{
|
||||
unsigned char operator()() { return N + 256; } //deliberately causing overflow
|
||||
};
|
||||
|
||||
#define COMPILE_TIME_SIZEOF(x) CompileTimeSizeOf_<x, sizeof(x)>()();
|
||||
|
||||
34
tjp/core/debug/Debug.h
Executable file
34
tjp/core/debug/Debug.h
Executable file
@@ -0,0 +1,34 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../system/Debug.h"
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
#define xDebugLine() { int x = 0; (void)x; }
|
||||
#define IS_DEBUG() 1
|
||||
|
||||
#ifndef _DEBUG
|
||||
#define _DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define xDebugLine() (void)0;
|
||||
#define IS_DEBUG() 0
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
#define DEBUG_ONLY(...) __VA_ARGS__
|
||||
#else
|
||||
#define DEBUG_ONLY(...)
|
||||
#endif
|
||||
7
tjp/core/debug/RUN_IF.h
Executable file
7
tjp/core/debug/RUN_IF.h
Executable file
@@ -0,0 +1,7 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#define RUN_IF(x, ...) if constexpr(x){ __VA_ARGS__; }
|
||||
23
tjp/core/debug/Stack.h
Executable file
23
tjp/core/debug/Stack.h
Executable file
@@ -0,0 +1,23 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../system/Debug.h"
|
||||
#include "../system/System.h"
|
||||
#include <string>
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
std::string getStackString(int maxStackDepth=32);
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifdef TJP_CORE_HEADER_ONLY
|
||||
#ifdef SYS_ANDROID
|
||||
#include "android/Stack.cpp"
|
||||
#else
|
||||
#include "glib/Stack.cpp"
|
||||
#endif
|
||||
#endif
|
||||
99
tjp/core/debug/StackUsage.cpp
Executable file
99
tjp/core/debug/StackUsage.cpp
Executable file
@@ -0,0 +1,99 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#include "StackUsage.h"
|
||||
#include <pthread.h>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
|
||||
#include "../system/System.h"
|
||||
|
||||
#ifdef SYS_APPLE
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/thread_info.h>
|
||||
#include <mach/thread_act.h>
|
||||
#include <mach/mach_types.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
#ifndef SYS_ANDROID
|
||||
|
||||
#ifdef SYS_APPLE
|
||||
void *getStackBase ()
|
||||
{
|
||||
return pthread_get_stackaddr_np(pthread_self());
|
||||
|
||||
/*
|
||||
uint64_t threadId;
|
||||
pthread_threadid_np(nullptr, &threadId);
|
||||
|
||||
// Get thread info
|
||||
mach_msg_type_number_t threadInfoCount = THREAD_BASIC_INFO_COUNT;
|
||||
thread_basic_info_data_t threadInfo;
|
||||
if (thread_info((thread_act_t)threadId, THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &threadInfoCount) != KERN_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the stack base address
|
||||
void* stackBase = (void*)threadInfo.stack_base;
|
||||
return stackBase;
|
||||
*/
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void *getStackBase()
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_getattr_np(pthread_self(), &attr);
|
||||
|
||||
// Get the stack base address
|
||||
void* stackBase = nullptr;
|
||||
pthread_attr_getstackaddr(&attr, &stackBase);
|
||||
|
||||
// Clean up thread attributes
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
return stackBase;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::size_t getStackUsage() {
|
||||
// Define a local variable
|
||||
int localVariable;
|
||||
|
||||
void* stackBase = getStackBase();
|
||||
|
||||
// Calculate the current stack pointer (address of localVariable)
|
||||
std::uintptr_t currentStackPointer = reinterpret_cast<std::uintptr_t>(&localVariable);
|
||||
|
||||
// Calculate the stack usage
|
||||
std::size_t stackUsage = static_cast<std::size_t>(reinterpret_cast<std::uintptr_t>(stackBase) - currentStackPointer);
|
||||
|
||||
return stackUsage;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
std::size_t getStackUsage() {
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_getattr_np(pthread_self(), &attr);
|
||||
|
||||
size_t size = 0;
|
||||
pthread_attr_getstacksize(&attr, &size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
13
tjp/core/debug/StackUsage.h
Executable file
13
tjp/core/debug/StackUsage.h
Executable file
@@ -0,0 +1,13 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
size_t getStackUsage();
|
||||
|
||||
} // namespace
|
||||
81
tjp/core/debug/android/Stack.cpp
Executable file
81
tjp/core/debug/android/Stack.cpp
Executable file
@@ -0,0 +1,81 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#ifdef TJP_CORE_HEADER_ONLY
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "../../header_only/compile.h"
|
||||
|
||||
#include "../Stack.h"
|
||||
#include "../../system/System.h"
|
||||
|
||||
#include <unwind.h>
|
||||
#include <dlfcn.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
// https://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace
|
||||
struct BacktraceState
|
||||
{
|
||||
void** current;
|
||||
void** end;
|
||||
};
|
||||
|
||||
|
||||
TJP_CORE_HEADER_ONLY_INLINE
|
||||
static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg)
|
||||
{
|
||||
BacktraceState* state = static_cast<BacktraceState*>(arg);
|
||||
uintptr_t pc = _Unwind_GetIP(context);
|
||||
if (pc) {
|
||||
if (state->current == state->end) {
|
||||
return _URC_END_OF_STACK;
|
||||
} else {
|
||||
*state->current++ = reinterpret_cast<void*>(pc);
|
||||
}
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
TJP_CORE_HEADER_ONLY_INLINE
|
||||
size_t captureBacktrace(void** buffer, size_t max)
|
||||
{
|
||||
BacktraceState state = {buffer, buffer + max};
|
||||
_Unwind_Backtrace(unwindCallback, &state);
|
||||
|
||||
return state.current - buffer;
|
||||
}
|
||||
|
||||
TJP_CORE_HEADER_ONLY_INLINE
|
||||
void dumpBacktrace(std::ostream& os, void** buffer, size_t count)
|
||||
{
|
||||
for (size_t idx = 0; idx < count; ++idx) {
|
||||
const void* addr = buffer[idx];
|
||||
const char* symbol = "";
|
||||
|
||||
Dl_info info;
|
||||
if (dladdr(addr, &info) && info.dli_sname) {
|
||||
symbol = info.dli_sname;
|
||||
}
|
||||
|
||||
os << " #" << std::setw(2) << idx << ": " << addr << " " << symbol << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
TJP_CORE_HEADER_ONLY_INLINE
|
||||
std::string getStackString(int maxStackDepth)
|
||||
{
|
||||
auto buffer = (void **)alloca(sizeof(void *) * maxStackDepth);
|
||||
auto count = captureBacktrace(buffer, maxStackDepth);
|
||||
|
||||
std::ostringstream oss;
|
||||
dumpBacktrace(oss, buffer, count);
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
24
tjp/core/debug/debug_break.h
Executable file
24
tjp/core/debug/debug_break.h
Executable file
@@ -0,0 +1,24 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../system/Debug.h"
|
||||
|
||||
#include "../system/System.h"
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
#ifdef _DEBUG
|
||||
inline void debug_break()
|
||||
{
|
||||
#ifdef SYS_APPLE
|
||||
__asm__("brk #0");
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
inline void debug_break() {};
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
43
tjp/core/debug/glib/Stack.cpp
Executable file
43
tjp/core/debug/glib/Stack.cpp
Executable file
@@ -0,0 +1,43 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#ifdef TJP_CORE_HEADER_ONLY
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "../../header_only/compile.h"
|
||||
|
||||
#include "../Stack.h"
|
||||
#include "../../system/System.h"
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
TJP_CORE_HEADER_ONLY_INLINE
|
||||
std::string getStackString(int maxStackDepth)
|
||||
{
|
||||
void* trace[64];
|
||||
if (maxStackDepth > 64) maxStackDepth = 64;
|
||||
|
||||
char** messages = NULL;
|
||||
int trace_size = 0;
|
||||
|
||||
std::ostringstream out;
|
||||
|
||||
trace_size = backtrace( trace, maxStackDepth );
|
||||
messages = backtrace_symbols( trace, trace_size );
|
||||
for( int i = 2; i < trace_size; ++i ) {
|
||||
out << "\t" << messages[i] << std::endl;
|
||||
}
|
||||
|
||||
free (messages);
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user