Видеокарта в простое похожа на спящего зверя: частоты ядра падают до пары сотен мегагерц, плата расходует десяток ватт, и система спокойно живет в состоянии P8 или P12. Запуск расчета будит плату мгновенно, драйвер поднимает ее в P0, ядра уходят к полутора-двум гигагерцам, а потребление упирается в лимит мощности. Этой лестницей состояний, известной как P-states, драйвер управляет по правилам DVFS, и от положения на лестнице зависят скорость, температура и счет за электричество. Профилирование состояний питания это умение увидеть, где плата находится прямо сейчас, понять, почему драйвер сбросил частоту, и посчитать, сколько работы дает каждый ватт. Ниже разобраны запросы nvidia-smi, persistence mode, фиксация частот ядра и памяти, причины троттлинга и числовой расчет производительности на ватт.

Физика DVFS и лестница состояний от P0 до P12

Каждый полупроводниковый кристалл умеет работать на наборе пар частота плюс напряжение, а переключение между ними называется DVFS, от dynamic voltage and frequency scaling. Динамическая часть мощности растет пропорционально квадрату напряжения и первой степени частоты, короткая запись выглядит как P = C·V²·f, где C это емкость переключаемых цепей. Отсюда неприятная арифметика: подъем частоты с 1500 до 1800 МГц дает множитель 1.2 по частоте, но драйвер при этом поднимает напряжение с 0.85 до 0.95 В, и суммарный рост мощности выходит 1.2 × (0.95/0.85)², около полутора раз. Производительность растет линейно, а энергозатраты заметно быстрее, поэтому лишние ватты обходятся дорого и в прямом, и в переносном смысле.

Ускорители NVIDIA кодируют готовые пары частота плюс напряжение состояниями от P0 до P12, где P0 это максимум производительности, а P12 минимум потребления. Набор состояний зависит от модели: у серверных ускорителей лестница длинная, у настольных GeForce типично встречаются P0, P2, P3, P5 и P8, добирающиеся до P12 в глубоком простое. После нескольких секунд без нагрузки плата сползает вниз, частота ядра падает до 210-300 МГц, память до 405 МГц, а обратный подъем при появлении работы занимает миллисекунды, поэтому в живой системе состояние меняется десятки раз за минуту. Отсюда практический вывод: одиночный снимок малоинформативен, для картины нужны серии замеров, и даже состояние P0 не гарантирует максимальной частоты, ведь максимумы из раздела Max Clocks могут отличаться от рабочих частот P0 на несколько мегагерц из-за заводской калибровки.

Текущее состояние и частоты в выводе nvidia-smi

Самый быстрый взгляд на состояние платы дает пакетный запрос с выбранными полями:

nvidia-smi --query-gpu=name,pstate,clocks.sm,clocks.mem,power.draw,temperature.gpu,utilization.gpu --format=csv -l 1
name, pstate, clocks.sm, clocks.mem, power.draw, temperature.gpu, utilization.gpu
NVIDIA GeForce RTX 3060, P8, 210 MHz, 405 MHz, 11.29 W, 36, 0 %
NVIDIA GeForce RTX 3060, P0, 1867 MHz, 7501 MHz, 168.47 W, 69, 97 %

Строка с P8 показывает плату в глубоком простое, строка с P0 снята под расчетной нагрузкой, и разница между ними лучше любых слов объясняет, зачем вообще следить за состояниями. Ключ pstate дает текущую ступень лестницы, clocks.sm и clocks.mem сообщают фактические частоты мультипроцессоров и памяти в МГц, power.draw и temperature.gpu дополняют картину потреблением и нагревом, а параметр -l 1 повторяет запрос каждую секунду до прерывания по Ctrl+C.

Для глубокой диагностики удобнее три запроса целиком:

nvidia-smi -q -d PERFORMANCE
nvidia-smi -q -d CLOCK
nvidia-smi --query-supported-clocks=graphics,memory --format=csv

