gencpp/project/dependencies/timing.cpp

170 lines
4.1 KiB
C++
Raw Normal View History

#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "filesystem.cpp"
#endif
#pragma region Timing
GEN_API_C_BEGIN
2023-07-24 15:35:16 -07:00
#ifdef GEN_BENCHMARK
#if defined( GEN_COMPILER_MSVC ) && ! defined( __clang__ )
u64 read_cpu_time_stamp_counter( void )
{
return __rdtsc();
}
#elif defined( __i386__ )
u64 read_cpu_time_stamp_counter( void )
{
u64 x;
__asm__ volatile( ".byte 0x0f, 0x31" : "=A"( x ) );
return x;
}
#elif defined( __x86_64__ )
u64 read_cpu_time_stamp_counter( void )
{
u32 hi, lo;
__asm__ __volatile__( "rdtsc" : "=a"( lo ), "=d"( hi ) );
return scast( u64, lo ) | ( scast( u64, hi ) << 32 );
2023-07-24 15:35:16 -07:00
}
#elif defined( __powerpc__ )
u64 read_cpu_time_stamp_counter( void )
{
u64 result = 0;
u32 upper, lower, tmp;
__asm__ volatile(
"0: \n"
"\tmftbu %0 \n"
"\tmftb %1 \n"
"\tmftbu %2 \n"
"\tcmpw %2,%0 \n"
"\tbne 0b \n"
: "=r"( upper ), "=r"( lower ), "=r"( tmp )
);
result = upper;
result = result << 32;
result = result | lower;
return result;
}
#elif defined( GEN_SYSTEM_EMSCRIPTEN )
u64 read_cpu_time_stamp_counter( void )
{
return ( u64 )( emscripten_get_now() * 1e+6 );
}
#elif defined( GEN_CPU_ARM ) && ! defined( GEN_COMPILER_TINYC )
u64 read_cpu_time_stamp_counter( void )
{
# if defined( __aarch64__ )
int64_t r = 0;
asm volatile( "mrs %0, cntvct_el0" : "=r"( r ) );
# elif ( __ARM_ARCH >= 6 )
uint32_t r = 0;
uint32_t pmccntr;
uint32_t pmuseren;
uint32_t pmcntenset;
// Read the user mode perf monitor counter access permissions.
asm volatile( "mrc p15, 0, %0, c9, c14, 0" : "=r"( pmuseren ) );
if ( pmuseren & 1 )
{ // Allows reading perfmon counters for user mode code.
asm volatile( "mrc p15, 0, %0, c9, c12, 1" : "=r"( pmcntenset ) );
if ( pmcntenset & 0x80000000ul )
{ // Is it counting?
asm volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"( pmccntr ) );
// The counter is set up to count every 64th cycle
return ( ( int64_t )pmccntr ) * 64; // Should optimize to << 6
}
}
# else
# error "No suitable method for read_cpu_time_stamp_counter for this cpu type"
# endif
return r;
}
#else
u64 read_cpu_time_stamp_counter( void )
{
GEN_PANIC( "read_cpu_time_stamp_counter is not supported on this particular setup" );
return -0;
}
#endif
#if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN )
u64 time_rel_ms( void )
{
local_persist LARGE_INTEGER win32_perf_count_freq = {};
u64 result;
LARGE_INTEGER counter;
local_persist LARGE_INTEGER win32_perf_counter = {};
if ( ! win32_perf_count_freq.QuadPart )
{
QueryPerformanceFrequency( &win32_perf_count_freq );
GEN_ASSERT( win32_perf_count_freq.QuadPart != 0 );
QueryPerformanceCounter( &win32_perf_counter );
}
QueryPerformanceCounter( &counter );
result = ( counter.QuadPart - win32_perf_counter.QuadPart ) * 1000 / ( win32_perf_count_freq.QuadPart );
return result;
}
#else
# if defined( GEN_SYSTEM_LINUX ) || defined( GEN_SYSTEM_FREEBSD ) || defined( GEN_SYSTEM_OPENBSD ) || defined( GEN_SYSTEM_EMSCRIPTEN )
u64 _unix_gettime( void )
{
struct timespec t;
u64 result;
clock_gettime( 1 /*CLOCK_MONOTONIC*/, &t );
result = 1000 * t.tv_sec + 1.0e-6 * t.tv_nsec;
return result;
}
# endif
u64 time_rel_ms( void )
{
# if defined( GEN_SYSTEM_OSX )
u64 result;
local_persist u64 timebase = 0;
local_persist u64 timestart = 0;
if ( ! timestart )
{
mach_timebase_info_data_t tb = { 0 };
mach_timebase_info( &tb );
timebase = tb.numer;
timebase /= tb.denom;
timestart = mach_absolute_time();
}
// NOTE: mach_absolute_time() returns things in nanoseconds
result = 1.0e-6 * ( mach_absolute_time() - timestart ) * timebase;
return result;
# else
local_persist u64 unix_timestart = 0.0;
if ( ! unix_timestart )
{
unix_timestart = _unix_gettime();
}
u64 now = _unix_gettime();
return ( now - unix_timestart );
# endif
}
#endif
f64 time_rel( void )
{
return ( f64 )( time_rel_ms() * 1e-3 );
}
#endif
GEN_API_C_END
#pragma endregion Timing