Linux测量时间问题! std::chrono、查询性能计数器、clock_gettime
Linux measuring time problem! std::chrono, QueryPerformanceCounter, clock_gettime
我在 Linux 中使用 clock_gettime() 并在 Windows 中使用 QueryPerformanceCounter() 来测量时间。在测量时间的时候遇到了一个有趣的案例
首先,我在无限循环中计算 DeltaTime。这个循环调用一些更新函数。为了计算 DeltaTime,程序在 Update 函数中等待 40 毫秒,因为更新函数还为空。
然后,在编译为 Win64-Debug 的程序中,我测量了 DeltaTime。大约为 0.040f。只要程序是 运行,这种情况就会继续(Win64-Release 也可以这样工作)。它运行正确。
但是在编译为Linux64-Debug或Linux64-Release的程序中,出现了问题
程序启动时运行。一切正常。 DeltaTime 约为 0.040f。但过了一会儿,deltatime 计算为 0.12XXf 或 0.132XX,紧随其后的是 0.040f。等等。
我以为我正确使用了 QueryPerformanceCounter 而错误地使用了 clock_gettime()。然后我决定用标准库std::chrono::high_resolution_clock试一试,结果是一样的。没有变化。
#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
可能的原因:
- 您的 clock_gettime 没有使用 VDSO,而是一个系统调用 - 如果
strace
下的 运行 将可见,可以在现代内核版本上配置。
- 您的线程被抢占(被调度程序从 CPU 中取出)。 运行 一个干净的实验 运行 你的应用程序具有实时优先级并固定到特定的 CPU 核心。
此外,我会在实验时禁用 CPU 频率缩放。
我在 Linux 中使用 clock_gettime() 并在 Windows 中使用 QueryPerformanceCounter() 来测量时间。在测量时间的时候遇到了一个有趣的案例
首先,我在无限循环中计算 DeltaTime。这个循环调用一些更新函数。为了计算 DeltaTime,程序在 Update 函数中等待 40 毫秒,因为更新函数还为空。
然后,在编译为 Win64-Debug 的程序中,我测量了 DeltaTime。大约为 0.040f。只要程序是 运行,这种情况就会继续(Win64-Release 也可以这样工作)。它运行正确。
但是在编译为Linux64-Debug或Linux64-Release的程序中,出现了问题
程序启动时运行。一切正常。 DeltaTime 约为 0.040f。但过了一会儿,deltatime 计算为 0.12XXf 或 0.132XX,紧随其后的是 0.040f。等等。
我以为我正确使用了 QueryPerformanceCounter 而错误地使用了 clock_gettime()。然后我决定用标准库std::chrono::high_resolution_clock试一试,结果是一样的。没有变化。
#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
可能的原因:
- 您的 clock_gettime 没有使用 VDSO,而是一个系统调用 - 如果
strace
下的 运行 将可见,可以在现代内核版本上配置。 - 您的线程被抢占(被调度程序从 CPU 中取出)。 运行 一个干净的实验 运行 你的应用程序具有实时优先级并固定到特定的 CPU 核心。
此外,我会在实验时禁用 CPU 频率缩放。