2019-07-19 20:56:21 +00:00
|
|
|
#define SCOPE_NAME_LENGTH 256
|
|
|
|
struct scope_time_record
|
|
|
|
{
|
|
|
|
char ScopeName_[SCOPE_NAME_LENGTH];
|
|
|
|
string ScopeName;
|
|
|
|
|
|
|
|
u32 Duration_Cycles;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct debug_interface
|
|
|
|
{
|
|
|
|
b32 ShowCameraMouse;
|
|
|
|
b32 ShowTrackedScopes;
|
|
|
|
b32 RenderSculpture;
|
|
|
|
b32 SendSACNData;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef s64 debug_timing_proc();
|
|
|
|
|
|
|
|
#define HISTOGRAM_DEPTH 10
|
|
|
|
struct debug_histogram_entry
|
|
|
|
{
|
|
|
|
char ScopeName_[SCOPE_NAME_LENGTH];
|
|
|
|
string ScopeName;
|
|
|
|
|
|
|
|
u32 PerFrame_Cycles[HISTOGRAM_DEPTH];
|
|
|
|
u32 PerFrame_CallCount[HISTOGRAM_DEPTH];
|
|
|
|
s32 CurrentFrame;
|
|
|
|
|
|
|
|
// NOTE(Peter): Cached Values, recalculated ever frame
|
|
|
|
u32 Average_Cycles;
|
|
|
|
u32 Average_CallCount;
|
|
|
|
u32 Total_Cycles;
|
|
|
|
u32 Total_CallCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define SCOPE_HISTOGRAM_SIZE 512
|
|
|
|
struct debug_services
|
|
|
|
{
|
|
|
|
s32 TrackedScopesCount;
|
|
|
|
s32 TrackedScopesMax;
|
|
|
|
scope_time_record* TrackedScopes;
|
|
|
|
|
|
|
|
s64 PerformanceCountFrequency;
|
|
|
|
memory_arena DebugStorage;
|
|
|
|
|
|
|
|
debug_interface Interface;
|
|
|
|
|
|
|
|
debug_timing_proc* GetWallClock;
|
|
|
|
|
2019-11-02 20:17:23 +00:00
|
|
|
debug_histogram_entry* ScopeHistogramUnsorted;
|
|
|
|
debug_histogram_entry* ScopeHistogramSorted;
|
|
|
|
|
2019-07-19 20:56:21 +00:00
|
|
|
s32 ScopeHistogramUsed;
|
|
|
|
};
|
|
|
|
|
|
|
|
internal void
|
|
|
|
InitDebugServices (debug_services* Services, u8* Memory, s32 MemorySize, s32 TrackedScopesMax, s64 PerformanceCountFrequency)
|
|
|
|
{
|
|
|
|
InitMemoryArena(&Services->DebugStorage, Memory, MemorySize, 0);
|
|
|
|
|
|
|
|
Services->TrackedScopesCount = 0;
|
|
|
|
Services->TrackedScopesMax = TrackedScopesMax;
|
|
|
|
Services->TrackedScopes = PushArray(&Services->DebugStorage, scope_time_record, TrackedScopesMax);
|
|
|
|
|
|
|
|
Services->Interface.RenderSculpture = true;
|
|
|
|
|
|
|
|
Services->PerformanceCountFrequency = PerformanceCountFrequency;
|
|
|
|
|
|
|
|
Services->Interface.ShowCameraMouse = false;
|
|
|
|
Services->Interface.ShowTrackedScopes = false;
|
|
|
|
Services->Interface.RenderSculpture = true;
|
|
|
|
Services->Interface.SendSACNData = false;
|
|
|
|
|
2019-11-02 20:17:23 +00:00
|
|
|
Services->ScopeHistogramUnsorted = PushArray(&Services->DebugStorage, debug_histogram_entry, SCOPE_HISTOGRAM_SIZE);
|
|
|
|
Services->ScopeHistogramSorted = PushArray(&Services->DebugStorage, debug_histogram_entry, SCOPE_HISTOGRAM_SIZE);
|
|
|
|
|
2019-07-19 20:56:21 +00:00
|
|
|
Services->ScopeHistogramUsed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal s32
|
|
|
|
DEBUGFindScopeHistogram (debug_services* Services, string Name)
|
|
|
|
{
|
|
|
|
s32 Result = -1;
|
|
|
|
for (s32 i = 0; i < SCOPE_HISTOGRAM_SIZE; i++)
|
|
|
|
{
|
2019-11-02 20:17:23 +00:00
|
|
|
if (StringsEqual(Services->ScopeHistogramUnsorted[i].ScopeName, Name))
|
2019-07-19 20:56:21 +00:00
|
|
|
{
|
|
|
|
Result = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal s32
|
|
|
|
DEBUGAddScopeHistogram (debug_services* Services, scope_time_record Record)
|
|
|
|
{
|
|
|
|
Assert(Services->ScopeHistogramUsed < SCOPE_HISTOGRAM_SIZE);
|
|
|
|
|
|
|
|
s32 Result = Services->ScopeHistogramUsed++;
|
|
|
|
|
2019-11-02 20:17:23 +00:00
|
|
|
debug_histogram_entry* Entry = Services->ScopeHistogramUnsorted + Result;
|
2019-07-19 20:56:21 +00:00
|
|
|
Entry->ScopeName = MakeString(Entry->ScopeName_, 256);
|
|
|
|
|
|
|
|
Entry->CurrentFrame = 0;
|
|
|
|
Entry->Average_Cycles = 0;
|
|
|
|
Entry->Average_CallCount = 0;
|
|
|
|
Entry->Total_Cycles = 0;
|
|
|
|
Entry->Total_CallCount = 0;
|
|
|
|
|
|
|
|
CopyStringTo(Record.ScopeName, &Entry->ScopeName);
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
DEBUGRecordScopeInHistogram (debug_services* Services, s32 Index, scope_time_record Record)
|
|
|
|
{
|
2019-11-02 20:17:23 +00:00
|
|
|
debug_histogram_entry* Entry = Services->ScopeHistogramUnsorted + Index;
|
2019-07-19 20:56:21 +00:00
|
|
|
s32 FrameIndex = Entry->CurrentFrame;
|
|
|
|
if (FrameIndex >= 0 && FrameIndex < HISTOGRAM_DEPTH)
|
|
|
|
{
|
|
|
|
Entry->PerFrame_Cycles[FrameIndex] += Record.Duration_Cycles;
|
|
|
|
Entry->PerFrame_CallCount[FrameIndex]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
DEBUGCacheScopeHistogramValues (debug_histogram_entry* Histogram)
|
|
|
|
{
|
|
|
|
Histogram->Total_Cycles = 0;
|
|
|
|
Histogram->Total_CallCount = 0;
|
|
|
|
|
|
|
|
// TODO(Peter): This doesn't account for the first frames when the histogram isn't full
|
|
|
|
for (s32 i = 0; i < HISTOGRAM_DEPTH; i++)
|
|
|
|
{
|
|
|
|
Histogram->Total_Cycles += Histogram->PerFrame_Cycles[i];
|
|
|
|
Histogram->Total_CallCount += Histogram->PerFrame_CallCount[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
Histogram->Average_Cycles = (Histogram->Total_Cycles / HISTOGRAM_DEPTH);
|
|
|
|
Histogram->Average_CallCount = (Histogram->Total_CallCount / HISTOGRAM_DEPTH);
|
|
|
|
}
|
|
|
|
|
2019-11-02 20:17:23 +00:00
|
|
|
internal void
|
|
|
|
DEBUGSortedHistogramInsert(debug_histogram_entry Source, debug_histogram_entry* DestList, s32 DestCount, s32 Max)
|
|
|
|
{
|
|
|
|
s32 CurrentFrame0 = Source.CurrentFrame;
|
|
|
|
s32 V0 = Source.Average_Cycles; //PerFrame_Cycles[CurrentFrame0];
|
|
|
|
if (DestCount > 0)
|
|
|
|
{
|
|
|
|
for (s32 i = DestCount - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
s32 CurrentFrame1 = DestList[i].CurrentFrame;
|
|
|
|
s32 V1 = DestList[i].Average_Cycles; //PerFrame_Cycles[CurrentFrame1];
|
|
|
|
if (V0 < V1)
|
|
|
|
{
|
|
|
|
DestList[i + 1] = Source;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DestList[i + 1] = DestList[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DestList[0] = Source;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
DEBUGSortHistogram(debug_histogram_entry* Source, debug_histogram_entry* Dest, s32 Count, s32 Max)
|
|
|
|
{
|
|
|
|
for (s32 i = 0; i < Count; i++)
|
|
|
|
{
|
|
|
|
DEBUGSortedHistogramInsert(Source[i], Dest, i, Max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-19 20:56:21 +00:00
|
|
|
internal void
|
|
|
|
DEBUGCollateScopeRecords (debug_services* Services)
|
|
|
|
{
|
|
|
|
for (s32 i = 0; i < Services->TrackedScopesCount; i++)
|
|
|
|
{
|
|
|
|
scope_time_record Record = Services->TrackedScopes[i];
|
|
|
|
s32 Index = DEBUGFindScopeHistogram(Services, Record.ScopeName);
|
|
|
|
if (Index < 0)
|
|
|
|
{
|
|
|
|
Index = DEBUGAddScopeHistogram(Services, Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUGRecordScopeInHistogram(Services, Index, Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (s32 h = 0; h < Services->ScopeHistogramUsed; h++)
|
|
|
|
{
|
2019-11-02 20:17:23 +00:00
|
|
|
DEBUGCacheScopeHistogramValues(Services->ScopeHistogramUnsorted + h);
|
2019-07-19 20:56:21 +00:00
|
|
|
}
|
2019-11-02 20:17:23 +00:00
|
|
|
|
|
|
|
DEBUGSortHistogram(Services->ScopeHistogramUnsorted,
|
|
|
|
Services->ScopeHistogramSorted,
|
|
|
|
Services->ScopeHistogramUsed,
|
|
|
|
SCOPE_HISTOGRAM_SIZE);
|
2019-07-19 20:56:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
EndDebugFrame (debug_services* Services)
|
|
|
|
{
|
|
|
|
DEBUGCollateScopeRecords(Services);
|
|
|
|
|
|
|
|
GSZeroMemory((u8*)Services->TrackedScopes, sizeof(scope_time_record) * Services->TrackedScopesMax);
|
|
|
|
Services->TrackedScopesCount = 0;
|
|
|
|
|
|
|
|
for (s32 i = 0; i < Services->ScopeHistogramUsed; i++)
|
|
|
|
{
|
2019-11-02 20:17:23 +00:00
|
|
|
s32 NewFrame = Services->ScopeHistogramUnsorted[i].CurrentFrame + 1;
|
2019-07-19 20:56:21 +00:00
|
|
|
if (NewFrame >= HISTOGRAM_DEPTH)
|
|
|
|
{
|
|
|
|
NewFrame = 0;
|
|
|
|
}
|
2019-11-02 20:17:23 +00:00
|
|
|
Services->ScopeHistogramUnsorted[i].CurrentFrame = NewFrame;
|
|
|
|
Services->ScopeHistogramUnsorted[i].PerFrame_Cycles[NewFrame] = 0;
|
|
|
|
Services->ScopeHistogramUnsorted[i].PerFrame_CallCount[NewFrame] = 0;
|
2019-07-19 20:56:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal scope_time_record*
|
|
|
|
PushScopeRecord(string ScopeName, debug_services* Services)
|
|
|
|
{
|
|
|
|
scope_time_record* Result = 0;
|
|
|
|
|
|
|
|
s32 OnePastIndex = InterlockedIncrement((long*)&Services->TrackedScopesCount);
|
|
|
|
Assert(OnePastIndex <= Services->TrackedScopesMax);
|
|
|
|
Result = Services->TrackedScopes + OnePastIndex - 1;
|
|
|
|
|
|
|
|
Result->ScopeName = MakeString(Result->ScopeName_, SCOPE_NAME_LENGTH);
|
|
|
|
CopyStringTo(ScopeName, &Result->ScopeName);
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
LogScopeTime (debug_services* Services, string ScopeName, u64 CyclesElapsed)
|
|
|
|
{
|
|
|
|
scope_time_record* Record = PushScopeRecord(ScopeName, Services);
|
|
|
|
Record->Duration_Cycles = CyclesElapsed;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal r32 DEBUGGetSecondsElapsed (s64 Start, s64 End, r32 PerformanceCountFrequency)
|
|
|
|
{
|
|
|
|
r32 Result = ((r32)(End - Start) / (r32)PerformanceCountFrequency);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
#define DEBUG_TRACK_FUNCTION scope_tracker ScopeTracker (__FUNCTION__, GlobalDebugServices)
|
|
|
|
#define DEBUG_TRACK_SCOPE(name) scope_tracker ScopeTracker_##name (#name, GlobalDebugServices)
|
|
|
|
#else
|
|
|
|
#define DEBUG_TRACK_FUNCTION
|
|
|
|
#define DEBUG_TRACK_SCOPE(name)
|
|
|
|
#endif
|
|
|
|
struct scope_tracker
|
|
|
|
{
|
|
|
|
s64 ScopeStart;
|
|
|
|
|
|
|
|
char ScopeName_[SCOPE_NAME_LENGTH];
|
|
|
|
string ScopeName;
|
|
|
|
|
|
|
|
debug_services* DebugServices;
|
|
|
|
|
|
|
|
scope_tracker(char* ScopeName, debug_services* DebugServices)
|
|
|
|
{
|
|
|
|
this->ScopeName = MakeString(this->ScopeName_, SCOPE_NAME_LENGTH);
|
|
|
|
CopyCharArrayToString(ScopeName, &this->ScopeName);
|
|
|
|
this->ScopeStart = DebugServices->GetWallClock();
|
|
|
|
this->DebugServices = DebugServices;
|
|
|
|
}
|
|
|
|
|
|
|
|
~scope_tracker()
|
|
|
|
{
|
|
|
|
s64 ScopeEnd = DebugServices->GetWallClock();
|
|
|
|
u32 CyclesElapsed = (u32)(ScopeEnd - this->ScopeStart);
|
|
|
|
#if 0
|
|
|
|
r32 SecondsElapsed = DEBUGGetSecondsElapsed(this->ScopeStart, ScopeEnd, DebugServices->PerformanceCountFrequency);
|
|
|
|
#endif
|
|
|
|
LogScopeTime(DebugServices, ScopeName, CyclesElapsed);
|
|
|
|
}
|
|
|
|
};
|