Наши партнеры

UnixForum






Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

На главную -> MyLDP -> Тематический каталог -> Аппаратное обеспечение

Что каждый программист должен знать о памяти

Оригинал: What every programmer should know about memory
Автор: Ulrich Drepper
Дата публикации: 21.09.2007
Перевод: Капустин С.В.
Дата перевода: 25.03.2009

2 Современное массовое аппаратное обеспечение

2.1 Типы RAM

За прошедшие годы было много типов RAM, и каждый тип отличался, зачастую значительно, от другого. Старые типы сегодня интересны только историкам. Мы не будем исследовать их детали. Вместо этого мы сконцентрируемся на современных типах RAM. Мы пройдем только по поверхности, исследуя детали, видимые ядру ОС или разработчику программного обеспечения через характеристики производительности.

Первые интересные детали сосредоточены вокруг вопроса, почему существуют различные типы RAM на одной и той же машине. Более конкретно, почему существуют вместе статическая RAM (SRAM {В других контекстах SRAM может означать ⌠синхронная RAM■.}) и динамическая RAM (DRAM). Первая намного быстрее и предоставляет ту же функциональность. Почему не вся RAM на машине это SRAM? Ответ, как легко ожидать, в цене. SRAM намного дороже производить и использовать, чем DRAM. Оба этих фактора важны, важность второго возрастает все больше и больше. Чтобы понять эту разницу, мы посмотрим, как реализовано хранение единицы информации для SRAM и DRAM.

В оставшейся части этого раздела обсуждаются низкоуровневые детали реализации RAM. Будем вдаваться в детали ровно настолько, насколько это требуется. То есть будем обсуждать сигналы на "логическом уровне", а не на том уровне, на котором их рассматривают разработчики аппаратного обеспечения. Этот уровень для наших целей достаточен.

2.1.1 Статическая RAM

Рисунок 2.4: 6-транзисторная статическая RAM

Рисунок 2.4 показывает структуру 6-транзисторной ячейки SRAM. Ядро этой ячейки формируется четырьмя транзисторами от M1 до M4, которые формируют два перекрещенных инвертера. Они имеют два стабильных состояния, представляющих 0 и 1 соответственно. Состояние остается стабильным, пока подается напряжение Vdd.

Если нужно узнать состояние ячейки, на линию доступа к слову WL подается ток. Это немедленно делает состояние ячейки доступным на BL и BL. Если нужно записать новое состояние, сначала устанавливаются нужные значения на BL и BL и затем подается ток на WL. Так как внешние генераторы сильнее четырех транзисторов (от M1 до M4), это позволяет перезаписать старое состояние.

Более детальное описание того, как работают ячейки памяти можно найти в [1]. Для дальнейшего обсуждения важно отметить следующее:

  • одна ячейка требует шесть транзисторов. Есть варианты с четырьмя транзисторами, но у них есть недостатки.

  • поддержание состояния ячейки требует постоянного наличия напряжения.

  • состояние ячейки становится доступным почти немедленно после подачи напряжения на WL. Сигнал настолько прямоугольный (быстро меняется между двумя двоичными состояниями) насколько таковыми являются все сигналы, управляемые транзисторами.

  • состояние ячейки стабильное, циклы регенерации не требуются.

Есть другие формы SRAM, более медленные и экономичные, но они нам неинтересны, так как мы смотрим на быструю RAM. Эти медленные варианты интересны в основном из-за того, что они могут использоваться вместо динамической RAM, так как имеют более простой интерфейс.

2.1.1 Динамическая RAM

Динамическая RAM по своей структуре намного проще, чем статическая. Рисунок 2.5 показывает структуру типичной ячейки DRAM. Она состоит всего из одного транзистора и одного конденсатора. Огромная разница в сложности означает, конечно, что она и функционирует совсем по-другому.

Figure 2.5: 1-транзисторная динамическая RAM

Ячейка динамической RAM хранит своё состояние в конденсаторе C. Транзистор M служит для того, чтобы охранять доступ к состоянию. Чтобы прочитать состояние ячейки подается ток на линию доступа AL, это приводит к тому, что в зависимости от наличия заряда в конденсаторе на линии DL может появиться или не появиться ток. Чтобы записать данные в ячейку линия DL соответственно устанавливается, затем на AL подается ток на время, достаточное для зарядки или разрядки конденсатора.

Есть некоторые затруднения при реализации схемы работы динамической RAM. Использование конденсатора означает, что чтение ячейки разряжает конденсатор. Эта процедура не может повторяться до бесконечности, в некоторый момент конденсатор необходимо перезарядить. Еще хуже то, что для того, чтобы обеспечивать энергией огромное количество ячеек (сейчас на чипах 109 или больше ячеек) емкость конденсатора должна быть маленькой (на уровне фемтофарад или ниже). Полностью заряженный конденсатор содержит несколько десятков тысяч электронов. И хотя сопротивление конденсатора велико (пара тераОм), он самопроизвольно разряжается за короткое время. Эта проблема называется "утечки".

