Почему мой первый бенчмарк CPU был слишком шумным и как я это исправил
5 ноября 2026 г.
Мои первые цифры бенчмарка выглядели разумно, пока я не запустил то же самое дважды и не получил разные ответы. Эта статья о том, как я нашёл причину и что изменил, прежде чем доверять любым числам.
Все числа взяты из README репозитория cpu-inference-bench (включая раздел «First attempt (archived)») и из results/archive_summary.json.
Первая попытка оказалась непригодной
Я начал с запуска ResNet-18 на PyTorch, ONNX Runtime и OpenVINO с настройками по умолчанию на ноутбучном CPU (Intel i7-12650H). Чтобы проверить повторяемость, я запускал каждую конфигурацию дважды. У 12 из 18 повторных строк два одинаковых запуска отличались более чем на 5%, а для одной строки (PyTorch, 12 потоков, batch 1) — до 48,27%. Результаты нельзя было использовать для сравнения, поэтому я их заархивировал.
У ноутбука есть ограничения по мощности пакета и по температуре, поэтому частота меняется во время запуска. Без контроля над этим разница в несколько процентов между фреймворками оказывается в пределах шума.
Поиск причины
В первой попытке использовалось масштабирование частоты по умолчанию, поэтому частота могла свободно меняться. У этого CPU устойчивое ограничение мощности пакета 45 Вт и кратковременное 115 Вт; такие ограничения по мощности и температуре могут менять частоту во время запуска. Фоновые службы и другие процессы на тех же ядрах тоже могут добавлять шум.
Данные той попытки заархивированы локально и не лежат в публичном репозитории, поэтому я не могу показать здесь частоты и температуры по запускам. Вместо того чтобы гадать, какой фактор преобладал, я изменил настройку так, чтобы каждый из них либо контролировался, либо был виден: теперь каждый повтор записывает температуру пакета, среднюю и минимальную частоту P-ядер и счётчики термического троттлинга ядра.
Пилот, которого всё ещё было недостаточно
Я ограничил P-ядра частотой 3000 МГц и провёл небольшой пилот. В двух из четырёх строк счётчики термического троттлинга ядра всё равно выросли, поэтому я выбрал 2600 МГц — частоту, которую ядра могут выдерживать.
Что я изменил
Все приведённые запуски используют:
- фиксированную частоту 2600 МГц на 6 P-ядрах при отключённых SMT-соседях — устойчивую частоту, которую ядра могут удерживать, а не пиковую;
- закреплённые ядра, питание от сети и остановленные фоновые службы;
- ожидание охлаждения перед каждым повтором, пока температура пакета не станет ниже 60 °C;
- чередующиеся раунды, чтобы дрейф одинаково влиял на все фреймворки;
- правило стабильности: строка стабильна, только если разброс по 5 повторам ниже 5% и ни один счётчик термического троттлинга не вырос.
Ускорение указывается только между двумя стабильными строками. Нестабильные строки показываются и помечаются, а не отбрасываются.
Что это дало
При таких ограничениях INT8 против FP32 для ResNet-18 при batch 1 дал 2,34× (PyTorch), 2,74× (ONNX Runtime) и 3,48× (OpenVINO, 2,6 мс). Пять из 36 строк BERT и 2 из 18 строк ResNet (обе — FP32) всё равно остались нестабильными, и в README об этом сказано.
Чего это не показывает
Тепловые счётчики не обнаруживают троттлинг по ограничению мощности, поэтому я также проверил столбцы с частотами. Во время всех запусков работал VPN-клиент, и я не измерял его влияние. Это один ноутбук и одна серия замеров.
Что я из этого вынес
- Запускайте одну и ту же конфигурацию дважды, прежде чем что-либо сравнивать.
- Сообщайте о нестабильных результатах, а не скрывайте их.
- Записывайте то, что вы не контролировали (здесь: ограничения мощности, VPN).
Код написан с помощью Claude Code; методология, решения и проверка — мои.