Тип загрузки ЦП для выполнения постоянной расслабленной работы

Я пытаюсь понять, как запрограммировать определенный тип нагрузки на процессор, чтобы он работал постоянно, но со средней нагрузкой.

Единственный известный мне подход, как загрузить ЦП какой-то работой, которая не будет работать с максимально возможной производительностью, - это когда мы чередуем часть предоставления ЦП чего-то делать со сном в течение некоторого времени. Например. чтобы достичь 20% использования ЦП, выполните некоторые вычисления, которые потребуют, например. 0,2 секунды, а затем спать в течение 0,8 секунды. Тогда загрузка ЦП будет примерно 20%.

Однако это, по сути, означает, что ЦП будет постоянно переключаться между максимальной производительностью и бездействием.

Я написал небольшую программу на Python, в которой я создаю процесс для каждого ядра ЦП, устанавливаю его привязку, чтобы каждый процесс выполнялся на назначенном ядре, и даю ему какую-то абсолютно бессмысленную нагрузку:

def actual_load_cycle():
    x = list(range(10000))
    del x

при повторении вызова этой процедуры в цикле, а затем некоторое время приостанавливается, чтобы гарантировать, что рабочее время составляет N% от общего времени:

while 1:
    timer.mark_time(timer_marker)
    for i in range(coef):
        actual_load_cycle()
    elapsed = timer.get_time_since(timer_marker)

    # now we need to sleep for some time. The elapsed time is CPU_LOAD_TARGET% of 100%.
    time_to_sleep = elapsed / CPU_LOAD_TARGET * (100 - CPU_LOAD_TARGET)
    sleep(time_to_sleep)

Он работает хорошо, давая нагрузку в пределах 7% от желаемого значения CPU_LOAD_TARGET — мне не нужна точная величина нагрузки. Но он устанавливает очень высокую температуру ЦП, при CPU_LOAD_TARGET=35 (реальная загрузка ЦП, о которой сообщает система, составляет около 40%), температура ЦП достигает 80 градусов. Даже при минимальной цели вроде 5% темпы подскакивают, может быть, не так сильно - до 72-73.

Я считаю, что причина этого в том, что эти 20% времени процессор работает изо всех сил, и он недостаточно быстро охлаждается во время сна после этого.

Но когда я запускаю игру, такую ​​как Uncharted 4, загрузка процессора, измеренная MSI Afterburner, составляет 42-47%, но температура остается ниже 65 градусов.

Как я могу добиться аналогичных результатов, как я могу запрограммировать такую ​​​​нагрузку, чтобы сделать загрузку ЦП высокой, но сама работа была бы довольно расслабленной, как это делается, например. в играх?

Спасибо!

Тепло не связано напрямую с нагрузкой, но напрямую связано с мощностью. Как ваша программа соотносится со 130W на скриншоте?

Useless 27.11.2022 01:43

@Useless Теперь он измерил следующее: температура: 79 градусов, использование: 39%, мощность: 150 Вт.

Xarrion 27.11.2022 08:03

Но я не уверен, что это всегда верно, что температура вызывается силой. Если я загружу только 1 ядро ​​​​до 100%, мой процессор будет оставаться на уровне 70 ° C при нагрузке 6% и потреблять 77 Вт энергии.

Xarrion 27.11.2022 10:42
За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
TL;DR: Angular Signals может облегчить отслеживание всех выражений в представлении (Component или EmbeddedView) и планирование пользовательских...
Sniper-CSS, избегайте неиспользуемых стилей
Sniper-CSS, избегайте неиспользуемых стилей
Это краткое руководство, в котором я хочу поделиться тем, как я перешел от 212 кБ CSS к 32,1 кБ (сокращение кода на 84,91%), по-прежнему используя...
3
3
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Тепловыделение ЦП в основном зависит от его энергопотребления, которое очень зависит от рабочей нагрузки, а точнее от выполняемой инструкции и количества активных ядер. Современные процессоры очень сложны, поэтому очень сложно предсказать энергопотребление на основе заданной рабочей нагрузки, особенно когда исполняемый код представляет собой код Python, выполняемый в интерпретаторе CPython.

Есть много факторов, которые могут повлиять на энергопотребление современных процессоров. Наиболее важным из них является масштабирование частоты. Основные процессоры x86-64 могут адаптировать частоту ядра в зависимости от типа выполняемых вычислений (например, использование широких SIMD векторов с плавающей запятой, таких как регистры ZMM AVX-512F VS скалярных 64-битных целых чисел), количество активных ядер (чем больше количество ядер, тем ниже частота), текущая температура ядра, время выполнения инструкций по сравнению со спящим режимом и т. д. На современном процессоре иерархия памяти может потреблять значительное количество энергии, поэтому операции, связанные с контроллер памяти и, в более общем случае, ОЗУ могут потреблять больше энергии, чем тот, который работает с внутренними регистрами. На самом деле, что касается фактически выполняемых инструкций, процессор должен включать/отключать некоторые части своей интегральной схемы (например, блоки SIMD, встроенный графический процессор и т. д.), и не все они могут быть включены одновременно из-за ограничений TDP (см. Темный силикон). Инструкции SIMD с плавающей запятой потребляют больше энергии, чем инструкции SIMD с целыми числами. Что еще более странно: потребление на самом деле может зависеть от входных данных, поскольку транзисторы могут чаще переключаться из одного состояния в другое с некоторыми данными (исследователи обнаружили это при вычислении ядер умножения матриц на разных платформах с разными входными данными). Мощность автоматически адаптируется процессором, поскольку для инженеров было бы безумием (если вообще возможно) учитывать все возможные случаи и все возможные динамические нагрузки.

