Musa-Cpp-Lib-V2/lib/Base/Timing.h

153 lines
4.8 KiB
C

// #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 <intrin.h>
#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, s32 trailing_width = 3) {
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;
}
switch (trailing_width) {
case 0: return format_string("%.0f %s", count_f64, units[unit_index].data);
case 1: return format_string("%.1f %s", count_f64, units[unit_index].data);
case 2: return format_string("%.2f %s", count_f64, units[unit_index].data);
case 3: return format_string("%.3f %s", count_f64, units[unit_index].data);
default: break;
}
Assert(trailing_width >= 0 && trailing_width <= 3);
return "";
}
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);
}
};