Первый выводит таблицу всех состояний с диапазонами частот ядра и памяти внутри каждого, и из нее сразу видно, куда драйвер вообще способен поставить плату. Второй показывает текущие частоты всех блоков, включая графический и видеодекодер, а также причины Clocks Event Reasons, по которым частота оказалась ниже заявленной. Третий печатает список допустимых значений, из которого позже выбирают цель для фиксации; драйвер принимает лишь частоты из этого списка, при чужом значении подставляя ближайшее разрешенное.

Непрерывный поток метрик вместо одиночных снимков дает встроенный монитор:

nvidia-smi dmon -s puc -d 1 -c 5
# gpu pwr gtemp mtemp sm mem enc dec
  0 11 36 34 210 405 0 0
  0 165 68 58 1867 7501 48 0
  0 171 71 61 1867 7501 52 0

Буквы после -s выбирают группы метрик, p это мощность и температуры, u утилизация, c частоты, ключ -d задает интервал в секундах, -c ограничивает число строк. Такой лог удобно складывать в файл и сопоставлять всплески мощности с моментами смены состояния, строка за такт читается даже в терминале через ssh-сессию.

Стабильный драйвер через persistence mode и службу nvidia-persistenced

Профилировщику мешает еще одна особенность драйвера на Linux: когда последний клиент закрывается, ядро драйвера выгружается, и следующий запуск заново инициализирует карту, добавляя секунды задержки и путая первые строки лога. Отсюда persistence mode, режим, в котором драйвер остается загруженным даже без клиентов:

nvidia-smi -pm 1
nvidia-smi --query-gpu=persistence_mode --format=csv

Команда требует прав суперпользователя, действует сразу и на все платы, если не указать -i, существует только на Linux и переживает ровно до перезагрузки, после которой режим возвращается в Disabled. Для серверов обходят системной службой nvidia-persistenced из состава драйвера:

sudo systemctl enable --now nvidia-persistenced

Служба держит драйвер резидентным и переживает перезагрузки сама. Здесь важна точность формулировок: persistence mode не держит частоты, в простое плата все равно сползает в P8, он лишь убирает накладные расходы на инициализацию при каждом запуске. Без прав команда изменения вернет отказ с кодом 4, а на устройстве без поддержки режима с кодом 3, и обе ошибки в логе профилировщика выглядят обидно именно из-за неочевидности.

Фиксация частот ядра и памяти для повторяемых замеров

Драйвер гоняет частоту по своей воле, поднимая ядра к максимуму при запасе по мощности и температуре, и для бенчмарков эта непредсказуемость оборачивается разбросом результатов от запуска к запуску. Лечение одно, зафиксировать частоты руками:

nvidia-smi -i 0 -lgc 1500
nvidia-smi -i 0 -lmc 7501
nvidia-smi --query-gpu=clocks.sm,clocks.mem,pstate --format=csv

Ключ -lgc принимает пару минимум и максимум через запятую или одно значение, как в примере выше, и работает на архитектуре Volta и новее. Ключ -lmc тем же способом фиксирует память, на ускорителях Hopper он не поддерживается, там его заменяет отложенный вариант -lmcd, вступающий при следующей инициализации драйвера. Оба ключа требуют прав суперпользователя, а значения берут из списка допустимых частот: при произвольном числе драйвер молча подставит ближайшее разрешенное, поэтому контрольный запрос после фиксации обязателен.

Устаревший вариант -ac принимает пару частота памяти и частота графики, классический пример вызова выглядит как -ac 2000,800, но его пометили к удалению и рекомендуют связку -lmc и -lgc. У свежих драйверов у -lgc есть и режим: --mode=0 фиксирует частоту с максимальной точностью, --mode=1 включает замкнутый контур регулирования, который чуть снижает точность, зато улучшает производительность на ватт для части задач.

nvidia-smi -i 0 -lgc 1500 --mode=1
nvidia-smi -rgc -rmc

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

Причины снижения частоты и лимит мощности

Фиксация не отменяет физических ограничителей, и раздел CLOCK честно перечисляет причины, по которым частота упала ниже запрошенной. Запись SW Power Cap означает, что плата уперлась в программный лимит мощности, SW Thermal Slowdown сообщает о перегреве выше рабочего порога, HW Thermal Slowdown режет частоту вдвое и сильнее, а Sync Boost выравнивает частоту по самой медленной карте группы. Причины видны и в компактном виде, через --query-gpu с полем clocks_event_reasons.active, а на старых драйверах clocks_throttle_reasons.active.

