3620f97f31544f16f92e23539418272f.jpg

Для большинства пользователей ПК критерий выбора оперативной памяти схож с выбором накопителя — чем больше, тем лучше. И с этим, конечно же, не поспоришь — как говорится, памяти много не бывает. Но почему-то многие забывают про скоростные характеристики памяти, считая, что они слабо влияют на производительность.

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

Но если с накопителями все понятно — чем быстрее их скорости чтения и записи, тем быстрее будут читаться файлы, и тем быстрее будет происходить с ними работа, то вот в случае с ОЗУ и процессором все остается туманным, и в этой статье мы попытаемся развеять этот туман.

Как происходит обсчет данных на процессоре

Начнем с того, как именно процессор работает с данными. По сути перед ним стоит задача: у него есть неструктурированная информация, с которой он должен что-то делать. Сама информация хранится в кэше процессора — это небольшой объем быстрой памяти, которая обычно расположена на одном кристалле с CPU для быстрого доступа к ней.

Что делать процессору с неструктурированной информацией? Вполне логично, что он должен ее структурировать — и для этого создается так называемая очередь инструкций вместе с кэшем инструкций: это место, где хранятся так сказать «полуфабрикаты» — процессор уже знает, как именно работать с этой информацией, но пока с ней не работает.

1.png

Каждый процессор имеет множество вычислительных блоков — ALU или FPU — которые и предназначены для работы с арифметическими и логическими данными. И каждый такт процессор выбирает из очереди именно те микрооперации, которые могут занять как можно больше вычислительных блоков, и если так получается, что мы нагружаем все доступные блоки, то мы достигаем максимальной загрузки и, значит, и производительности процессора.

На практике же, разумеется, всегда встречаются простои. Рассмотрим это на простом примере: допустим, нам нужно сложить X и Y. Казалось бы, плевая задача — но только при условии того, что мы эти X и Y знаем. Но зачастую X — это результат сложения A и B, а Y — результат, допустим, разности C и D. Поэтому процессору сначала нужно посчитать A+B и C-D, и лишь потом он сможет вычислить X+Y. В итоге вычисление X+Y откладывается как минимум на один такт, что приводит к появлению пустого места в конвейере на текущем такте.

Однако все может быть много хуже — у процессора может банально не быть данных ни для каких вычислений. Конечно, тут все сильно зависит от выполняемой задачи и «ровнорукости» программиста, писавшего сию программу — последний должен хорошо себе представлять, как процессор будет «понимать» его код, преобразованный декодером команд процессора. Так что в идеальном случае, если программист написал код, который способен хорошо и на некоторое время вперед загрузить CPU вычислениями, то тут влияния на производительность от разгона памяти практически нет — даже если данные подгружаться медленно, процессору все равно есть, что считать.

Увы, но на практике таких программистов маловато, и поэтому процессоры постоянно дорабатывают так, чтобы они могли быть заняты даже при недостатке данных. Для этого используется так называемый предсказатель переходов (или ветвлений), который по особому алгоритму может «додумать», что ему делать дальше, когда данных недостаточно. 

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

Нужно больше золота памяти

4960x_die_detail.png

Очевидно, что проблем с недостатком данных не было бы в принципе, если процессор хранил все нужные данные у себя. Однако на практике это слишком дорого, поэтому кэш рос медленно — в 90-ые годы это были десятки килобайт кэша первого уровня (L1). На рубеже тысячелетий этого стало катастрофически мало, и добавили кэш второго уровня, L2, объемом в сотни килобайт. В конце нулевых появился кэш L3, позволяющий хранить несколько мегабайт информации, ну и совсем недавно, в 2015 году, появились процессоры с кэшем четвертого уровня, L4, объем которого мог быть до 128 МБ.

Смысл в увеличении объема кэша был прост — обеспечить процессор как можно большим количеством данных, получить доступ к которым он может с наименьшими задержками, что, в свою очередь, уменьшает количество простоев. Но, разумеется, все данные в кэш поместить не получится, поэтому часть их хранится в ОЗУ, которая имеет задержки доступа зачастую на порядок больше, чем кэш L1, и в разы больше, чем L3. Плюс пропускная способность памяти кажется просто смешной, если сравнивать ее с теми гигантскими объемами информации, с которыми процессор может оперировать ежесекундно.

Поэтому, если нам нужно обсчитать большой объем информации, который не помещается в кэш, то задержки при работе с ОЗУ и ее относительно низкая пропускная способность прямым образом влияют на загрузку процессора — то есть на то, будут ли у него данные для вычислений, или нет — а это, в свою очередь, напрямую влияет на его производительность.

Каким именно образом память влияет на производительность

Теперь, когда с теорией немного разобрались, пора бы уже объяснить, как именно влияет память на производительность CPU. Представим себе задачу, при работе с которой процессор 50% времени простаивает. Казалось бы — по мониторингу нагрузка на него должна быть 50%, но на практике тот же диспетчер задач будет говорить, что CPU занят на 100%. Врет ли он? Да в общем-то нет — перед процессором стоит задача, и он ее из всех сил выполняет. Ну а то, что при этом конвейер занят на 50% — ну вот такая «кривая» задача, процессор все равно не может выполнить ее быстрее.

Теперь представим, что у нас есть идеальная память, частоту которой можно увеличить вдвое. Что произойдет? Во-первых, вдвое увеличится пропускная способность. Во-вторых, вдвое уменьшатся задержки — потому что они изначально измеряются не в наносекундах, а в тактах контроллера памяти, которые обратно пропорциональны частоте. Соответственно рост частоты вдвое во столько же раз уменьшает задержки.

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

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

Еще увеличиваем частоту вдвое, еще вдвое уменьшаются задержки, а, значит, и простаивать процессор теперь будет «всего» 12.5%. Увеличение частоты еще в два раза «добавит» процессору еще 6.25% производительности, и так далее. Отсюда же, кстати, хорошо видно, что «бесконечный» разгон памяти не эффективен — уже после трех удвоений частоты мы будем «отыгрывать» лишь единицы процентов производительности — и это в том случае, если у нас задача изначально нагружала процессор всего на 50%. На практике этот уровень выше, поэтому и увеличение частоты выше определенного уровня перестает существенно увеличивать производительность.

Поэтому память и процессоры всегда развивались параллельно — так, с бурным ростом производительности CPU в 90-ые годы, когда новые процессоры всего через пару лет были вдвое мощнее предыдущих, ОЗУ тоже совершила качественный скачок от SDRAM до DDR, когда «внешняя» частота памяти стала вдвое выше «внутренней». Также хорошо видно, что сейчас в сегменте высокопроизводительных CPU, где количество ядер уже превышает пару десятков, начинается переход от 4-канальной памяти к 6-канальной. 

И тут становится ясно, что ОЗУ в общем-то не увеличивает производительность процессора — она лишь уменьшает время его простоя, приближая его к той производительности, которую он мог бы выдавать в идеальном мире. Поэтому не надейтесь на то, что, купив какой-нибудь Intel Celeron и DDR4-5000, вы получите производительность Core i7 — нет, такого не будет и близко. Но все еще, имея высокопроизводительный процессор, можно заставить его выдавать больше производительности, разогнав память. А вот оптимальный уровень частоты ОЗУ и ее задержек для каждого процессора свой — но это уже практическая область, которую мы в этой статье касаться не будем.