HDD и SSD – единство различий (страница 2)
реклама
Позиционирование
Перед выполнением операций с секторами, HDD должен выставить головки на нужную дорожку. Собственно, на этом заканчивается достоверная информация и начинаются гадания. Как и всё, что касается низкоуровневого представления, закрыто плотным NDA. Что бы ни означали эти буквы, но информации нет. Что же, будем использовать "здравый смысл".
При переходе с дорожки на дорожку контроллер выдает новое значение тока соленоида позиционера, что вызывает перемещение головок. Вполне очевидно, что форма тока не постоянна во времени, применяется активный разгон и активное торможение (кстати, это вызывает повышенное потребление, поэтому степень 'активности' зависит от модели и области применения данного накопителя).
Позиционер лишен четких положений, нельзя гарантированно точно изменить его положение на нужное количество дорожек. Это раньше применялись шаговые двигатели (а в приводах на гибких магнитных дисках и сейчас), которые могли смещаться на одну дорожку при одном импульсе управления. В HDD для перемещения головок используется соленоид, а это означает весьма условную величину перемещения на изменение его тока.
С точки зрения математики, нет никаких проблем перевести нелинейное преобразование величины тока в целевое положение, вот только мешают случайные факторы - напряженность магнитного поля магнитов соленоида и ориентация HDD в пространстве, вещи довольно нестабильные. Поэтому контроллер может 'толкнуть' позиционер только на предполагаемое положение дорожки, а потом уточнять реальное положение и "дальше по обстановке". Для того чтобы узнать положение, используется чтение специальной разметки с номерами дорожек (и секторов). Значит, алгоритм позиционирования состоит в 'прыжке', потом головка выравнивается на текущей (куда попала) дорожке и осуществляется поиск записи с номером дорожки. То есть тупо сидит и ждет.
Поэтому есть довольно четкая зависимость между количеством адресных меток со временем позиционирования. Утрированно: если на дорожке только одна метка, то контроллеру придется, в среднем, ждать 1/2 времени оборота диска. Чем больше количество меток, тем меньше бессмысленные траты времени, но сами метки занимают место на дорожке, что уменьшает полезную площадь. Одна метка явно плохо, а, например, 50 или 100 почти одинаково малы и не мешают позиционированию. Сколько в реальности - не знает никто, из простых смертных. Но, судя по всему, количество меток уменьшается.
Впрочем, это не самое интересное в данном процессе. После нудного ожидания номера дорожки, контроллер всё-таки его получает и принимает решение по следующему перемещению позиционера, ведь это точно не та дорожка. Теория вероятности не исключает возможности сразу попасть на свою дорожку, но такого никогда не произойдет - на современных дисках порядка 200 тысяч дорожек. При перемещении на 100 тысяч, каков шанс, что удастся попасть именно на нужную, даже при условии довольно точных предсказаний перемещения? Практически нулевой.
реклама
Итак - 'промазали', значит надо сдвинуться и повторить-повторить...повторить. Пока конец дорожки не будет найден. Дорожка найдена, но операции надо выполнять не над первым попавшимся сектором, а с вполне конкретным. То есть контроллер должен ждать нужный сектор. Теперь вопрос - что делает контроллер в те моменты, когда 'ждет'? Самый простой и бессмысленный ответ - ничего. Однако во время ожидания контроллер мог считать довольно много информации с нескольких дорожек, в том числе и целевой. У него есть буферная память, где эту информацию можно сохранять. Понятное дело, что полученные данные никак не пригодятся при записи (хотя, и тут не всё гладко), но бо́льшую часть времени HDD выполняет операции чтения.
Последовательное чтение
Последовательное чтение означает получение информации с (обычно) последовательно расположенных секторов. Причем, операции выполняются блоками, величиной от одного сектора до MaxTransferLength. Последний параметр считывается из конфигурации привода операционной системой и обычно составляет 128 Кбайт. Обычно. Но некоторые устройства, чаще всего экзотические на Flash памяти, не поддерживают блочный режим, что крайне негативно сказывается как на общей производительности накопителя, так и на загрузке процессора при выполнении обмена с ним.
Для операционных систем *nix есть программа, которая возвращает параметр MaxMultSect, который есть то же самое, что и MaxTransferLength, только измеренное в 'секторах', а не байтах.
Итак, при выполнении команды чтения контроллер устанавливает головки в нужное положение на диске (дорожке), ждет появления конкретного сектора и начинает читать его в буферную память. Считав нужное количество секторов, контроллер накопителя выставляет в устройство ввода-вывода настройки для передачи считанного блока и начинает саму передачу данных. После этого он переходит к обработке следующего запроса. Данный вариант описан для обычного режима (IDE), в спекулятивных вариантах (AHCI или RAID+AHCI) будет несколько иначе, но не важно.
Важно другое - если вы думаете, что происходит именно так, то гарантированно ошибаетесь. Подчеркиваю - ошибаетесь безвариантно. Если бы контроллер обрабатывал запросы подобным 'последовательным' образом, то к началу обработки второго запроса (смотрите название параграфа - последовательное чтение) диск бы здорово сместился, и некоторое количество секторов просто пролетело мимо. То есть контроллер обязан (!) читать в буферную память то, что идет после (!) запрошенных данных. По некоторым слухам, HDD читает всю дорожку сразу. Может и не 'всю', но существенную часть точно.
В параграфе "Позиционирование" описывалось возможное поведение контроллера при позиционировании на целевой дорожке и, по логике вещей, выходит, что он может считывать информацию до нужного сектора. При выполнении самой команды чтения считывается нужное количество секторов (которое всяко меньше объема данных на дорожке одной поверхности) и далее хотя бы один сектор. Попробуем предположить, что он дочитывает сектора до полной дорожки.
С точки зрения операционной системы, данные считываются в последовательности 'установил дорожку' - 'прочитал' - 'передал', и так множество раз. А в реальности? Какой смысл что-то считывать, если это уже лежит в буферной памяти, да и само чтение потребует еще одного оборота диска? Естественно, никто так не делает. Команды чтения выполняются по несколько измененному пути: один раз 'установил дорожку' - 'прочитал' - 'передал' и во множестве 'взял из памяти' - 'передал'. При этом сам контроллер может начать выполнение следующей команды (для режимов AHCI).
реклама
Последовательная запись
Этот режим во многом повторяет идеологию последовательного чтения, только для случая записи кэшировать считываемые данные не надо и "пишется, как пишется". Естественно, контроллер будет 'умничать', он обязан (!) это делать - при записи данные собираются в буферную память, но не записываются до тех пор, пока не соберется достаточно большой последовательный набор секторов.
Причина здесь та же, что и в последовательном чтении - если долго копаться, то нужный сектор уже успеет пролететь под магнитной головкой и для получения доступа к нему придется ждать еще один оборот диска. То есть HDD без кэширования записи не работают. Объем локального кэширования должен быть не меньше количества секторов между адресными метками, если они поделены на блоки секторов, а лучше равняться размеру всей дорожки.
При последовательной записи, да и записи вообще, есть серьезная техническая проблема - запись неполного блока. В таком случае контроллер лишен права начинать запись без предварительного считывания всего блока хранения информации (сектора). И здесь могут быть проблемы. Гипотетически, было бы просто здорово поставить головку чтения на 'много' вперед и она бы считала тот блок информации, который сразу же был бы перезаписан с добавлением новых данных. Но... увы, позиционер поворачивает головку на дорожке при перемещении между ними, что исключает "гипотетически". Значит, придется тратить еще один оборот диска на считывание нужных секторов.
В любом случае, надо это непосредственно сейчас контроллеру или нет, но система кэширования через буферную память себя оправдывает.
SSD
Вначале о самой важной составляющей части - о микросхемах Flash памяти типа NAND. Их бывает три типа:
- SLC, Single Level Cell, двухуровневая ячейка – в накопительной ячейке хранится один бит данных с двумя уровнями напряжения – логический 0 и логическая 1. Уровни обладают большой разностью потенциалов, что позволяет надежно и быстро производить считывание и запись информации. В виду бо́льшей, чем MLC, стоимости применяется только в дорогих SSD.
- MLC, Maiden Level Cell, многоуровневая ячейка – в одной ячейке может храниться несколько бит данных. Когда говорят ”MLC”, то обычно подразумевают два бита, что означает использование четырех уровней сигнала – обычные 'да' и 'нет', и добавленные элементы женской логики 'возможно' и 'наверно'. С четырьмя уровнями работать труднее – при считывании вместо одного устройства сравнения приходится ставить несколько, а при записи, вместо уровней '0' и 'всё питание', устанавливать строго фиксированные уровни напряжения.
Всё это сильно замедляет работу с устройством и понижает надежность. Кроме снижения скорости работы, у MLC пониженная радиационная стойкость, что пока не существенно, и сниженное время хранения. Хуже другое - время хранения зависит от того, насколько использован ресурс микросхем. Процедуры стирания и записи увеличивают дефектность матрицы NAND, что приводит к возрастанию токов утечки. - TLC, Teenager Level Cell – в ячейке хранится три бита данных. Странно, что для такого принципа организации применили специальное название ”TLC”, когда уже существовало ”MLC”. Система хранения подобного типа ужасна – применяется восьмиуровневое кодирование. Малейшая нестабильность по питанию схемы записи или просто шум, и вместо одного уровня считается другой. Для SLC такое практически невозможно, у MLC с этим ‘плохо’, а TLC … единственно, что радует – SSD на них пока не делают.
Честно говоря, не очень понимаю, зачем разработали подобный тип ячейки. Большую емкость микросхемы можно получить переходом на более 'тонкий’ техпроцесс, в результате чего заряд в ячейке будет определяться действительно ‘счетным’ значением электронов. SLC и MLC технологии сохранят свою работоспособность, а TLC 'умрет' из-за банальной флуктуации и шума.
Слегка утрируя: при улучшении техпроцесса изготовления микросхем окажется, что микросхемы MLC и TLC будут обладать одинаковой емкостью при одинаковом размере – MLC еще можно будет 'уменьшать', а размеры ячейки TLC уже ограничены уровнем шума. И главное, каков выигрыш? Ради чего гробить надежность и скорость работы? У SLC в одной ячейке один бит, у MLC два, у TLC три. Выигрыш всего в полтора раза. Всего! И какой ценой. Нет, спасибо, склеротическую память с детскими болезнями – это в мусорную корзину.
SSD на микросхемах SLC довольно дороги. Скорее всего, будущее за MLC, поэтому только о них и пойдет речь.
Формат хранения данных в Flash памяти типа NAND медленно эволюционировал к повышению емкости микросхем и к снижению времени доступа, но за последнее несколько лет этот тип памяти претерпел существенные, не побоюсь этого слова, революционные изменения. Если в младенческие времена NAND была очень простой - поставил адрес и читай или записывай страницу, то на данный момент вроде бы мелкие изменения привели к качественному скачку. Появилось разделение на несколько поверхностей (plane), несколько независимых банков (Logical Units, LUNs), количество независимых микросхем в одном корпусе превысило количество ‘один’. Кроме того, был добавлен синхронный режим работы. Если брать все эти изменения 'по одному', то выигрыш от применения будет небольшой, но их суммарное воздействие сказывается крайне приятно на общей производительности.
Давайте, процитируем организацию Open NAND Flash Interface (ONFI), специализирующуюся на разработке стандартов внутренней организации микросхем такого типа:
A device contains one or more targets. A target is controlled by one CE# signal. A target is organized into one or more logical units (LUNs).
Эта фраза означает, что в одном корпусе может находиться одна или несколько дискретных микросхем NAND, которые выбираются с помощью индивидуальных сигналов выборки CE (Chip Enable, выборка микросхемы). Каждая микросхема может содержать один или несколько логических блоков (LUN). Стоит сразу добавить, что один логический банк может содержать несколько плоскостей (plane).
Давайте возьмем что-то конкретное, а то от формулировок ONFI вида "один или несколько" меня уже в дрожь бросает.
Например, MT29F32G08. В ее спецификации написано:
1. # of CE# = 2
2. # of die = 4
3. Common
Пункт первый, тут просто - две независимые микросхемы (targets).
реклама
Пункт два, несколько сложнее - 4/2 = две микросхемы с двумя логическими блоками в каждом.
Пункт три - общая шина данных. Еще бывает "Separate", что означает раздельные выводы шины данных для всех микросхем в корпусе. Про последний вариант лучше сразу забыть - под MLC память его практически не встречается, как и 16-битной шины - банально дорого, требуется очень уж много выводов в корпусе, что стоит денег. Да и геометрические размеры растут, снова затраты.
Так, стоп! Давайте посмотрим на одну таблицу, сейчас поймете зачем:
Электрическая емкость выводов зависит от количества устройств, подключенных к данному сигналу внутри корпуса.
И что же выходит? ... емкость прямо пропорциональна количеству LUN'ов!
Так, всё, счищаем лапшу с ушей. Пусть господа ONFI и дальше играют в свое квазиумничанье, а я скажу прямо - и LUN, и Die (target?) есть одно и то же. Меняется принцип выборки - аппаратный сигнал CE для target и старший (старшие?) для LUN(s), но суть одна и та же - в корпус запихнули множество независимых микросхем NAND. Так что, не забивайте себе голову глупостями с разбивкой на LUN и target.
Кстати, в спецификации микросхемы указано "Density – 32Gb (quad-die stack)". Фууу, и на том спасибо. Четыре. Независимых устройств четыре и точка.
Итак, посмотрим на структурную схему NAND:
В принципе, здесь изображена половина микросхемы из примера (для одного target) - два LUN с двумя поверхностями на каждом.
Итак, про ‘разные’ LUN забыли, это не интересно, и сосредоточим внимание на детальную структуру одного LUN. Он состоит из пары плоскостей, состоящих из блоков, которые, в свою очередь, собираются из секторов. Неплохая выходит матрешка. Если присмотреться внимательнее, то замечается явная аналогия с форматом HDD. Сектор = страница, дорожка = блок, сторона диска = plane. Довольно странно - у диска две стороны, а у NAND всего две plane. Складывается ощущение, что в ONFI собрались ярые фанаты накопителей на жестких дисках.
Страница - минимальная адресуемая единица чтения (или записи) информации. Можно прочитать/записать и меньше, но все остальное, 'остаток' страницы, все равно считается из NAND при чтении или запишется мусором при записи. Однако некоторые типы микросхем (обычно это SLC) поддерживают работу с неполными страницами.
Блок - минимальная единица стирания информации. Если бы в NAND можно было стирать блоки, равные размеру страницы, то это было бы просто и красиво. Но разработчики видимо посчитали, что это было бы слишком уж просто и исключили возможность стирания одиночных страниц.
Плоскость (plane) - некий элемент для повышения скорости работы. Весь LUN делится на две равные сущности, которые могут работать (относительно) независимо. Возможно, вы спросите, почему бы не считать это разбиение аналогично дроблению одного корпуса на target и LUN? Да, плоскости могут независимо выполнять команды, но разработчики опять позаботились, чтоб пользователям было не слишком удобно. Например:
Two-Plane Addressing
Two-plane commands require two addresses, one address per plane. These two addresses are subject to the following requirements:
- The least significant block address bit (BA7), must be different for each address.
- The most significant block address bit for 32Gb devices (BA19), must be identical for both addresses.
- The page address bits, PA[6:0], must be identical for both addresses.
В переводе это звучит примерно так:
- Бит адреса BA7 выбирает номер плоскости, поэтому при указании адреса для какой-то плоскости ставьте значение этого бита в соответствии с номером плоскости. Пока логично, при обращении к плоскости 0 надо и номер и адрес указывать для плоскости 0.
- Бит адреса BA19 выбирает номер LUN, то есть при выставлении адресов должен быть выбран один и тот же LUN. Это тоже логично, контроллер плоскости не может 'вылезать' из своего LUN и идти в другой.
- В обоих адресах должен быть один и тот же номер страницы. Ссылка на картинку для медитаций.
Последнее свойство объединяет плоскости лучше сиамских близнецов - разделять их на что-то независимое будет так же трудно, как (у автора кончилась фантазия, извините).
Слава разработчикам, они думают за нас, чтоб, ни дай Бог, что-то работающее не вышло.
Итак, через плоскости, то есть одновременно, можно выполнять команды:
- чтения страницы *
- записи страницы
- стирание блока
* в виду явной надуманности, не все микросхемы поддерживают режим чтения по плоскостям. Используйте конвейерный запрос чтения через буферный регистр.
Операции с четными банками будут выполняться на нулевой плоскости его контроллером, а для банков с нечетным номером - на первой плоскости силами его контроллера.
Некоторые приемы, используемые в NAND для повышения скорости работы
Да, 'уффф', тягомотина закончилась, переходим к чему-то более интересному.
Шина передачи данных
При включении микросхема NAND работает в асинхронном режиме работы с передачей информации по управляющим сигналам. Это классический режим работы, только очень уж медленный.
Вычисление времени множества параметров долгая и весьма неточная процедура (из-за различий в быстродействии разных режимов), поэтому воспользуемся любезно предоставленной презентацией "ONFI 2 Source-Synchronous Interface Breaks the I/O Bottleneck".
В документе приводится информация, что асинхронный режим передачи данных ограничен 160 Мбайт/сек (страница 11).
Обратите внимание на максимальную высоту столбиков – ограничение именно из-за шины передачи данных. Для устранения этого досадного ограничения в ONFI 2.0 был введен режим синхронной передачи данных. При этом данные передаются по обоим фронтам управляющей частоты. Наверно, вы обращали внимание на странные цифры в маркировке микросхем NAND, довольно часто там фигурируют цифры вида "-12". Это означает, что для синхронного режима работы можно использовать задающий сигнал с периодом 12 нс, или 83 МГц, что означает скорость передачи данных 83*2=166 МГц.
Снова воспользуемся презентацией ONFI - в ней фигурирует скорость чтения, для подобного способа передачи, 800 Мбайт/сек (страница 21).
Разница почти в пять раз, и вызвана тем, что протокол чтения состоит из фазы выдачи команды чтения, установки адреса ... (подождать) ... считывания данных. Эту цепочку нельзя прервать для выдачи новой команды, ведь и команда, и адрес, и данные передаются через одну и ту же шину. Поэтому сокращение бессмысленного времени на передачу данных снимает ограничение на производительность всего устройства.
Буферная память
В документации по NAND фигурирует понятие 'регистр данных' (Data Register), в котором хранятся данные на запись или уже считанные из матрицы. То есть рисуют на картинках и пишут в тексте 'регистр', но речь идет о блоке данных в одну страницу (плюс небольшая зона под коды коррекции). А именно, размерность порядка 2 или 4 Кб (зависит от размера страницы в конкретной NAND). Пусть вас не вводит в заблуждение слово 'регистр', там лежит вся страница.
Для ускорения работы каналов передачи данных применяют дополнительную буферизацию, снимающую требование обязательной синхронности процесса записи с выполнением, что устраняет дополнительные задержки на ожидание. В NAND применяется аналогичный прием, между выходом и регистром данных вставлен кэширующий регистр. Его основная функция - сохранять данные до тех пор, пока они не будут переданы из устройства (при чтении) или помещены в освободившийся регистр данных (при записи).
Для последующих иллюстраций я буду использовать "Optimizing NAND Flash Performance" , представляемой организацией ONFI.
Чтение данных
Процедура чтения состоит из фаз выдачи команды и адреса страницы, небольшого ожидания и вычитывания данных. Проблема в "небольшом ожидании".
Хочу обратить внимание – на картинках красным цветом обозначается ожидание готовности устройства. Чем больше 'красного', тем менее эффективно работает обмен.
Для устранения ожидания можно сделать конвейерное чтение через кэш-регистр. Суть его в том, что во время вычитывания данных из NAND происходит загрузка из матрицы информации по следующей странице. Конкретно (и несколько упрощенно), происходит следующее:
- команда чтения первой страницы (с указанием адреса)
- большая пауза для получения данных из матрицы
- команда кэширующего чтения второй страницы (с указанием адреса)
- вычитывание данных из первой страницы. В действительности, данные считываются из буферного регистра (Cache Register), в который они переписались сразу по факту окончания передачи из матрицы в регистр данных. Пока идет процесс вычитывания данных из микросхемы, данные страницы номер два переписываются в освободившийся регистр данных.
- команда кэширующего чтения третьей страницы (с указанием адреса)
- вычитывание второй страницы из буферного регистра .... и далее аналогично.
Как вы наверно заметили, дополнительные накладные расходы ожидания есть только для чтения первой страницы, все остальные идут без пауз - время ожидания выполнения чтения из матрицы Flash скрадывается временем передачи данных из микросхемы - они идут параллельно.
Дополнительную экономию можно получить, используя команду кэширующего чтения без передачи полного адреса, просто указывая "следующий". Экономия небольшая, но есть.
Запись данных
Запись выполняется примерно таким же способом, что чтение, только намного дольше. Наверно, не стоит детально расписывать последовательность выполняемых действий и событий, логика происходящего аналогична чтению, только 'наоборот'. Процедура записи состоит из фаз выдачи команды, адреса, пересылки страницы данных и дооооолгого ожидания. Само время ожидания уменьшить нельзя, запись делается аппаратно контроллером в микросхеме NAND (для каждой плоскости свой).
Немного ускорить процесс записи нескольких страниц можно приемом, аналогичным применяемому в операции чтения - воспользоваться буферным регистром. При этом запись первого блока ведется обычно, но после окончания отправки данных контроллер принимает команду и данные в буферный регистр, который хранит их до освобождения регистра данных и начала следующей процедуры записи. Экономия? - на времени передачи данных, что откровенная мелочь в сравнении со временем ожидания окончания записи.
Однако вовсе не случайно в NAND применяется деление на плоскости. Это позволяет выполнять такую длительную процедуру, как запись, параллельно на плоскостях. То есть можно выдать команду записи для страницы банка I, потом сразу, без ожидания окончания процедуры, выдать команду записи для страницы банка I+1.
Дальнейшее повышение производительности можно получить, комбинируя оба варианта - запись через буферную память сразу на обе плоскости.
реклама
Лента материалов раздела
Соблюдение Правил конференции строго обязательно!
Флуд, флейм и оффтоп преследуются по всей строгости закона!
Комментарии, содержащие оскорбления, нецензурные выражения (в т.ч. замаскированный мат), экстремистские высказывания, рекламу и спам, удаляются независимо от содержимого, а к их авторам могут применяться меры вплоть до запрета написания комментариев и, в случае написания комментария через социальные сети, жалобы в администрацию данной сети.
Комментарии Правила