#c #linux #time #system-calls #rdtsc
#c #linux #время #системные вызовы #rdtsc
Вопрос:
Я реализовал быструю функцию, которая возвращает время (используя rdtsc), давайте назовем ее fast_time()
. У меня есть для справки исходная функция, которая использует системный вызов, давайте назовем ее system_time()
. Моя программа использует fast_time()
, но в отдельном потоке я постоянно запускаю цикл while, чтобы проверить, превышает ли разница между временем, возвращаемым моей функцией, и исходной функцией заданный порог. Что-то вроде
while (true)
{
if (abs((fast_time() - system_time()).microseconds()) > MICROSECONDS_THRESHOLD)
{
report error
}
}
Обычно я не вижу ошибок, но иногда я их получаю, и я хотел бы лучше разобраться в этой проблеме. Мое первое подозрение заключается в том, что вызов system_time()
не происходит сразу после fast_time()
возврата. Как я могу заставить программу выполняться fast_time() - system_time()
по возможности «атомарно»?
Комментарии:
1. Привет, прежде чем я отвечу, ваш код привязан к одному процессору? Ничего страшного, если вы не знаете, что это значит, просто скажите мне, с чего начать объяснение 🙂
2. Если вы не работаете на ядре реального времени (а Linux таковым не является), вы не получаете никаких гарантий того, как часто планируется запуск вашего программного обеспечения, и вы не можете знать, будут ли потоки выполняться на одном ядре по очереди или на разных ядрах. Обычно это полностью зависит от операционной системы.
3. @LtWorf на самом деле в Linux есть планировщик реального времени, если вы решите его использовать, и в его конкретном случае на многоядерном процессоре он может привязать свой поток к ЯДРУ и получить результаты, которые он ищет.
4. Я привязываю поток, который к одному ядру с помощью
sched_setaffinity
, и да, я знаю, что я не получаю гарантий для планирования (я не использую ядро реального времени), мой вопрос в том, что это лучшее, что я могу сделать, чтобы исправить это?5. Чего вы хотите достичь с помощью теста? Является ли это тестом для
fast_time
реализации, которую вы сравниваете с тойsystem_time
, которой вы доверяете?
Ответ №1:
rdtsc по своей сути является ненадежным способом измерения в реальном времени по нескольким причинам:
1) каждый поток HW будет возвращать разные значения, поэтому, если ваш поток не привязан к одному потоку HW, вы получите разные значения. Таким образом, время может неожиданно прыгать вперед и назад в зависимости от того, как ОС планирует поток
И что еще более важно:
2) Регулирование процессора может привести к неожиданному изменению частоты процессора. Поскольку rdtsc измеряет выполненные циклы, а не время, вы не можете надежно получить прошедшее время, разделив количество циклов на частоту процессора (между двумя вызовами rdtsc частота могла измениться случайным образом)
Также в вашем конкретном тестовом примере ОС может запланировать поток для выхода между вызовами fast_time() и system_time(), что вызывает расхождение между измеренными временами, даже если fast_time () вернет правильные значения. Итак, отвечая на ваш вопрос, я не думаю, что есть какой-либо способ предотвратить это.
Комментарии:
1. Вы правы! Если проблема не в планировании, то мое следующее предположение заключается в том, что частота процессора меняется (разгоняется или не разгоняется). В любом случае я не думаю, что готов так легко отказаться от rdtsc, поскольку он оказался в 4 раза быстрее системного вызова. Итак, как вы упомянули, я подозреваю, что ОС выдает мой поток именно тогда, когда я не хочу, чтобы он планировал мой поток. Итак, я все еще ищу какой-нибудь способ предотвратить это
2. Может быть, вы могли бы поместить system_time () между двумя вызовами fast_time() и отклонить случай, если время между вызовами fast_time() превышает некоторый порог? Мне также любопытно, в каком конкретном приложении разница во времени вызова в 4 раза имеет значение?
3. Отвечая на ваш второй вопрос, приложение относится к области алгоритмической торговли, где важна каждая микросекунда.
4. Я не знаю, какую платформу вы используете, но я профилировал QueryPerformanceCounter() против __rdtsc() в win32, и для 1 миллиарда вызовов я получил время 10,63 с против 8,11 с соответственно. Так что, по крайней мере, в этом случае не стоит лишних хлопот использовать rdtsc.