Search code examples
c++linuxc++11time-measurement

Linux measuring time problem! std::chrono, QueryPerformanceCounter, clock_gettime


I use clock_gettime() in Linux and QueryPerformanceCounter() in Windows to measure time. When measuring time, I encountered an interesting case.

Firstly, I'm calculating DeltaTime in infinite while loop. This loop calls some update functions. To calculating DeltaTime, the program's waiting in 40 milliseconds in an Update function because update functions is empty yet.

Then, in the program compiled as Win64-Debug i measure DeltaTime. It's approximately 0.040f. And this continues as long as the program is running (Win64-Release works like that too). It runs correctly.

But in the program compiled as Linux64-Debug or Linux64-Release, there is a problem.

When the program starts running. Everything is normal. DeltaTime is approximately 0.040f. But after a while, deltatime is calculated 0.12XXf or 0.132XX, immediately after it's 0.040f. And so on.

I thought I was using QueryPerformanceCounter correctly and using clock_gettime() incorrectly. Then I decided to try it with the standard library std::chrono::high_resolution_clock, but it's the same. No change.

#define MICROSECONDS (1000*1000)

auto prev_time = std::chrono::high_resolution_clock::now();
decltype(prev_time) current_time;

while(1)
{
current_time = std::chrono::high_resolution_clock::now();

int64_t deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(current_time - previous_time).count();

printf("DeltaTime: %f", deltaTime/(float)MICROSECONDS);

NetworkManager::instance().Update();

prev_time = current_time;

}

void NetworkManager::Update()
{
auto start = std::chrono::high_resolution_clock::now();
decltype(start) end;

while(1)
{
end = std::chrono::high_resolution_clock::now();

int64_t y = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count();

if(y/(float)MICROSECONDS >= 0.040f)
break;

}

return;

}

Normal

Problem


Solution

  • Possible causes:

    1. Your clock_gettime is not using VDSO and is a system call instead - will be visible if run under strace, can be configured on modern kernel versions.
    2. Your thread gets preempted (taken out of CPU by the scheduler). To run a clean experiment run your app with real time priority and pinned to a specific CPU core.

    Also, I would disable CPU frequency scaling when experimenting.