Дросселирование процессора в C++
Мне просто интересно, есть ли элегантный способ установить максимальную нагрузку на процессор для конкретного потока, выполняющего интенсивные вычисления.
Прямо сейчас я нашел наиболее трудоемкий цикл в потоке (он выполняет только сжатие) и использую GetTickCount()
а также Sleep()
с жестко закодированными значениями. Это гарантирует, что цикл продолжается в течение определенного периода времени, а затем спит в течение определенного минимального времени. Это более или менее выполняет работу, т.е. гарантирует, что поток не будет использовать более 50% процессорного времени.
Однако поведение зависит от количества ядер процессора (огромный недостаток) и просто безобразно (меньший недостаток:)).
Есть идеи?
5 ответов
Я не знаю ни одного API, который бы заставлял планировщик ОС делать то, что вы хотите (даже если ваш поток имеет приоритет бездействия, если нет готовых потоков с более высоким приоритетом, ваш будет работать). Тем не менее, я думаю, что вы можете импровизировать довольно элегантную функцию регулирования на основе того, что вы уже делаете. По сути (у меня нет удобной машины для Windows):
Выберите количество времени, по истечении которого поток будет спать каждую итерацию. Затем на каждой итерации (или на каждой n-й итерации, так что функция регулирования сама по себе не становится значительной загрузкой ЦП),
- Вычислите количество процессорного времени, использованного вашим потоком с момента последнего вызова функции регулирования (я назову этот dCPU). Вы можете использовать API GetThreadTimes(), чтобы получить количество времени, которое ваш поток выполнял.
- Вычислите количество реального времени, прошедшего с момента последнего вызова функции регулирования (я назову этот dClock).
- dCPU / dClock - это процент использования ЦП (одного ЦП). Если оно выше, чем вы хотите, увеличьте время сна, если ниже, уменьшите время сна.
- Пусть ваш поток спит в течение вычисленного времени.
В зависимости от того, как ваш сторожевой таймер вычисляет загрузку ЦП, вы можете использовать GetProcessAffinityMask(), чтобы узнать, сколько ЦП имеет система. dCPU / (dClock * CPU) - это процент общего доступного времени CPU.
Вам все равно придется выбирать магические числа для начального времени ожидания и величины увеличения / уменьшения, но я думаю, что этот алгоритм может быть настроен так, чтобы поток работал на довольно близком к определенному проценту ЦП.
В linux вы можете изменить приоритет планирования потока с помощью nice().
Проблема в том, что не хочется оставлять процессор бездействующим, пока у вас есть работа. Обычно вы устанавливаете фоновую задачу с приоритетом IDLE и позволяете операционной системе планировать все время ЦП, которое не используется интерактивными задачами.
Для меня это звучит так, как будто проблема в сторожевом процессе.
Если ваша фоновая задача связана с процессором, то вы хотите, чтобы она занимала все неиспользуемое время ЦП для своей задачи.
Может быть, вы должны посмотреть на исправление сторожевой программы?
Я не могу придумать какой-либо кроссплатформенный способ того, что вы хотите (или любой гарантированный способ полной остановки), но, поскольку вы используете GetTickCount, возможно, вас не интересует кроссплатформенность:)
Я бы использовал межпроцессное взаимодействие и установил хорошие уровни интенсивных процессов, чтобы получить то, что вам нужно, но я не уверен, что это подходит для вашей ситуации.
РЕДАКТИРОВАТЬ: Я согласен с Бернардом, поэтому я думаю, что процесс, а не поток может быть более подходящим, но он может просто не соответствовать вашим целям.
Вы можете изменить приоритет потока, но изменение максимального использования потребует либо опроса и хаков для ограничения количества происходящих событий, либо использования инструментов ОС, которые могут установить максимальное использование процесса. Тем не менее, я не вижу никаких обстоятельств, когда вы хотели бы сделать это.