Лимит мощности смотрят отдельным запросом:

nvidia-smi -q -d POWER

В выводе стоят мгновенное потребление, действующий предел Enforced Power Limit, заводское значение Default Power Limit и границы Min и Max Power Limit, у типичного игрового ускорителя это выглядит как минимум 125 Вт, заводские 170 Вт и потолок 180 Вт. Лимит перестраивается на лету:

nvidia-smi -i 0 -pl 140

Снижение с 170 до 140 Вт урежет пиковую частоту, но освободит запас по нагреву и шуму, а в тесных корпусах это единственный способ удержать плату в разумном тепловом режиме. Рядом живут счетчики Clock Event Reasons Counters, копящие время каждого ограничения в микросекундах: если за час теста счетчик SW Power Cap набрал минут двадцать, задача уперлась в питание, и поднимать частоту бессмысленно, пока лимит не поднят или частоты не снижены руками. На части устройств доступен еще и -gtt, сдвигающий целевую температуру, ниже которой драйвер охотно держит буст.

Расчет производительности на ватт по данным замеров

Производительность на ватт считают просто: фиксируют частоту, прогоняют фиксированную задачу, записывают время и среднюю мощность. Среднюю мощность собирает короткий конвейер:

nvidia-smi --query-gpu=power.draw --format=csv,noheader,nounits -l 1 | awk '{s+=$1; n++} END {printf "avg %.1f W\n", s/n}'

Дальше простая арифметика на примере теста, считающего тысячу шагов симуляции. На зафиксированных 2100 МГц он идет 480 с при средней мощности 245 Вт, энергия выходит 480 × 245 = 117.6 кДж, и на каждый килоджоуль приходится 1000 / 117600, около 8.5 шага. На 1650 МГц те же шаги идут 611 с при 178 Вт, это 108.8 кДж и уже 9.2 шага на килоджоуль. Снижение до 1400 МГц растягивает задачу до 720 с при 152 Вт, энергия 109.4 кДж, и эффективность падает до 9.1 шага, потому что время выросло, а постоянные расходы на память и питание самого кристалла остались.

Оптимум оказался у середины лестницы. Подъем с 1650 до 2100 МГц укорачивает работу на пятую часть, 480 с против 611, и стоит плюс 8 процентов энергии, на рабочей станции время почти всегда дороже. Спуск до 1400 МГц уже ничего не экономит, время растет, а энергия даже чуть выше, ведь постоянные расходы размазываются по более долгой шкале. В стойке датацентра ваттами платят и за электричество, и за охлаждение, поэтому там середина лестницы выбирается чаще, а крайние режимы оставляют коротким всплескам.

Частые ошибки профилировщика и порядок рабочего замера

Ошибки в этой области типовые и повторяются из проекта в проект. Состояние P0 само по себе не говорит о скорости, при активном лимите мощности плата сидит в P0 с частотой вдвое ниже буста. Сонные 210 и 405 МГц в простое это не поломка, а нормальное поведение, и чинить его нечем и не нужно. Забытая фиксация частот на общем узле превращается в месячную загадку для коллег, поэтому после замеров фиксацию снимают. Ключ -lgc на карте старше Volta вернет отказ с кодом 3, и это тоже часть диагноза, а не повод перебирать значения наугад.

Рабочий порядок замера на одной машине укладывается в несколько строк: 1. включить persistence mode командой nvidia-smi -pm 1 и убедиться, что плата в простое сидит в P8; 2. снять список допустимых частот через --query-supported-clocks и выбрать цель для ядра; 3. зафиксировать ядро и память командами -lgc и -lmc и проверить результат запросом clocks.sm; 4. прогреть нагрузку пять минут и вести лог через dmon или конвейер с awk; 5. записать время задачи, среднюю мощность и счетчики Clock Event Reasons; 6. снять фиксацию командами -rgc и -rmc и повторить контрольный запрос.

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