1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | extern u32 GlobalDebugCounter; #define GET_COUNTER__(Counter, FileNameInit, LineNumberInit, BlockNameInit, ...) \ static u32 Init_##Counter = 0; \ static u32 Counter = 0;\ if (Init_##Counter != 2) {\ if (AtomicCompareExchangeUInt32(&Init_##Counter, 1, 0) == 0) {\ Counter = AtomicAddU32(&GlobalDebugCounter, 1);\ \ CompletePreviousWritesBeforeFutureWrites;\ Init_##Counter = 2;\ Assert(Counter < MAX_DEBUG_RECORD_COUNT); \ debug_record *Record = GlobalDebugTable->Records[TRANSLATION_UNIT_INDEX] + Counter; \ Record->FileName = FileNameInit; \ Record->LineNumber = LineNumberInit; \ Record->BlockName = BlockNameInit; \ } else {\ volatile u32* test = &Init_##Counter;\ while (*test != 2);\ }\ } #define GET_COUNTER_(Name, FileNameInit, LineNumberInit, BlockNameInit, ...) GET_COUNTER__(Name, FileNameInit, LineNumberInit, BlockNameInit) #define GET_COUNTER(Name, FileNameInit, LineNumberInit, BlockNameInit, ...) GET_COUNTER_(Name, FileNameInit, LineNumberInit, BlockNameInit) #define FRAME_MARKER() \ { \ GET_COUNTER(Counter, __FILE__, __LINE__, "Frame Marker"); \ RecordDebugEvent(Counter, DebugEvent_FrameMarker); \ } #define TIMED_BLOCK__(BlockName, Number, ...) \ GET_COUNTER(Counter_##Number, __FILE__, __LINE__, BlockName, ## __VA_ARGS__); \ timed_block TimedBlock_##Number(Counter_##Number) #define TIMED_BLOCK_(BlockName, Number, ...) TIMED_BLOCK__(BlockName, Number, ## __VA_ARGS__) #define TIMED_BLOCK(BlockName, ...) TIMED_BLOCK_(#BlockName, __COUNTER__, ## __VA_ARGS__) #define TIMED_FUNCTION(...) TIMED_BLOCK_(__FUNCTION__, __COUNTER__, ## __VA_ARGS__) #define BEGIN_BLOCK_(Counter) RecordDebugEvent(Counter, DebugEvent_BeginBlock); #define END_BLOCK_(Counter) RecordDebugEvent(Counter, DebugEvent_EndBlock); #define BEGIN_BLOCK(Name) \ GET_COUNTER(Counter_##Name, __FILE__, __LINE__, #Name); \ BEGIN_BLOCK_(Counter_##Name); #define END_BLOCK(Name) \ END_BLOCK_(Counter_##Name); struct timed_block { int Counter; timed_block(int CounterInit) { // TODO(casey): Record the hit count value here? Counter = CounterInit; BEGIN_BLOCK_(Counter); } ~timed_block() { END_BLOCK_(Counter); } }; |
You also need AtomicAddU32:
1 2 3 4 5 6 7 | inline u32 AtomicAddU32(u32 volatile *Value, u32 Addend) { // NOTE(casey): Returns the original value _prior_ to adding u32 Result = _InterlockedExchangeAdd((long volatile *)Value, Addend); return(Result); } |
In build.bat there should be only 2 distinct TRANSLATION_UNIT_INDEX with this method, as only the executable and the dll will have separate GlobalDebugCounter variables, which will fix the problem with the TRANSLATION_UNIT being different in the inline/macro RecordDebugEvent
Each of these compiled blocks will then need some additional info.
win32_handmade.cpp and for instance handmade_debug.cpp now need an extra line:
1 | u32 GlobalDebugCounter = 0; |
Each compiled block also needs to set the GlobalDebugTable->RecordCount to GlobalDebugCounter. But this is currenty not really used as far as I know.
1 | GlobalDebugTable->RecordCount[TRANSLATION_UNIT_INDEX] = GlobalDebugCounter; |
I also moved the initialisation of the DebugRecord to the GET_COUNTER part that gets the next available counter, so this is also only done once. Which could eliminate some overhead (though small).
In the end I think this only adds one conditional jump to the normal process of gathering the profile info, which should not be that bad. It does have a spinwait to keep other threads that might contest the counter initialisation waiting for the correct value. This could even be removed to let each contesting thread increase the count, which would result in more debugrecords being used. But each counter would only have a max duplicate count of the thread count, so it is limited and should not corrupt the results. But the spinwait is only for the first time inialising and should complete quickly.
Regards,
Mox
BTW, I still use __COUNTER__ in this code, but only to create unique identifiers for the counter variables, not for their values.