Проблема измерения времени в Linux! std::chrono, QueryPerformanceCounter, clock_gettime

Я использую clock_gettime() в Linux и QueryPerformanceCounter() в Windows для измерения времени. При измерении времени я столкнулся с интересным случаем.

Во-первых, я вычисляю DeltaTime в бесконечном цикле while. Этот цикл вызывает некоторые функции обновления. Для расчета DeltaTime программа ожидает 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;

}

Обычный

Проблема


person tgrlsrt    schedule 02.09.2019    source источник
comment
Если вы запускаете свой исполняемый файл Linux под strace, показывает ли он множество системных вызовов?   -  person bobah    schedule 02.09.2019
comment
Вместо (float)MICROSECONDS рассмотрите возможность определения MICROSECONDS как float. например: constexpr float MICROSECONDS = 1000*1000;   -  person user4581301    schedule 02.09.2019
comment
int64_t y = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count(); Лично я бы использовал auto вместо y. И (float)MICROSECONDS - э-э-э, пожалуйста, не используйте приведения в стиле C.   -  person Jesper Juhl    schedule 02.09.2019
comment
@bobah Я никогда не использовал strace, но попробую.   -  person tgrlsrt    schedule 02.09.2019
comment
Несвязанные: эти изображения могут быть вставлены в текст. По возможности отдавайте предпочтение тексту, так как изображения непрозрачны для слишком многих людей.   -  person user4581301    schedule 02.09.2019
comment
@kmdreko Извините, это должно быть 0,040f. я отредактировал.   -  person tgrlsrt    schedule 02.09.2019


Ответы (1)


Возможные причины:

  1. Ваш clock_gettime не использует VDSO, а вместо этого является системным вызовом — будет виден, если он запущен под strace, его можно настроить в современных версиях ядра.
  2. Ваш поток вытесняется (вынимается из процессора планировщиком). Чтобы провести чистый эксперимент, запустите приложение с приоритетом в реальном времени и прикрепите его к определенному ядру ЦП.

Кроме того, я бы отключил масштабирование частоты процессора при экспериментах.

person bobah    schedule 02.09.2019
comment
Что вы подразумеваете под приоритетом реального времени. Это приоритет потока? Я никогда не имел дело с линуксом раньше. Почему работающая программа должна потреблять ресурсы ЦП планировщиком. Я не мог понять. - person tgrlsrt; 02.09.2019
comment
Спасибо, посмотрю. - person tgrlsrt; 02.09.2019
comment
@bobah Я попробовал это с помощью strace -p 9441 -e 'trace=!clock_gettime' -o /home/tgrl_monster_pc/strace.log Есть только функция записи. write(1, DeltaTime: 0.040340 - 1567454514..., 36) = 36. Значит, это должно быть связано с планированием. - person tgrlsrt; 02.09.2019
comment
clock_gettime (CLOCK_REALTIME, {1567457330, 194450552}) = 0 - person tgrlsrt; 02.09.2019
comment
@tgrlsrt - вы можете указать strace также регистрировать, сколько времени занял конкретный системный вызов. Если вы видите clock_gettime в выводе strace, это означает, что получение временных меток в вашей системе может быть довольно дорогим, обычно вы можете изменить конфигурацию ОС (точные инструкции зависят от поставщика), чтобы использовать быструю реализацию на основе VDSO (см. это, например). - person bobah; 03.09.2019
comment
@bobah Я прикрепил его к конкретному ядру процессора. Больше никаких проблем. Я посмотрю на ВДСО. Спасибо. Есть ли недостатки при включении VDSO? - person tgrlsrt; 03.09.2019
comment
@tgrlsrt - это компромисс между точностью и накладными расходами (было несколько лет назад, когда я в последний раз работал с ним) - person bobah; 03.09.2019