Глава 0. Введение
Привет, читатель! Посмотрим, как древнючий Broadwell аж из 2015 года выжимает все соки из своей подсистемы памяти (напомню, что это 1150 сокет с DDR3 оперативной памятью), приближаясь по её латентности к более современным решениям.
Глава 1. Что такое L4 и с чем его едят?
Автор, это явно какое‑то противоречие! Как процессор, работающий с оперативкой, старше многих школьников, умудряется догонять те же Skylake вроде i7-6700K?
Ответ кроется в той самой подсистеме памяти, а вернее в L4 кэше. Он же — eDRAM
eDRAM (embedded Dynamic Random Access Memory) изначально создавался как быстрый буфер, созданный для повышения ПСП (пропускной способности памяти) для встроенной графики Iris Pro 6200.

Все‑таки, если он создавался изначально под встройку, то почему на представленной схеме он мало того, что сидит на кольцевой шине, так еще и съел часть кэша третьего уровня своими тегами?! Ответ прост: тогда Intel не испытывала конкуренции (AMD со своими Bulldozer находилась в глубоком упадке) и она могла позволить себе такие эксперименты. К тому же, далее станет понятно, зачем этот эксперимент вообще был проведен. Но не будем забегать вперед.
Теги кэша L4, съевшие транзисторный бюджет кэша L3, позволяют префетчеру работать с ОЗУ агрессивнее. Каким образом? Все потому, что за счет этого ядра знают о наличии подушки безопасности, которая смягчит последствия заваливания мусором кэша L3. Да, действительно, это привело к тому, что в сравнении с другими CPU той эпохи у нас не 2 мегабайта на ядро, а 1.5 (6 мегабайт на проц целиком), но зато будем работать не с DDR3 с латентностью ~65 нс, а c eDRAM с задержкой ~45 нс.
Сам по себе кэш L4 работает по схеме Non‑Inclusive Victim Cache (Неинклюзивный кэш жертв). Это означает, что в иерархии памяти он работает вот так:
Сначала процессор должен сбегать в ОЗУ и загрузить данные в кэш L3
Если он столкнется с экзистенциальным кризисом: поймет, что загруженные данные отравили кэш (вызвали Cache Pollution) и теперь их необходимо куда‑то деть, прождав вечность, то:
Выгрузить эти данные обратно в оперативную память и скачать новые
Тут страсти накаляются! Если стандартный процессор (например, Haswell) будет выгружать их обратно в ОЗУ, то наш экспериментальный Broadwell это сделает быстрее, выгрузив их в eDRAM.
И теперь, если вдруг процессору понадобятся те данные, которые поначалу оказались мусором (а в итоге стали нужны как можно скорее), он не пойдет в DDR3, вызвав простой. Вместо этого он, используя теги L4 в L3, сходит в L4, передав запрос системному агенту.

Другими словами, это свалка тех данных, что не вместились в L3, но выбросить в ОЗУ нашему герою стало жалко. Настоящий Плюшкин.
А как это работает с точки зрения операционной системы? А никак:) Дело в том, что для ядра операционной системы и для MSR‑регистров, которые отслеживают поведение процессора, кэш L4 прозрачен. Серьезно. Вы не найдете никаких метрик вроде L4MISS/L4HIT в утилитах отладки типа intel‑pcm или perf. Все события, происходящие за пределами L3 не отслеживаются никоим образом. Поэтому один из способов узнать активность L4 (собственно, он здесь и будет использоваться) — это отслеживать трафик той самой DDR3 и IPC.
Глава 2. Работа JVM на сервере Minecraft и префетчер — вещи несовместимые
Вспомним, что Java управляет ссылочными типами данных. В контексте игры это означает, что все энтити (сущности), все блоки и чанки лежат в оперативной памяти не последовательным массивом, а разбросаны во всей куче (heap). Кроме того, каждый такой объект помимо себя самого обязан нести заголовок. Данный факт напрочь ломает стандарты процессора: префетчер сходит с ума, пытаясь угадать, какой кусок данных понадобится следующим.
Мало того, что всё это раздувает рабочее пространство процессора, так еще и вызывает дикие требования к латентности ОЗУ. Все эти объекты должны быть получены CPU как можно скорее для обработки. В противном случае мы получим постоянные ожидания за небольшой порцией данных или, проще говоря, падение IPC (количества инструкций за такт).

