PerformanceAwareProgramming/part2/listing_0074_platform_metrics.cpp

99 lines
2.4 KiB
C++

/* ========================================================================
(C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Please see https://computerenhance.com for more information
======================================================================== */
/* ========================================================================
LISTING 74
======================================================================== */
#if _WIN32
#include <intrin.h>
#include <windows.h>
static u64 GetOSTimerFreq(void)
{
LARGE_INTEGER Freq;
QueryPerformanceFrequency(&Freq);
return Freq.QuadPart;
}
static u64 ReadOSTimer(void)
{
LARGE_INTEGER Value;
QueryPerformanceCounter(&Value);
return Value.QuadPart;
}
#else
#include <x86intrin.h>
#include <sys/time.h>
static u64 GetOSTimerFreq(void)
{
return 1000000;
}
static u64 ReadOSTimer(void)
{
// NOTE(casey): The "struct" keyword is not necessary here when compiling in C++,
// but just in case anyone is using this file from C, I include it.
struct timeval Value;
gettimeofday(&Value, 0);
u64 Result = GetOSTimerFreq()*(u64)Value.tv_sec + (u64)Value.tv_usec;
return Result;
}
#endif
/* NOTE(casey): This does not need to be "inline", it could just be "static"
because compilers will inline it anyway. But compilers will warn about
static functions that aren't used. So "inline" is just the simplest way
to tell them to stop complaining about that. */
inline u64 ReadCPUTimer(void)
{
// NOTE(casey): If you were on ARM, you would need to replace __rdtsc
// with one of their performance counter read instructions, depending
// on which ones are available on your platform.
return __rdtsc();
}
static u64 EstimateCPUTimerFreq(void)
{
u64 MillisecondsToWait = 100;
u64 OSFreq = GetOSTimerFreq();
u64 CPUStart = ReadCPUTimer();
u64 OSStart = ReadOSTimer();
u64 OSEnd = 0;
u64 OSElapsed = 0;
u64 OSWaitTime = OSFreq * MillisecondsToWait / 1000;
while(OSElapsed < OSWaitTime)
{
OSEnd = ReadOSTimer();
OSElapsed = OSEnd - OSStart;
}
u64 CPUEnd = ReadCPUTimer();
u64 CPUElapsed = CPUEnd - CPUStart;
u64 CPUFreq = 0;
if(OSElapsed)
{
CPUFreq = OSFreq * CPUElapsed / OSElapsed;
}
return CPUFreq;
}