DN/Source/Core/dn_core_debug.h
2025-09-17 21:48:33 +10:00

108 lines
4.6 KiB
C

#if !defined(DN_CORE_DEBUG_H)
#define DN_CORE_DEBUG_H
#include "../dn_base_inc.h"
// NOTE: DN_Debug
enum DN_DebugAllocFlag
{
DN_DebugAllocFlag_Freed = 1 << 0,
DN_DebugAllocFlag_LeakPermitted = 1 << 1,
};
struct DN_DebugAlloc
{
void *ptr; // 8 Pointer to the allocation being tracked
DN_USize size; // 16 Size of the allocation
DN_USize freed_size; // 24 Store the size of the allocation when it is freed
DN_Str8 stack_trace; // 40 Stack trace at the point of allocation
DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed
DN_U16 flags; // 72 Bit flags from `DN_DebugAllocFlag`
};
static_assert(sizeof(DN_DebugAlloc) == 64 || sizeof(DN_DebugAlloc) == 32, // NOTE: 64 bit vs 32 bit pointers respectively
"We aim to keep the allocation record as light as possible as "
"memory tracking can get expensive. Enforce that there is no "
"unexpected padding.");
// NOTE: DN_Profiler
struct DN_ProfilerAnchor
{
// Inclusive refers to the time spent to complete the function call
// including all children functions.
//
// Exclusive refers to the time spent in the function, not including any
// time spent in children functions that we call that are also being
// profiled. If we recursively call into ourselves, the time we spent in
// our function is accumulated.
DN_U64 tsc_inclusive;
DN_U64 tsc_exclusive;
DN_U16 hit_count;
DN_Str8 name;
};
struct DN_ProfilerZone
{
DN_U16 anchor_index;
DN_U64 begin_tsc;
DN_U16 parent_zone;
DN_U64 elapsed_tsc_at_zone_start;
};
struct DN_ProfilerAnchorArray
{
DN_ProfilerAnchor *data;
DN_USize count;
};
enum DN_ProfilerTSC
{
DN_ProfilerTSC_RDTSC,
DN_ProfilerTSC_OSPerformanceCounter,
};
struct DN_Profiler
{
DN_USize frame_index;
DN_ProfilerAnchor *anchors;
DN_USize anchors_count;
DN_USize anchors_per_frame;
DN_U16 parent_zone;
bool paused;
DN_ProfilerTSC tsc;
DN_U64 tsc_frequency;
DN_ProfilerZone frame_zone;
DN_F64 frame_avg_tsc;
};
#define DN_Profiler_ZoneLoop(prof, name, index) \
DN_ProfilerZone DN_UniqueName(zone_) = DN_Profiler_BeginZone(prof, DN_STR8(name), index), DN_UniqueName(dummy_) = {}; \
DN_UniqueName(dummy_).begin_tsc == 0; \
DN_Profiler_EndZone(prof, DN_UniqueName(zone_)), DN_UniqueName(dummy_).begin_tsc = 1
#define DN_Profiler_ZoneLoopAuto(prof, name) DN_Profiler_ZoneLoop(prof, name, __COUNTER__ + 1)
DN_API DN_Profiler DN_Profiler_Init (DN_ProfilerAnchor *anchors, DN_USize count, DN_USize anchors_per_frame, DN_ProfilerTSC tsc, DN_U64 tsc_frequency);
DN_API DN_ProfilerZone DN_Profiler_BeginZone (DN_Profiler *profiler, DN_Str8 name, DN_U16 anchor_index);
#define DN_Profiler_BeginZoneAuto(prof, name) DN_Profiler_BeginZone(prof, DN_STR8(name), __COUNTER__ + 1)
DN_API void DN_Profiler_EndZone (DN_Profiler *profiler, DN_ProfilerZone zone);
DN_API DN_USize DN_Profiler_FrameCount (DN_Profiler const *profiler);
DN_API DN_ProfilerAnchorArray DN_Profiler_FrameAnchorsFromIndex (DN_Profiler *profiler, DN_USize frame_index);
DN_API DN_ProfilerAnchorArray DN_Profiler_FrameAnchors (DN_Profiler *profiler);
DN_API void DN_Profiler_NewFrame (DN_Profiler *profiler);
DN_API void DN_Profiler_Dump (DN_Profiler *profiler);
DN_API DN_F64 DN_Profiler_SecFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc);
DN_API DN_F64 DN_Profiler_MsFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc);
#if defined(DN_LEAK_TRACKING)
DN_API void DN_DBGTrackAlloc (void *ptr, DN_USize size, bool alloc_can_leak);
DN_API void DN_DBGTrackDealloc (void *ptr);
DN_API void DN_DBGDumpLeaks ();
#else
#define DN_DBGTrackAlloc(ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0)
#define DN_DBGTrackDealloc(ptr) do { (void)ptr; } while (0)
#define DN_DBGDumpLeaks() do { } while (0)
#endif
#endif // DN_CORE_DEBUG_H