Из-за утечек ячейки DRAM нужно постоянно подзаряжать. Сейчас для большинства чипов DRAM эта подзарядка происходит каждые 64 миллисекунды. Во время цикла подзарядки доступ к памяти невозможен. В некоторых случаях это задерживает до 50% обращений к памяти (см. [2]).

Вторая проблема, возникающая из-за маленького заряда, это то, что информация, прочитанная из ячейки, не может быть сразу использована. Линия данных должна быть подключена к усилителю считывания, который должен определить, 0 это или 1, так как единицей может быть целый диапазон значений заряда.

Третья проблема, это то, что чтение ячейки истощает заряд конденсатора. Это означает, что после каждой операции чтения должна идти операция перезарядки конденсатора. Это делается автоматически направлением выхода из усилителя считывания обратно в конденсатор. Это означает, однако, что чтение требует дополнительной энергии и, что более важно, времени.

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

[Formulas]

Это означает, что конденсатору нужно некоторое время (определяемое емкостью C и сопротивлением R), чтобы зарядиться или разрядиться. Это также означает, что ток, который может быть распознан усилителем считывания, появляется не сразу. Рисунок 2.6 показывает кривые зарядки и разрядки. Единицами измерения оси X служат единицы произведения емкости на сопротивление RC, которые являются единицами времени.

Рисунок 2.6: Время зарядки и разрядки конденсатора

В отличие от случая статической RAM, где результат чтения ячейки появляется немедленно после подачи тока на линию доступа слова, всегда проходит некоторое время пока конденсатор отдаст достаточное количество заряда. Эта задержка жестко ограничивает скорость DRAM.

Простой подход имеет и свои преимущества. Основное - это размер. Площадь на чипе, необходимая для одной ячейки DRAM во много раз меньше площади для ячейки SRAM. Ячейкам SRAM также необходимо отдельное питание для транзисторов, поддерживающих её состояние. Структура ячейки DRAM также позволяет располагать рядом друг с другом много ячеек, образующих матрицу.

В общем, значительная разница в стоимости побеждает. Везде, кроме специализированного аппаратного обеспечения (например, сетевых маршрутизаторов), мы вынуждены жить с основной памятью, основанной на DRAM. Это оказывает громадное влияние на работу программиста, что мы и обсудим далее в этой статье. Но сначала ещё несколько деталей об использовании DRAM.

2.1.3 Доступ к DRAM

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

Было бы совершенно непрактично адресовать каждый участок памяти непосредственно из контроллера памяти: 4Гб RAM потребовали бы 232 адресных линий. Вместо этого адрес передается как двоичное число, используя меньшее количество адресных линий. В чипе DRAM этот адрес нужно, прежде всего, демультиплексировать. Демультиплексор с N адресными линиями будет иметь 2N выходов. Эти выходы будут использоваться для выбора ячейки памяти. Использование такого прямого подхода не является проблемой для чипов небольшого размера.

Но число ячеек растет, и этот подход больше не работает. Чип с емкостью 1Гбит (ненавижу эти десятичные префиксы из СИ. Для меня гигабит всегда будет 230, а не 109 бит.) потребовал бы 30 адресных линий и 230 линий выбора. Размер демультиплексора растет экспоненциально при росте числа входных линий, если мы не хотим жертвовать скоростью. Демультиплексор с 30 входными линиями занимает большую площадь на чипе и вдобавок очень сложен. Еще важнее то, что передать 30 импульсов по адресным линиям синхронно намного сложнее, чем, скажем, "всего" 15. Меньше линий придется в этом случае подгонять по длине так, чтобы сигнал доходил до конца по ним одновременно. {Современные типы DRAM такие, как DDR3, могут автоматически подгонять время, но есть пределы допустимых расхождений.}

Рисунок 2.7: Схема динамической RAM

На рисунке 2.7 изображена упрощенная схема строения DRAM. Ячейки DRAM организованы в строки и колонки. Можно было бы расположить их в одной строке, но тогда потребовался бы огромный демультиплексор. А так мы можем обойтись одним мультиплексором и одним демультиплексором общим размером вполовину меньше. {Мультиплексоры и демультиплексоры эквивалентны, и мультиплексор здесь будет работать как демультиплексор при записи. Поэтому отныне мы будем их отождествлять.} Это огромная экономия со всех сторон. В этом примере адресные линии a0 и a1 через демультиплексор выбора адреса строки (RAS - row address selection) выбирают адресную линию целой строки ячеек. При чтении содержимое всех ячеек строки подается на мультиплексор выбора адреса колонки (CAS - column address selection) {линия над именами означает логическое отрицание}. На основе адреса, полученного по адресным линиям a2 и a3, содержимое одной из колонок подается на выход чипа DRAM. Это происходит параллельно на некотором количестве чипов DRAM, для того чтобы получить количество бит, соответствующее ширине шины данных.

