Всем привет! Это моя первая статья на Хабре, так что буду рад любым комментариям. Я бы хотел затронуть одну из самых сложных и больных тем в IT и электронике, из-за которой создают сотни бенчмарков и тестов, но вопрос всё равно остается открытым: как сравнить 2 процессора? Какую архитектуру выбрать в конкретной задаче, когда у тебя ограниченный бюджет и условия?
Представьте ситуацию: вы выбираете между Intel Core i9 и Apple M2 (как пример двух мощных систем). Один потребляет 300 Ватт и греется как печка, другой — 30 Ватт и работает от батареи 20 часов. Один показывает 200 FPS в играх, другой — 90, но в три раза эффективнее. Один стоит $600, другой — встроен в ноутбук за $800. Кого вы выберете?
В данной статье я "пройдусь" по самым известным способам измерения эффективности процессоров, их проблемам и возможном решении.
1. Эффективны ли бенчмарки?
Один из самых очевидных и довольно часто эффективных способов измерить производительность вычислительной системы — бенчмарк. Их огромное множество, начиная с самописных алгоритмов и заканчивая сложнейшими синтетическими тестами.
По бенчмарку довольно легко понять, подходит ли вам процессор или нет, ведь все результаты теста видны в консоли. Но сделать бенчмарк, который вам покажет общую производительность на реальном коде и способность чипа выполнить вашу задачу максимально эффективно, притом учесть количество съеденных ватт и температуру в пике — довольно тяжело, и особенно когда у тебя нет этого процессора под рукой. А синтетические тесты вроде SPECint 2017 часто показывают только пиковую производительность без учета других характеристик.
Подавляющее большинство бенчмарков измеряет пропускную способность и пиковую скорость выполнения. Бенчмарков по измерению энергоэффективности (операции на джоуль и подобные) практически нет. Тем более в современной эре гетерогенных архитектур важнее стал показатель скорости передачи данных между общим процессором (CPU) и специальным акселератором вроде Google TPU (изза чего обучение моделей нередко эффективно на многоядерных CPU для минимизации пересылок данных). Исследования конца 2000-х и начала 2010-х показывали, что оптимизация под SPECint приводит к неоптимальным решениям с точки зрения энергопотребления. Это привело к появлению метрик EDP (Energy-Delay Product) и бенчмарков, измеряющих мощность в реальном времени.
А вот что насчет популярных флопсов, то даже раньше FLOPS (FLoat OPerationS) была не самой корректной оценкой производительности - если оценивать именно процессоры. Как и��ог: "гонкам за флопсами" и другие оптимизации микроархитектуры в пользу скорости на операциях с плавающей точкой.
Это привело к очень интересному феномену "Попадание в бенчмарк" (Benchmarketing) — оптимизации, которые как раз ведут к повышению производительности на заранее известных тестах и бенчмарках, теряя производительность на реальных программах. Некоторые производители настраивали SoC на короткие "спринты" высокой частоты именно во время запуска популярных бенчмарков, что не отражало устойчивую производительность (было популярно для Android-систем).
Не говоря уже о том, что очень много бенчмарков любят измерять результаты в баллах относительно эталона. Баллы могут считаться на разных бенчмарках по-разному, делая их довольно необъективной оценкой эффективности архитектуры.
Если интересно, можете почитать тут, здесь также описано несоответствие между результатом в бенчмарке и реальном использовании.
2. Численные метрики — полезнее баллов с бенчмарков
Конкретные числа - очень показательная штука, но надо выбрать "правильные" числа. А их не так уж и мало. Сейчас я разберу некоторые популярные метрики.
Hz - герцы как показатель скорости
Частота раньше считалась прямым показателем скорости. Выше частота - меньше времени занимает 1 такт конвейера (так как частота - количество тактов в секунду). Это кажется логичным, и потому до 2000-х годов производители чипов стремились повышать частоту любой ценой путем конвейеризации EX-стадии на несколько штук, уменьшая латентность каждой (подробнее о конвейере процессора). Правда потом уже все поняли, что повышение частоты >6 ГГц сулит большими проблемами с теплоотводом, а проектирование таких чипов — тяжёлая инженерная задача. Тем более для точности еще крайне важен IPC (Instructions Per Cycle), а не сырые гигагерцы.
IPC — удобные Instructions Per Cycle
IPC буквально означает "количество инструкций за цикл", или же инструкции за 1 такт процессора. Казалось бы, в чем смысл этой метрики, если процессор вроде бы и так выполняет по одной инструкции за такт? На деле все сложнее: разные инструкции имеют разные латентность (к примеру, mul в среднем в 3 раза медленнее сумматора), а так называемые зависимости по данным (см. data hazards) и подавна не дают выполнять ровно по инструкции за такт - техника bypassing хоть и решает проблемы RAW-зависимостей (Read-After-Write) и других хазардов, но обычно в сложных конвейерах приходиться ждать 1 такт на разрешение зависимости (как итог, IPC = 1 инстр / 2 такта = 0,5 на зависимых инструкциях). И наоборот: современные суперскалярные OOO (Out Of Order) процессоры имеют IPC > 1 за счет параллелизма инструкций.
Однако IPC коварен — он может сильно отличаться на разных задачах, и привести его к среднему значению бывает очень нелегко. Поэтому обычно берут средний IPC на реальных, смешанных программах, который чаще всего в разы ниже "синтетических" IPC с бенчмарков.
Средний IPC является очень важным параметром, особенно в связ��е с частотой. Обычно их комбинируют в единую метрику Perf, которая часто численно равна IPC * Hz (что логично - производительность равна количеству инструкций за такт, помноженное на количество тактов в секунду). Perf - среднее количество инструкций в секунду, если переформулировать. Именно Perf считается наиболее точной метрикой для измерения сырой производительности, ведь показывает усредненную скорость с учётом производительности на частых обращениях к памяти, кэш-миссам, мощностью векторных блоков и т.д.
Perf/Watt и Perf/mm² - "для гиков"
Практичные (кроме perf/$) метрики для большинства процессоров.
Perf/Watt — очень удобная метрика, особенно для RISC-процессоров, микроконтроллеров и IoT-устройств. Она обозначает среднее количество инструкций, которое наш чип способен выполнить, потратив 1 Ватт энергии. Этой единицей измерения очень удобно показывать эффективность чипов в микроконтроллерах, где каждый Ватт энергии на счету. Именно перфоманс на Ватт — главная фишка Apple Silicon благодаря множеству разных оптимизаций, включая UMA (Unified Memory Access) и мощному кластеру из E-cores, специально заточенных под энергоэффективность и фоновые задачи. Основная причина — отсутствие мощного кулера в ноутбуках, из-за чего тепло уходит пассивно через корпус, здесь как раз уместны низкие потребления.
Perf/mm² — очень интересная и не самая частая метрика измерения эффективности процессора, но, тем не менее, полезная. Она буквально обозначает, какую вычислительную мощь мы получаем на 1 мм² кремния этого чипа. Сложность в том, что по ней одной ты не узнаешь реальную производительность процессора, а получишь абстрактные "производительность на мм² площади". Как доп. критерий при покупке с ограниченным бюджетом может быть удобной, но часто она неполная. Тем не менее, высокая производительность на площадь явно намекает пользователю на современный техпроцесс (5нм, 3нм) и SoC (System-On-Chip), сильно уменьшая количество лишних шин данных и повышая плотность транзисторов, а также косвенно указывая на относительно дешёвую цену.
Есть еще одна метрика, довольно непрактичная — Perf/$. Я буду удивлен, если кто то с ней считался или вообще видел. Считать среднее количество инструкций в 1 доллар очень странно, но в связке с perf/watt может дать какое-то понимание.
3. Так в чем проблема?
А проблема вот в чем — нет единой метрики. Чтобы понять все "грани" той или иной модели чипа, надо знать хотя бы 2 из вышеперечисленных метрики или хорошо разбираться в архитектурах процессоров. Очень сложно понять, подходит ли той или иной процессор под ваши задачи, пока вы его не купите и не проведёте нужные вам бенчмарки или тесты. А сырые цифры - не для всех лёгкая штука.
Вот бы была такая метрика, которая учла бы все самые частые характеристики и могла высчитать "пользу" под вашу задачу. Точнее, уже формула.
4. Может, сделать единую формулу?
...которая объединит в себе и площадь, и мощность, и производительность!
Отличная математическая задачка. Давайте попробуем это сделать. Вот что мне пришло на ум:
Eff = (Perf * LogicalCores^a) / (TotalPower^b * TotalArea^c) / 10⁶
Где: 0<a<1; 0<b,c<1,5;
LogicalCores = (P_cores * SMT + E_cores)Номер 1 — производительность
От нее зависит все. В чем будем измерять производительность? Конечно, не в герцах и не чистых IPC. К примеру, можно в Perf - он адекватно показывает среднее количество инструкций в секунду, а это как раз то, что определяет скорость одного ядра. Будем брать номинальную производительность на реальном коде, а не синтетике.
Также важной метрикой является количество ядер (LogicalCores), а точнее потоков и уровень параллелизма. Тут мы вводим коэффициент a — он показывает уровень, до которого мы можем распараллелить исходную задачу. 1 — задача идеально параллельна и все ядра загружены, 0 — распараллелить невозможно. При этом итоговый множитель нелинейный, что очень хорошо показывает закон Амдала.
Также тут использованы логические ядра (не путать с физическими). Многие современные процессоры поддерживают Hyper-Threading технологию, при которой одно ядро может запускать несколько потоков (обычно до 2). Логические ядра - это как раз количество физических ядер, умноженное на количество потоков на одно ядро. Для гетерогенных систем явно разделяем P-ядра и E-ядра.
Один минус — она не показывает латентность памяти и кэшей, что мы не учитываем. Как таковую пропускную способность памяти я не собираюсь измерять, ведь я фокусируюсь именно на измерении общей эффективности процессора.
Номер 2 — тепло и площадь
Это наши враги, убивающие производительность. Или же друзья — зависит от того, что мы ищем. Делители — TotalPower обозначает общее тепловыделение на все ядра чипа в Ваттах, а TotalArea — соответственно, всю площадь чипа в мм² (включая кэши, межъядерную коммуникацию и т.д, но не включая остальную периферию).
Также можно заметить, что b и c коэффициенты могут быть больше 1. Это зависит от задачи — если нужно выбрать самый энергоэффективный чип, то ставим на максимум b, если самый компактный — то высокий c.
Интересно, что TotalArea косвеннт обозначает цену чипа — ведь чем больше площадь, тем дороже чип, так как мы платим за бо́льший кусок кремния. В формуле c-коэффициент явно задает критерий площади, и в зависимости от кейса он может быть высоким.
Как это работает?
Коэффициенты вы подбираете сами под конкретные задачи. Вы сами выставляете a, b и c под нужные вам задачи, что очень важно. Она показывает не просто perf/watt, а именно то, насколько тот или иной процессор вам подходит.
Основная часть формулы довольно логична: мы делим общую производительность (это производительность одного ядра, умноженная на количество потоков) на общие затраты (вся потраченная мощность и затраты на площадь чипа). Коэффициенты, возводящие в степень компоненты формулы, регулируют их значимость. А конечный делитель 10⁶ просто нормализует результат до удобных для понимания.
Степени, кстати, с потолка не взяты. Коэффициент a, к примеру, прекрасно иллюстрирует закон Амдала, который даже на идеально параллельном коде не дает линейное ускорение при увеличении числа потоков. Даже при a = 0,9 на процессоре с 4 логическими ядрами мы получим примерный множитель 4^0,9 ≈ 3.48, а с 16 — только 12.1. С 24 ядрами — 17.46. Видно, что даже на максимально параллельном коде мы не получаем бонус в x4 раза, а только в x3,4. На меньшем коэффициенте a уровень нелинейности только растет.
Коэффициенты b и c аналогично влияют нелинейно на итоговый результат, регулируя "важность" параметров. Так, b = 1 делает линейный вклад потребления энергии в результат, а b = 1,5 сильно "наказывает" мощные процессоры, подводя результат в пользу энергоэффективных.
Пример конфигураций для разных задач (для ориентира):
Игровой ПК: a = 0,5 (2-3 ядра загружены); b = 0,5 (есть розетка и кулер); c = 0,2 (не важно). Эта конфигурация максимизирует однопоточную производительность
Сервер: a = 0,95 (максимальный); b = 1 (мощность важна); c = 0,4 (площадь кристалла мало влияет). Упор на многопоточность и perf/watt.
Телефон: a = 0,6 (в основном фоновый); b = 1,4 (очень важно); c = 0,6 (ограниченное место в корпусе). Упор на энергоэффективность.
Как пользоваться формулой
Красота этой формулы — полная конфигурируемость.
Посмотрим на конкретные примеры конфигураций — например, десктоп. Будем опираться на низкий параллелизм, небольшую мощность и не заоблачную цену:
— a = 0,6. Десктопные приложения имеют низкий параллелизм, single-thread решает.
— b = 1. Мощность важна, это видно - 1 приводит к линейной обратной зависимости от TotalPower
— c = 0,4. Площадь не так важна, ноутбук или моноблок большие.
Итак, давайте сравним 2 кандидата: Intel Core i9 и Apple M2 Pro (взял просто ради примера, вы можете сравнить вообще любые другие процессоры).
Важная оговорка: сразу скажу, что IPC (и частоту) я беру средние, из открытых исто��ников и проведённых бенчмарков вроде SPECint и Geekbench. Даже если в реальности он отличается на 0.1-0.3, это относительное сравнение, и разницы почти не сделает. Важен сам метод, а не абсолютные числа. Подставьте свои, более точные значения — и получите свою объективную оценку.
Intel Core i9 14900K:
Perf = IPC × Hz, как мы знаем. IPC ≈ 1,25 (в реальных программах); Hz ≈ 5,6 GHz (стабильная) -> Perf = 1,25 × 5,6 × 10⁹ = 7 000 000 000 инстр/сек в среднем
Logical cores = 8 * 2 + 16 = 32 потока
TotalPower ≈ 180 Ватт (под нагрузкой со слабым охлаждением)
TotalArea = 200 мм²
Считаем:
Eff = (7_000_000_000 * 32^0,6) / (180 ^ 1 * 200 ^ 0,4) / 10⁶ ≈ 56 * 10⁹ / 1499 / 10⁶ ≈ 37Apple M2:
IPC ≈ 1,5 (среднее); Hz = 3,5 GHz (номинально) -> Perf = 5 250 000 000 инстр/сек
Logical cores = 6 * 2 + 4 = 16 потоков
TotalPower ≈ 20 Ватт (если учитывать только cpu)
TotalArea = 155 мм²
Eff = (5_250_000_000 * 16^0,6) / (20 ^ 1 * 155 ^ 0,4) / 10⁶ ≈ 27,7 * 10⁹ / 150,3 / 10⁶ ≈ 18437 vs 184 — разница почти в 5 раз! Но не стоит думать, что M2 теперь имеет в 5 раз большую производительность: несмотря на высокую частоту и количество ядер, Core i9 проиграл в этом противостоянии, так как M2 имеет огромную энергоэффективность, компенсировав недостаток сырой скорости. И это кстати логично — в ноутбук вы вряд ли вставите флагманский i9, показывая правдоподобность формулы
Главное для понимания: эта формула дает оценочный показатель, на который можно полагаться при выборе архитектуры для конкретной задачи. Вы можете сравнить процессоры по-разному, меняя коэффициенты a, b и c и получая абсолютно разные результаты. Важно понимать, что сравнивать нужно только с едиными a, b, c, и это не абсолютные значения скорости/съеденных ватт и т.д, а оценка пользы процессора именно в заданной вами задаче, что гораздо важнее чистых флопсов и герц.
Кто хочет поиграть с формулой, вот быстрый copy-paste скрипт на питоне:
# Мини-скрипт для тестирования в консоли
# Ctrl+C для выхода, если что ;)
models = {}
def eff(perf, cores, power, area, a, b, c):
return round((perf * cores**a) / (power**b * area**c) / 1_000_000, 2)
a, b, c = map(float, input("Введите a, b и c через пробел: ").split(' '))
while True:
name = input("\nИмя модели: ")
if name in models.keys():
print("Прошлый результат:", models[name]["score"])
continue
models[name] = {}
models[name]["ipc"] = float(input("Средний ipc: "))
models[name]["hz"] = float(input("Средняя частота (ГГц): "))
models[name]["cores"] = float(input("Кол.во логических ядер: "))
models[name]["power"] = float(input("Общее потребление (Ватт): "))
models[name]["area"] = float(input("Общая площадь чипа (мм²): "))
models[name]["score"] = eff(models[name]["ipc"] * models[name]["hz"] * 10e9, models[name]["cores"], models[name]["power"], models[name]["area"], a,b,c)
print("Результат:", models[name]["score"])5. Возможные улучшения формулы
Тем не менее, она неидеальна - вряд ли вообще можно создать идеальную формулу для максимально точной и полной оценки эффективности процессора в сравнении с другими.
Тем не менее, в таком виде она уже невероятно полезно. Дальше можно ее просто немного нормализовать под все возможные кейсы. Вот как еще можно улучшить формулу:
Добавить пороговые значения
Внимательные читатели могли бы увидеть, что формула не учитывает пороговые значения. К примеру, уменьшение потребляемой мощности на десктопе после 50 Вт перестает быть значимой, так как все равно надобность в кулере становится минимальной. Тоже самое с площадью — формула может "поощрять" чрезмерно маленькие чипы, даже в ущерб эффективности. Это не критично, если вы не сравниваете всерьёз in-order RISCV-чип с 4 ядрами и какого нибудь монструозного Ryzen 9. Но можно попробовать закрыть этот недостаток через пороговые параметры и функцию max:
Eff = (Perf * LogicCores^a) / (max(TotalPower, P)^b * max(TotalArea, A)^c) / 10e6
Где P - наиболее оптимальная мощность; A - наиболее оптимальная площадьУменьшить значение SMT
SMT (Hyper-Threading) даеь нелинейный рост многопоточной производительности — P-ядро с SMT лишь примерно на 30% эффективнее ядра без SMT в многопоточных задачах. Оригинальная формула переоценивает её значение, хотя я должен сказать, что это практически не сказывается на результат при a < 0,9. Но для честности можно немного изменить расчет логических ядер:
LogicCores = Pcores * 1,3 + Ecores
В заключение
Надеюсь, статья вам понравилась. Я постарался затронуть все аспекты измерения скорости и насколько это на самом деле сложно — измерять эффективность процессоров. Даже 16 простейших RISC‑ядер могут быть лучше топового Ryzen в зависимости от задачи, бюджета и условий.
