153 lines
4.8 KiB
C
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);
|
|
}
|
|
};
|