При записи новое значение ячейки подается на шину данных и, когда ячейка выбрана через RAS и CAS, оно сохраняется в ячейке. Очень простой дизайн. Конечно, в реальности намного больше сложностей. При чтении нужно определить задержку, с которой данные поступают на шину данных, после подачи сигнала с адресом. Мы знаем из предыдущего раздела, что конденсаторы не отдают заряд мгновенно. Сигнал от ячеек такой слабый, что его нужно усиливать. При записи нужно определить, как долго должен подаваться сигнал с данными на шину, после того как выбраны адреса строк и колонок, чтобы успешно сохранить новое значение в ячейке (опять же конденсаторы не заряжаются мгновенно). Эти временные константы являются ключевыми для производительности чипа DRAM. Мы обсудим их в следующем разделе.

Ещё одна проблема масштабируемости состоит в том, что невозможно к каждому чипу подвести 30 адресных линий. Ножки чипа это драгоценный ресурс. К сожалению, данные по возможности должны передаваться параллельно (например, в 64 битных командах). Контроллер памяти должен уметь делать адресацию каждого модуля RAM (набора чипов RAM). Если по соображениям производительности требуется параллельный доступ к нескольким модулям RAM, и каждый модуль RAM требует свой набор из 30 или более адресных линий, тогда контроллеру памяти для 8 модулей RAM потребовалось бы более 240 ножек только для адресации.

Чтобы решить эту проблему, чипы DRAM уже давно мультиплексируют адреса самостоятельно. Это означает, что адрес передается двумя частями. Первая часть адресных бит (a0 и a1 в примере на рисунке 2.7) выбирает строку. Этот выбор остается активным, пока его не отменяют. Затем вторая часть, адресные биты a2 и a3, выбирает колонку. Ключевое отличие в том, что нужны только две внешние адресные линии. Ещё несколько линий будет необходимо для того, чтобы показывать, когда сигналы RAS и CAS готовы, но это небольшая плата за уменьшение числа адресных линий вдвое. Это мультиплексирование адресов само по себе, однако, создает некоторые проблемы. Мы обсудим их в разделе 2.2.

2.1.4 Выводы

Не беспокойтесь, если детали этого раздела покажутся вам неясными. Вот все важные вещи, которые нам понадобятся в дальнейшем:

  • есть причины, почему не вся память является памятью типа SRAM

  • чтобы использовать конкретную ячейку памяти, её нужно предварительно выбрать

  • число адресных линий непосредственно влияет на стоимость контроллера памяти, материнской платы, модуля DRAM и чипа DRAM

  • результаты операций чтения и записи доступны не сразу, а через некоторое время

В следующем разделе мы немного углубимся в детали процесса доступа к памяти DRAM. Мы не будем больше обсуждать детали доступа к SRAM, которая обычно адресуется напрямую. Так поступают для большей скорости и из-за небольшого размера SRAM. SRAM в настоящее время используется как встроенная в кэшах ЦПУ, а там размер соединений маленький и полностью под контролем разработчика ЦПУ. Кэши ЦПУ мы обсудим позже, но все, что мы должны знать, это то, что ячейки SRAM имеют определенную максимальную скорость, которая зависит от напряжения, приложенного к SRAM. Эта скорость может варьироваться от немного медленнее, чем ядро ЦПУ, до на один или два порядка медленнее.

[1] Wikipedia. Static random access memory. http://en.wikipedia.org/wiki/Static_Random_Access_Memory, 2006.

[2] Vinodh Cuppu, Bruce Jacob, Brian Davis and Trevor Mudge. High-Performance DRAMs in Workstation Environments. IEEE Transactions on Computers, 50(11):1133--1153, 2001.

[3] Stokes, Jon ``Hannibal''. Ars Technica RAM Guide, Part II: Asynchronous and Synchronous DRAM. http://arstechnica.com/paedia/r/ram_guide/ram_guide.part2-1.html, 2004.

[4] Dowler, M. Introduction to DDR-2: The DDR Memory Replacement. http://www.pcstats.com/articleview.cfm?articleID=1573, 2004.

[5] Double Data Rate (DDR) SDRAM MT46V. Micron Technology, 2003.


Назад Оглавление Вперед