Рассмотрим самый яркий пример: блуждание по указателям (Pointer chasing) в самом тяжелом случае. Мы организуем взрыв огромного количества блоков динамита в игре. Когда мы заставляем такое количество взорваться, происходит следующее:
Ядро CPU запрашивает объект TNT № 1.
Опрашивает насчет объекта иерархию кэшей — мимо
Бежит в оперативную память, чтобы получить информацию об объекте
Пока оно бежит, оно задумывается о смысле жизни: ему больше нечего делать. В этот момент обычный префетчер разводит руками — он не смог предугадать этот прыжок по адресу
Наконец‑то CPU познал смысл жизни! Кхм. Нет, он наткнулся на очередной указатель, например, взорвавшегося объекта TNT № 2, и вариантов, кроме как думать об этом снова и снова, больше нет.
Тут наш Плюшкин может гордиться своей кладовой. Пока префетчер типичных Haswell или Skylake вынужден осторожничать с посылками, чтобы не захламлять L3 (а предсказать наперед, что понадобится, невозможно: поток данных хаотичен), Broadwell может принимать эти самые посылки сотнями, тысячами, а то и сотнями тысяч. Да, с одной стороны он гарантированно будет встречать промахи L3 (объем‑то меньше!) и чаще работать с ОЗУ. Но ему есть куда складывать излишки! Так что, в таких тяжелых ситуациях, когда процессору нужно разгрести вагон и маленькую тележку указателей, eDRAM должен спасти ситуацию: стабилизировать IPC и опустить потребление ОЗУ гораздо раньше.
Часть 3. Тестовое оборудование
В качестве подопытных были взяты два максимально похожих процессора: i7-5775C (Название статьи кричало об этом с самого начала, правда?:)) и Xeon E3-1230V3. Вкратце пробежимся по ним:
Максимальная частота турбобуста на ядро: 3.7 ГГц
Количество ядер/потоков: 4/8
Оба были скальпированы и переведены на жидкий металл, после чего склеены обратно
Это Broadwell и Haswell соответственно. Разница в теоретическом IPC: 3–5%. Это значит что на 3–5% i7-5775C будет быстрее, чем Xeon E3-1230V3 за‑счет небольших архитектурных улучшений при условии, что ядра насыщены данными.
Можно возразить: автор, по спецификациям Intel All‑Core Turbo у них разные! Да, разные, но об этом далее.
Собственно, сам тестовый стенд:

Asus H97-PLUS
16 ГБ DDR3 (4 плашки Elixir по 4 ГБ с чипами Nanya) с XMP профилем 9-9-9-28 2N 1600 МГц
Intel Optane M10 16 ГБ для директории сервера Minecraft
Hynix PC401 256 ГБ для операционной системы
Кулер Deepcool по типу боксового с медным сердечником
GT 710. Видеокарта здесь нужна чтобы исключить влияние встроенной графики
А теперь самое главное: какая же операционка и как, черт меня возьми, получилось зафиксировать одинаковую частоту по всем ядрам и отследить поведение камней? Следите за пальцами:
Debian GNU/Linux 13 (Trixie)
Governor переведен в режим Performance (именно это заставило камни работать на максимальной частоте)
OpenJDK 25 jre‑headless.
PurpurMC 26.2 сервер, билд № 112
Все метрики были получены с помощью утилиты intel‑pcm
Ключ запуска сервера:java -Xms8G -Xmx8G -XX:+UnlockExperimentalVMOptions -XX:+AlwaysPreTouch -XX:+UseG1GC -XX:G1NewSizePercent=35 -XX:G1MaxNewSizePercent=60 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=16M -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -jar server.jar nogui
Переходим к самим тестам!
Глава 4. И чем же ты хочешь нас удивить?
Было проведено два теста, нагружающих процессоры по‑разному:
Преген мира с помощью плагина Chunky, настроенным на радиус 2000 блоков
Взрыв шар TNT радиусом 30 (это порядка 113 000 блоков) в строго одинаковых координатах, с одинаковыми сидом (зерном генерации) и типом мира
Сид мира: 42157344778486, тип мира: AMPLIFIED, координаты центра шара: -86.300/270/-18.492
Внутриигровые метрики вроде TPS/MSPT не замерялись: тесты, очевидно, экстремальны, и в условиях таких нагрузок никто не играет. Это бенчмарк от мира JVM. Здесь гораздо интереснее смотреть на поведение ОЗУ и подопытных. Поэтому замерялись: IPC, промахи L3 и трафик DDR3

Что видно на графиках? Видно именно то, что гласила теория!
Анализируем этап 1: прегенерация мира — предсказуемая и легкая задача. IPC обоих процессоров держится выше 2, трафик DDR3 и кэша промахи L3 коррелируют друг с другом. Префетчеры справляются, а задача была завершена за примерно одно время с разницей в те самые 3–5%
Анализируем этап 2: непосредственно взрыв. Обратите внимание на кэш промахи i7-5775C. Их очень много. Трафик оперативки у этого же камня образует «горб». Самое главное — IPC. IPC у i7-5775C держится выше, он стабильнее. Пока Xeon E3-1230V3 грустит в ожидании новой пищи для размышлений, i7-5775C руководствуется данными бодрее и принимает решения молниеносно.
Но как так получается? Промахов кэша у Broadwell ведь объективно больше!
Всё дело в том самом eDRAM, что мы обсуждали ранее. Мусорные данные оказываются не мусорными, а возвращаться за ними достаточно быстро: нужно всего лишь сходить в свою кладовую, а не плестись в библиотеку. Другими словами: Broadwell пытается (и у него это получается) нивелировать латентность ОЗУ используя фирменный L4.
Прикладываю также графики для каждого, отдельно взятого процессора:


Глава 5. И что в итоге?
Нужно снижать латентность ОЗУ для экстремальных Java задач! Действительно, есть тенденция покупать процессоры от AMD с 3D V‑Cache. Это позволяет запереть объем критически важных данных для серверов. Кэш L3 не бесконечен: когда дело доходит о тысячах объектов в оперативной памяти JVM, он разводит руками.
Таким образом: если сервер создается как локальный, на небольшое количество игроков для ванильных ядер, стоит рассмотреть Ryzen с 3D V‑Cache. Если же на сервере будет огромное количество сущностей, необходимо любыми средствами снижать латентность всей ОЗУ.
Исходники статьи на Яндекс.Диске https://disk.yandex.ru/d/x9_FIr3ik7W1Vw
ITsuperiorRF
Спасибо за статью! Интересно было почитать.
Единственное, иногда определенные речевые обороты затрудняют чтение, как мне кажется, но это чисто субъективно.