// #Timing API: #define System_Timed_Block_Print(name) \ system_timed_block_print Concat(_sys_timed_block_print_guard, __LINE__)(name) #define Timed_Block_Print(name) \ timed_block_print Concat(_timed_block_print_guard, __LINE__)(name) // This is for timing stuff that happens where context is not available. // memory will leak from this operation. #MemoryLeak #NoContext #define Timed_Block_Print_No_Context(name) \ timed_block_print_no_context Concat(_timed_block_print_guard, __LINE__)(name) force_inline u64 rdtsc(); #if OS_WINDOWS #include #pragma intrinsic(__rdtsc) force_inline u64 rdtsc() { return __rdtsc(); } #endif global u32 g_cpu_base_frequency_megahertz; void set_cpu_base_frequency (u32 frequency_megahertz) { g_cpu_base_frequency_megahertz = frequency_megahertz; } string format_time_seconds_no_context (f64 time) { // #MemoryLeak #NoContext if (time < 1.0e-6) { return format_string_no_context("%1.2f ns", time * 1.0e9); } if (time < 1.0e-3) { return format_string_no_context("%1.3f us", time * 1.0e6); } if (time < 1) { return format_string_no_context("%1.3f ms", time * 1.0e3); } return format_string_no_context("%1.3f s", time); } string format_cycles_no_context (u64 ticks) { // #MemoryLeak #NoContext string units[5] = { "cycles", "K cycles", "M cycles", "B cycles", "T cycles" }; f64 count_f64 = (f64)ticks; s64 unit_index = 0; while (count_f64 >= 1000 && unit_index < 4) { // 4 is from (units.count-1) count_f64 /= 1000.0; unit_index += 1; } return format_string_no_context("%1.2f %s", count_f64, units[unit_index].data); } string format_time_seconds (f64 time) { if (time < 1.0e-6) { return format_string("%1.2f ns", time * 1.0e9); } if (time < 1.0e-3) { return format_string("%1.3f us", time * 1.0e6); } if (time < 1) { return format_string("%1.3f ms", time * 1.0e3); } return format_string("%1.3f s", time); } string format_cycles (u64 ticks) { string units[5] = { "cycles", "K cycles", "M cycles", "B cycles", "T cycles" }; f64 count_f64 = (f64)ticks; s64 unit_index = 0; while (count_f64 >= 1000 && unit_index < 4) { // 4 is from (units.count-1) count_f64 /= 1000.0; unit_index += 1; } return format_string("%1.2f %s", count_f64, units[unit_index].data); } string format_bytes (s64 bytes) { string units[6] = { "B", "KB", "MB", "GB", "TB", "PB" }; f64 count_f64 = (f64)bytes; s32 unit_index = 0; while (count_f64 >= 1024 && unit_index < (5)) { count_f64 /= 1024.0; unit_index += 1; } return format_string("%1.3f %s", count_f64, units[unit_index].data); } struct timed_block_print { string block_name; u64 start_tick; timed_block_print(string _block_name) { Assert(g_cpu_base_frequency_megahertz != 0); Assert(thread_local_context != nullptr); // we need temp allocator initialized! block_name = _block_name; start_tick = rdtsc(); } ~timed_block_print() { u64 end_tick = rdtsc(); u64 tick_difference = end_tick - start_tick; f64 ticks_f64 = (f64)tick_difference; f64 elapsed_time_seconds = ticks_f64 / (f64)((s64)g_cpu_base_frequency_megahertz * 1000000); push_allocator(temp()); log("[Timed_Block %s]: %s (%s)", block_name.data, format_time_seconds(elapsed_time_seconds).data, format_cycles(tick_difference).data); } }; struct timed_block_print_no_context { string block_name; u64 start_tick; timed_block_print_no_context(string _block_name) { Assert(g_cpu_base_frequency_megahertz != 0); block_name = _block_name; start_tick = rdtsc(); } ~timed_block_print_no_context() { u64 end_tick = rdtsc(); u64 tick_difference = end_tick - start_tick; f64 ticks_f64 = (f64)tick_difference; f64 elapsed_time_seconds = ticks_f64 / (f64)((s64)g_cpu_base_frequency_megahertz * 1000000); printf("[Timed_Block(No Context) %s]: %s (%s)\n", block_name.data, format_time_seconds_no_context(elapsed_time_seconds).data, format_cycles_no_context(tick_difference).data); } }; struct system_timed_block_print { string block_name; f64 start_time; system_timed_block_print(string _block_name) { block_name = _block_name; start_time = GetUnixTimestamp(); } ~system_timed_block_print() { f64 end_time = GetUnixTimestamp(); f64 elapsed_time_seconds = end_time - start_time; push_allocator(temp()); log("[Timed_Block %s]: %s", block_name.data, format_time_seconds(elapsed_time_seconds).data); } };