Одной из самых дешевых инструкций x86 является NOP, что в основном означает «ничего не делать». При этом процессор может работать на самой высокой турбо-частоте, поэтому выполнение цикла NOP приводит к довольно высокому энергопотреблению. На самом деле, какой-то процессор может выполнять NOP параллельно на нескольких исполнительных устройствах данного ядра, сохраняя занятыми все доступные ALU. Забавный момент: выполнение зависимых инструкций с высокой задержкой может фактически снизить энергопотребление целевого процессора.

Инструкции MWAIT/MONITOR предоставляют подсказки, позволяющие процессору войти в оптимизированное состояние, зависящее от реализации. Это включает в себя более низкое энергопотребление, возможно, из-за более низкой частоты (например, без турбо) и использование состояний сна . По сути, ваш процессор может спать в течение очень короткого времени, чтобы снизить его энергопотребление, а затем иметь возможность использовать высокую частоту в течение более длительного времени из-за более низкой мощности / тепловыделения ранее. Поведение аналогично человеческому: чем глубже сон, тем быстрее может работать процессор после этого, но чем глубже сон, тем дольше время (полного) пробуждения. Плохая новость заключается в том, что такая инструкция требует очень высоких привилегий, AFAIK, поэтому вы в принципе не можете использовать их из пользовательского кода. Насколько я знаю, в пользовательской среде есть инструкции для этого, такие как UMWAIT и UMONITOR, но они еще не реализованы, за исключением, возможно, самых последних процессоров. Для получения дополнительной информации, пожалуйста, прочитайте этот пост.

На практике интерпретатор CPython по умолчанию потребляет много энергии, потому что он делает много обращений к памяти (включая косвенные и атомарные операции), выполняет множество ветвлений, которые должны быть предсказаны процессором (у которого есть специальные энергожадные блоки для что), выполняет множество динамических переходов в большом коде. Тип исполняемого кода на чистом Python не отражает реальных инструкций, выполняемых процессором, поскольку большая часть времени будет потрачена в самом интерпретаторе. Таким образом, я думаю, вам нужно использовать язык более низкого уровня, такой как C или C++, чтобы лучше контролировать тип выполняемой рабочей нагрузки. В качестве альтернативы вы можете использовать JIT-компилятор, такой как Numba, чтобы иметь лучший контроль, все еще используя код Python (но уже не чистый Python). Тем не менее, следует иметь в виду, что JIT может генерировать много нежелательных инструкций, что может привести к неожиданно высокому энергопотреблению. В качестве альтернативы компилятор JIT может оптимизировать тривиальные коды, такие как сумма от 1 до N (упрощенная как просто выражение N*(N+1)/2).

Вот пример кода:

import numba as nb

def test(n):
    s = 1
    for i in range(1, n):
        s += i
        s *= i
        s &= 0xFF
    return s

pythonTest = test
numbaTest = nb.njit('(int64,)')(test) # Compile the function

pythonTest(1_000_000_000)  # takes about 108 seconds
numbaTest(1_000_000_000)   # takes about 1 second

В этом коде функция Python требует в 108 раз больше времени для выполнения, чем функция Numba на моей машине (процессор i5-9600KF), поэтому следует ожидать, что для выполнения версии Python потребуется в 108 раз больше энергии. Однако на практике все еще хуже: функция на чистом Python заставляет целевое ядро ​​потреблять гораздо большую мощность (не просто больше энергии), чем эквивалентная скомпилированная реализация Numba на моей машине. Это хорошо видно на мониторе температуры:

Base temperature when nothing is running:          39°C
Temperature during the execution of pythonTest:    55°C
Temperature during the execution of numbaTest:     46°C

Обратите внимание, что мой процессор работал на частоте 4,4-4,5 ГГц во всех случаях (из-за выбранного регулятора производительности). Температура восстанавливается через 30 секунд в каждом случае, и она стабильна (благодаря системе охлаждения). Функция запускается в цикле while(True) во время теста.

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

Должен был знать, что писать загрузку ЦП лучше всего с помощью скомпилированного кода, а не интерпретируемого. Я изменил нагрузку на скомпилированную тестовую функцию вашего примера. Это меняет мир. Теперь я могу поддерживать температуру на уровне 60°C, даже когда загрузка процессора достигает 80%. Миллиард спасибо вам!

Xarrion 27.11.2022 16:31

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