Энергосберегающий SpinWait

У меня есть цикл опроса в C#, который должен опрашивать в среднем каждые 100 микросекунд (учитывая, конечно, что из-за нехватки ядра избыточное переключение контекста потока не выполняется, ).

Поскольку нет времени на перепланировку, Sleep(1) не подойдет.

Поэтому я решил выделить поток (и на практике ядро ​​при настройке сходства) и использовать Thread.SpinWait для набора циклов для каждой итерации. Хотя это работает нормально, оно потребляет ненужное количество энергии. 100 микросекунд будет достаточно для приостановки ЦП (хотя этого недостаточно для временного удаления потока из планировщика, поскольку временной интервал Windows будет слишком длинным).

Вместо этого я думал об использовании инструкции Intel PAUSE, но я не уверен, что это заставит процессор Intel приостанавливать аппаратный поток. Intel утверждает, что она сохраняет энергию и должна использоваться в цикле вращения, но поскольку пауза длится до 100 микросекунд, я действительно хочу, чтобы ядро ​​перешло в режим ожидания C1.

Есть идеи?

Редактировать: я опрашиваю сторонний API, поэтому нет события синхронизации для блокировки.

2 ответа

Решение

Естественно, использование примитивов и таймеров синхронизации является предпочтительным способом избежать ожидания загрузки процессора / энергопотребления. Однако, если вам нужно так часто опрашивать - нет способа добиться этого обычными средствами, по крайней мере, в пользовательском режиме.

Одна простая вещь, которую вы можете сделать, это включить pause Инструкция процессора в вашем цикле. В MSVC это реализовано внутренним YieldProcessor() метод.

Помимо этого - возможно, только в режиме программирования ядра. Там вы можете использовать высокоточный мультимедийный таймер.

Редактировать:

Около SetWaitableTimer, Это может быть вариантом. В отличие от "традиционных" функций ожидания Win32 (таких как Sleep, WaitForSingleObject и т. д.) в качестве параметра используется высокоточное время ожидания.

Однако таймеры пользовательского режима по своей природе асинхронны. Давайте предположим, что таймер становится активным с высокой точностью (хотя это не очевидно, "традиционные" функции ожидания Win32 с точностью до тактов, порядка десятков миллисекунд). После того, как таймер становится активным - он освобождает соответствующие ожидающие потоки. Но планировщик потока не должен немедленно присоединять этот поток к выполнению - он может ждать следующего отрезка времени. Или даже задержать выполнение потока больше, если есть параллельные потоки.

В заключение: идея, кажется, стоит попробовать. Но я не удивлюсь, если это более или менее эквивалентно использованию Sleep,

Учитывая, что ваши ожидания продолжительны, вы можете обнаружить, что мониторы области памяти SSE3 гораздо более эффективны с точки зрения энергосбережения, однако они на самом деле не рассчитаны как блокирующее ожидание вращения, а как оповещение с ожиданием, но все же могут оказаться жизнеспособной альтернативой.

Однако для получения этого в C# потребуется внешняя DLL, которая предоставляет интерфейс для встроенных функций C++ (_mm_mwait а также _mm_monitor).

Другие вопросы по тегам