#c #performance #time
Вопрос:
Я хотел бы приостановить время выполнения в c , и вот код, который я получил:
while (_run)
{
//pause code
std::this_thread::sleep_for(std::chrono::nanoseconds(_interval_ns));
//doing stuff
_counter ;
(*_mainSrcTick)(GetDeltaTime(), GetName());
for (auto obj : _physicsList)
{
PyObject_CallMethod(obj, "PhysicsTick", "(d)", GetDeltaTime());
}
//used to mesure time
LastTick = std::chrono::high_resolution_clock::now();
}
На всякий случай вот моя функция дельта-времени, которая показывает, сколько тысяч моих интервалов прошло с момента моего последнего тика:
double difference = std::chrono::duration<double,std::nano>(std::chrono::high_resolution_clock::now() - LastTick).count();
double result = difference/_interval_ns ;
return resu<
Проблема, с которой я сталкиваюсь, заключается в том, что, по-видимому, без паузы мой код может выполняться за пару секунд, а при небольшой паузе даже это занимает миллисекунды. И так далее, я хочу сделать паузу, которая не так сильно нарушает мою программу.
Прежде чем вы зададитесь вопросом, я знаю, как использовать «использование пространства имен», и этот проект работает на x64 (хотя я бы не возражал, если бы он также мог быть запущен на x86), связывает python с c и многопоточен, хотя только на стороне python. Поэтому я предполагаю, что мне нужен более быстрый способ приостановки или, по крайней мере, время, чтобы он мог приостановиться с помощью цикла while. Мне не нужны НИКАКИЕ сторонние зависимости. Я использую VS 2019.
Цель состоит в том, чтобы делать что-то с фиксированной частотой каждого _interval_ns. GetDeltaTime-это то, что я могу указать любые неточности в dostuff, но было бы лучше, если бы частота была точной, а не время дельты. Я ищу микро-секундную точность, и было бы неплохо использовать нано.
Комментарии:
1. В чем заключается ценность
_interval_ns
?2. Зависит, но обычно 1 000 000
3. Использовать felixcloutier.com/x86/umwait если ваш процессор поддерживает это
4. Какова предполагаемая цель задержки по времени? Пример кода заставляет меня подозревать, что вы хотите
next_time = get_monotomic_counter() my_delay; while(true) { do_stuff(); delay_until_monotomic_counter(next_time); next_time = my_delay; }
, чтобы чтоdo_stuff()
-то происходило с фиксированной частотой (например, 60 раз в секунду), даже еслиdo_stuff()
требуется неизвестное/переменное количество времени.5. Да, мне нужно, чтобы «что-то делать» происходило с фиксированной частотой, и я хочу каким-то образом контролировать частоту. Это :
next_time = get_monotomic_counter() my_delay; while(true) { do_stuff(); delay_until_monotomic_counter(next_time); next_time = my_delay; }
было бы здорово реализовать некоторые способы, ноthread::sleep_until
это слишком медленно.
Ответ №1:
Когда вы просите свой поток перейти в спящий режим, операционная система не планирует его выполнение, и его переназначение занимает некоторое время. Если вы хотите сделать паузу на очень небольшое количество времени, используйте _mm_pause()
. Возможно, вы захотите сделать это фиксированное количество раз, основываясь на ваших собственных измерениях того, сколько времени это занимает в вашей системе. Intel говорит, что на Skylake требуется 140 циклов (на старых процессорах это заняло гораздо меньше времени): https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_pauseamp;expand=5146
Если количество времени, которое вы хотите проспать, невелико, но вас волнует, сколько прошло фактического времени, вы можете проверить время в цикле и позвонить _mm_pause()
один раз за цикл. Около 70 нс для clock_gettime()
плюс 40 нс для _mm_pause()
должно дать вам разрешение где-то около 120 нс на Skylake.
В любом случае вы не будете явно освобождать ядро процессора для использования другими процессами, и ОС может отменить расписание вашего потока, если на том же ядре ожидают запуска другие потоки. Поэтому вам нужно будет настроить сходство с процессором таким образом, чтобы ничто другое не могло работать на том же ядре. Для получения более подробной информации см. https://www.suse.com/support/kb/doc/?id=000017747
Комментарии:
1. Не используйте
_mm_pause()
— это полезно только для предотвращения нежелательного спекулятивного выполнения в узких циклах опроса (поэтому цикл может завершаться быстрее при изменении опрашиваемых данных, и поэтому другой логический процессор в ядре может работать быстрее) и не имеет ничего общего со временем и не является временной задержкой.2. Что мне следует использовать, чтобы, по вашему мнению, не потребовалось много времени(относительного) для паузы? Я сейчас пробую
umwait
, но если у вас есть лучший способ, пожалуйста, оставьте ответ @Brendan .3. Я, кажется, не могу найти много о том, как использовать umwait, поэтому я все еще открыт для ответов.
4. @matapple: umwait-прекрасное предложение, не считая того факта, что он настолько новый, что большинство компьютеров его не поддерживают. Попробуйте
_mm_pause()
в цикле проверить текущее время, как я предлагал, и посмотрите, делает ли это то, что вам нужно. Если вы можете сообщить нам свои допуски, это также поможет (т. Е. Нужна ли вам точность в 1 микросекунду или что).5. Это работает, и я получил микросекундное разрешение, которое хотел.
Ответ №2:
Если вы не хотите платить за переключение контекста потока, подумайте о том, чтобы не переключать контекст потока, например, с помощью сопрограмм.Здесь Гор Нишанов утверждает, что приостановка и возобновление сопрограммы занимает менее наносекунды
Комментарии:
1. Операционная система порождает поток, и этот поток имеет контекст, например значения в регистрах процессора. Если у вас больше потоков, чем процессоров, операционная система выделяет каждому потоку некоторое время процессора. Если поток приостанавливается, а затем возобновляется, операционной системе необходимо восстановить контекст этого потока. переключение контекста вики