Когда я плотно занимался аппаратным тестированием в рамках разработки embedded-устройств, бывало так, что инженеры-разработчики и я оказывались в условиях жесткого ограничения в выборе возможных компонентов NAND или eMMC. И в этой связи возникала необходимость дополнительных проверок каждого из компонентов на долговечность и качество работы. Очень часто приходилось проверять чипы-кандидаты на общий ресурс записи/чтения, скорости операций и т. п. И мне пришла идея — почему бы не поделиться своим опытом с другими специалистами, перед которыми стоят аналогичные задачи. Я хотел бы рассказать в данной статье, что такое Flash-память, почему они выходят из строя, как я организовал тестирование и как через тестирование минимизировать риски при выборе устройства хранения для разрабатываемого устройства.
Всем, кому интересна данная тема — приглашаю под кат.
❯ Дисклеймер
Сразу же оговорюсь, что я не ставил для себя целью в этой статье сделать исчерпывающее описание, что такое Flash-память, не буду рассматривать стандарты индустрии и углубляться в рассмотрение вопросов по SSD-накопителям и прочим, не имеющим к embedded никакого отношения вещам. Я дам лишь вводные знания, чтобы инженер, принимающий решение о выборе того или иного устройства постоянного хранения информации, мог понимать, какое воздействие он может оказать на тестируемую систему и какие процессы при этом происходят, по каким критериям можно произвести оценку и как осуществить финальный выбор. Разумеется, многое из рассказанного можно подвергнуть критике и дополнить. Любым аргументированным возражениям — зеленый свет. Жду в комментарии.
❯ Немного истории
Прежде чем начать что-то тестировать, необходимо изучить, что же такое Flash-память, как она работает, какие есть слабые стороны и по каким критериям можно было бы оценить качество и производительность этого вида памяти.
Давайте попутно узнаем, почему данная память вообще называется Flash. Для начала нам придется обратиться к истории создания данного типа памяти. Первые попытки создать устройство хранения информации на транзисторах привели к изобретению ультрафиолетово-стираемых постоянных запоминающих устройств, так же называемых EPROM (англ. Erasable Programmable Read Only Memory). Данный тип памяти легко узнаваем по прозрачному окошку из кварцевого стекла в верхней части корпуса, через которое виден сам кремниевый чип и через которое производится облучение ультрафиолетовым светом во время стирания. А для защиты от случайной засветки чипа это окно закрывается специальной непрозрачной наклейкой.
Выглядят такие чипы вот так:
Запись на устройство осуществлялось с использованием специального программатора. Например, при помощи вот такого:
Стирание информации с EPROM было возможно только при использовании сильного источника ультрафиолетового света (например, от ртутного источника света).
Например, вот такого:
Процедура стирания напомнила его изобретателю, инженеру из Toshiba Сёдзи Ариидзуми простую фотовспышку (англ. Flash) и это название надежно закрепилось как устойчивое обозначение данного вида энергонезависимой памяти. Но стоит отдать должное изобретателю EPROM Дову Фроманому, инженеру из Intel, который запатентовал эту технологию хранения данных еще в далеком 1971 году.
❯ Технология хранения данных
В то же время был изобретен тип памяти и с электрическим способом стирания данных EEPROM, который приблизил появление распространенных на сегодня способов хранения информации, обеспечив более простую процедуру стирания данных из памяти.
Давайте рассмотрим, каким же образом данные сохраняются в Flash-памяти. Основным компонентом каждого из видов Flash памяти является т. н. транзистор FGMOS т. е. MOSFET с плавающим затвором. В отличии от обычного MOSFET, у него есть дополнительный затвор (плавающий), расположенный между управляющим затвором и p-слоем.
Особенность плавающего затвора заключается в том, что он полностью изолирован слоями диэлектрика и хранимый в нем отрицательный заряд, который туда можно поместить — может оставаться в нем достаточно долго.
Выглядит эта конструкция следующим образом:
Изменение заряда в плавающем затворе (т. е. процесс «запись» и «стирание») производится приложением между управляющим затвором и истоком определенного напряжения, чтобы возник туннельный эффект. При этом для усиления данного эффекта дополнительно пропускается ток через канал самого этого транзистора (т. н. явление инжекции горячих носителей). И когда напряжение снимается, электроны оказываются запертыми между барьерами диэлектрика и накопленный заряд не может утечь и хранится там в течение очень долгого времени.
Чтение выполняется же через полевой транзистор лежащим в основании, для которого плавающий затвор выполняет функцию основного затвора и протекание тока или его отсутствие уже детектируется соответствующими цепями чтения.
❯ NOR Flash
Термин Flash объединяет под собой несколько технологий, которые реализуют конечные продукты со своими характерными особенностями. Первый отличительный признак, который является ключевым — это способ выстраивания ячеек памяти на уровне транзисторной логики. Наиболее распространены два типа — NOR и NAND, они в некотором роде напоминают соответствующие логические элементы.
Существуют еще гибридные версии NOR и NAND технологий, такие как DINOR и SuperAND. Первая предложена компанией Mitsubishi и основной принцип заключается в том, что подбитовые линии состоят из поликремния и за счет этого происходит снижение рассеиваемой мощности и увеличение скорости передачи данных. А вторая архитектура, SuperAND просто сочетает в себе программируемые одноэлементные Flash-ячейки с управлением памятью, устраняя необходимость в механизмах коррекции ошибок и алгоритмах управления памятью. Думаю, вы можете сами потом ознакомиться с ними поискав самостоятельно информацию по названию этих технологий.
Для NOR-структуры характерно параллельное подключение всех ячеек к линии битов. При подаче логической единицы на управляющий затвор подсоединенных к линии битов, она переходит в состояние логического нуля, что соответствует логической операции ИЛИ-НЕ. А выбор ячеек в режиме чтения осуществляется с помощью линии слов. То есть в итоге получается классическая матрица строк и столбцов, в пересечении которых находятся ячейки.
Подключение ячейки NOR выглядит следующим образом:
NOR-память имеет несколько характерных особенностей, отличающих ее от NAND-памяти. NOR-память позволяет на очень высокой скорости получать доступ к произвольной ячейке памяти без использования последовательного чтения больших блоков информации. Память NOR может обращаться к данным размером до одного байта и это имеет решающее значение в ситуации, когда необходимо изменять данные мелкими порциями. За счет этого NOR-память имеет более высокую надежность, но это влияет на плотность размещения транзисторов на единицу площади, которая значительно ниже, чем у NAND, что в конечном итоге влияет и на размер и на стоимость такой памяти. Поэтому память NOR-типа применяется чаще всего в высоконадежных системах, где важна стабильность и долговечность но не критическим является вопрос объема этой самой памяти.
Стоит дополнительно отметить, что скорость доступа к ячейке NOR на чтение значительно выше, чем у NAND, и занимает десятки наносекунд, тогда как для NAND эта операция занимает десятки микросекунд.
❯ NAND Flash
Рассмотрим способ организации памяти NAND. В основе структуры NAND лежит принцип последовательного соединения элементарных ячеек, вместо того, как это было организовано в NOR, где используется только одна ячейка. Таким образом получается трехмерный массив с усложненной схемой доступа. И как вы можете заметить, обращение к отдельным ячейкам памяти невозможно и чтение происходит сразу всей группой ячеек.
В данной схеме добавлено два МОП-транзистора, первый является управляющим транзистором линии выборки (bit line select transistor), и второй управляющий транзистор включения к общему контакту (ground select transistor).
Сама структура ячеек NAND выглядит вот так:
Теперь рассмотрим как организуется чтение и запись данных в каждую ячейку при такой организации памяти.
-
Одна линия битов соответствует ряду ячеек памяти;
-
Если хотя бы один из транзисторов закрыт, то на линии битов будет высокое напряжение. Низкий уровень будет только если вся цепочка транзисторов окажется открытой;
-
Есть четкое разделение уровня напряжения для открытия транзисторов и изменения состояния плавающего затвора;
-
Для чтения отдельной ячейки не интересующие нас транзисторы открываются без изменения состояния плавающего затвора и производится считывание необходимой ячейки.
Именно такая компоновка ячеек памяти позволила существенно увеличить объем размещаемых элементов на единицу площади. Разумеется, данный способ организация памяти значительно сложнее и все же сказывается на скорости доступа к ячейкам памяти, но поскольку основной вектор развития устройств хранения состоит в наращивании объема хранимых данных — NAND вариант остался более предпочтительным. Продолжим его рассмотрение более подробно.
❯ SLC, MLC, TLC, QLC и PLC
Для увеличения плотности хранимой информации и общей емкости NAND-памяти разрабатывались различные ухищрения. Одним из таких ухищрений было решение добавить вариативность в уровнях заряда, который помещался в ячейку, чтобы кодировать не только 0 и 1, через наличие или отсутствие заряда, а еще и ранжировать его уровни.
В итоге получилось создать несколько видов памяти, которые имеют свои плюсы и минусы:
-
SLC (Single-Level Cell). Одноуровневая ячейка, хранит 1 бит на ячейку. Самая дорогая, самая надежная и долговечная технология организации ячейки памяти. Каждая ячейка может выдерживать до 100000 циклов записи/стирания.
-
pseudo-SLC (pseudo Single-Level Cell). Многоуровневая ячейка MLC, но работает в режиме SLC. Хранит 1 бит на ячейку. Имеет несколько сниженный ценник, и соответственно уступает по надежности и сроку жизни SLC.
-
MLC (Multi-Level Cell). Альтернатива SLC, то есть многоуровневая ячейка. Ее отличительная особенность состоит в том, что сама ячейка MLC является аналоговым запоминающим устройством, а не цифровым. То есть происходит сохранение определенного уровня заряда, а не битов. Поместив на плавающий затвор точное количество заряда можно запрограммировать два бита данных на одной ячейке. После отслеживая уровень тока, можно четко определить каждое из четырех состояний, которое соответствует одному из двухбитных сочетаний 11, 10, 01, 00. Имеет среднюю стоимость, с средним сроком жизни, но продолжает при этом оставаться достаточно надежной для типовых применений. Каждая ячейка может выдерживать до 10000 циклов записи/стирания.
-
TLC (Triple-Level Cell или 3bit MLC/MLC-3). Трехуровневая ячейка, которая хранит 3 бита информации и может нести 8 уровней заряда. Имеет низкую цену, и такую же надежность. Срок жизни тоже относительно не велик. Каждая ячейка может выдерживать до 3000 циклов записи/стирания.
-
QCL (Quad-Level Cell или 16LC). Четырёхъярусная ячейка, которая хранит 4 бита информации или 16 уровней на ячейку. Самая дешевая и ненадежная форма организации ячейки с относительно быстрым износом. Каждая ячейка может выдерживать до 1000 циклов записи/стирания.
-
PLC (Penta-level Cell). Перспективная, пятиуровневая ячейка, хранящая 5 бит информации, которая насколько мне известно, на момент написания этой статьи, еще не применялась в массовых продуктах.
Можно сделать очевидные выводы:
-
Память MLC имеет меньшее количество циклов перезаписи по сравнению с SLC;
-
SLC память будет быстрее, то есть базовые операции будут выполняться быстрее и итоговая производительность будет выше;
-
В SLC памяти используется только одно пороговое значение напряжения и вероятность возникновения проблем значительно ниже.
Понимая это, можно сделать однозначный вывод о том, что SLC-память будет надежнее и общий ресурс будет больше чем у MLC. Но по цене SLC-память будет значительно дороже и с меньшим объемом памяти и с увеличением разрядности — сложность сохранения точного заряда повышается и износ у более сложных ячеек гораздо более быстрый.
❯ 3D NAND
На этом оптимизации и улучшения не закончились. Раньше большая часть производимых чипов памяти Flash изготавливалось на одной подложке, на основе плоских однослойных структур с ячейками памяти. Но после того как был освоен техпроцесс изготовления транзисторов меньше 20 нм появились новые технологические проблемы и вызовы, которые существенно снижали надежность NAND-памяти. Одна из проблем заключалась в том, что при техпроцессе ниже 20 нм ячейки получаются настолько малые, что заряд который обеспечивает хранение информации, начинает беспрепятственно перетекать из одной ячейки памяти в другую.
После была разработана новая технология физической компоновки элементов памяти, но уже не по горизонтали, а по вертикали. Что же представляет собой трехмерная ячейка памяти 3D NAND. Обратите внимание на изображение:
Трехмерная ячейка 3D NAND представляет собой цилиндр, внешний слой которого является управляющим затвором, а внутренний — изолятором. Между внешним и внутренним слоями находится слой хранящий биты информации. Такие ячейки хранятся послойно и формируют стек.
Это позволило увеличить количество хранимой информации на единицу площади и увеличить надежность хранения информации от 2 до 10 раз. После этого перед инженерами появлялось очень много задач связанных с увеличением емкости Flash-памяти, оптимизации их энергопотребления, появлялись новые инженерные решения, различные типы внутренней компоновки ячеек памяти, уменьшение их размера и т. д. Тему развития технологии хранения мы оставим в стороне, достаточно много материалов есть в свободном доступе. Мы же перейдем к рассмотрению вопросов внутреннего устройства NAND-памяти.
❯ Структура NAND
А теперь стоит рассмотреть организационную структуру памяти NAND более подробно. Память NAND может состоять из нескольких отдельных компонентов:
-
Ячейка. Наименьший элемент Flash-памяти, который как раз и хранит в себе данные на уровне битов. Она не доступна для атомарных операций чтения и записи.
-
Страница. Это некоторый массив ячеек, которые можно стереть или считать.
-
Блок. Это массив страниц, который можно адресовать для операций удаления данных. Обычно составляет несколько единиц мегабайт.
-
Кристаллы. Отдельные физические микросхемы, которые упакованы в один корпус микросхемы с объединением сигналов питания и управления. Выглядит так, как будто несколько отдельных микросхем просто соединили параллельно и поместили в один корпус.
-
Контроллер. Отдельная часть микросхемы которая управляет логикой взаимодействия, используя которую можно проводить целевые операции и которая обеспечивает необходимый интерфейс для доступа внешним устройствам и для доступа к массиву ячеек.
❯ Операции записи и чтения, стирания блоков
Рассмотрим, что из себя представляют базовые операции. Итак, простейшая запись или чтение данных происходит на уровне страницы, и представляет собой инверсию битов из состояния по умолчанию т. е. из 1 в 0. Важная особенность. Каждая страница в блоке может быть записана только один раз. Для повторного программирования страницы необходимо стереть полностью весь блок.
Для осуществления массового удаления данных производятся операции на уровне блоков. При этом нельзя стереть только часть блока. Операция стирания выполняется намного медленнее, чем операции записи или чтения, которые выполняются на уровне страниц.
Когда блок больше не может использоваться для хранения данных — он помечается как «плохой» (bad block). Блоки изнашиваются по мере их стирания и в каждой Flash-памяти имеется специальный счетчик стирания блоков, который можно считать с помощью специальных утилит.
Никаких особых хитростей тут нет. Идём дальше.
❯ Основные проблемы в эксплуатации
Рассмотрим основные проблемы, которые возникают при эксплуатации Flash-памяти. Первоочередная проблема при эксплуатации — это ограниченный срок службы ячеек памяти, который исчисляется в количестве циклов записи/стирания. К счастью процесс чтения не оказывает такого большого влияния на общий ресурс, но об этом ниже.
Следующая причина деградации ячеек памяти — это отсутствие возможности индивидуально контролировать заряд плавающего затвора в каждой ячейке. Поскольку запись и стирание производится над целыми группами ячеек одновременно, то автомат записи контролирует пороговые значения инжекции зарядов по референсным ячейкам или по средней величине. И постепенно, по мере эксплуатации, уровни заряда рассогласуются и выходят за пределы нормы, которые могут быть скомпенсированы автоматом записи. И по сути ячейки выводятся из оборота из-за того, что изменяется степень их идентичности. И к сожалению, по мере уменьшения топологии полупроводников, все сложнее создавать идентичные элементы с одинаковыми характеристиками.
Ещё одна причина износа — это постепенная взаимная диффузия атомов, из которых состоят изолятор и проводник, которая ускоряется градиентом электрического поля в области кармана и периодическими электрическими пробоями изолятора при записи и стирании. По итогу получается размывание границ и ухудшению уровня изоляции и как следствие приводит к уменьшению времени хранения заряда.
Помимо чисто физических причин, есть особенности и определенные правила эксплуатации Flash-памяти, которые могут ускорить деградацию ячеек памяти. В самых дешевых вариантах NAND-памяти нередки ситуации, когда отдельный блок постоянно стирается и записывается, и соответственно быстро изнашивается. В более продвинутых вариантах NAND-памяти есть специальные механизмы оптимизации износа, мониторинга записи и перераспределения данных по физическим ячейкам таким образом, чтобы износ проходил равномерно. Также при производстве закладывается некоторый объем резервной памяти, которая может быть использована при перераспределении.
Помимо этого можно отметить еще некоторые особенности которые могут выявляться с течением времени:
-
Заряд с плавающего затвора может «утекать» со временем. Это называется программная межъячеечная интерференция. Она может привести к нарушению целостности данных в т. ч. при записи данных. Т.е. чем дольше хранятся данные, тем меньше вероятность их считать без ошибок. Как раз эта проблема пока стоит барьером на пути миниатюризации ячеек памяти.
-
Имеется разброс в характеристиках транзисторов для организации ячеек и при записи одинакового логического уровня есть вероятность прочитать неверные данные из-за разницы по величине заряда. То же касается операции чтения. Как правило эти ситуации маловероятны, но их стоит держать в голове в ситуациях когда при валидной записи NAND начинает давать ошибки при последующем чтении.
Теперь рассмотрим ошибки, которые чаще всего возникают при работе с памятью NAND.
❯ Ошибки чтения Read Distrib Error
Поскольку память NAND организована блочным способом и для определения бит которые хранятся в конкретной ячейке используется определение уровня заряда — считывание данных с дефектных блоков становится не такой простой задачей, как например в NOR, где можно вычитать каждую ячейку отдельно.
Причиной возникновения этой ошибки является операция чтения. Расскажу подробнее о механике возникновения этой ошибки. Напряжение считывания изначально выше максимально возможного порогового значения напряжения, но оно значительно ниже напряжения, которое необходимо для перепрограммирования или стирания ячейки. Поскольку при считывании опорное напряжение подается на страницу целиком, то при произведении операции считывания остаются отдельные ячейки которые остаются неактивными. После считывания нужных данных это напряжение снимается, но при выполнении операции оно уже оказало влияние на близлежащие ячейки из которых не производилось чтения и уровень порогового напряжения изменяется, хоть и незначительно.
После одного чтения конечно же ничего не изменяется, но вот после нескольких миллионов чтений — да, и величина отклонения неуклонно повышается. То есть получается, что происходит искажение бита на каждые 10^5 - 10^6 чтений страницы для памяти NAND типа MLC, изготовленной с применением 16-нм техпроцесса. Соответственно с увеличением разрядности ячеек растет и частота возникновения ошибки.
Основные методы решения проблемы — исправление данных при помощи алгоритмов ECC, либо перенос блока в другое место. Но стоит помнить, что перенос — это операция стирания/записи и ресурс ячеек тут тоже не бесконечен.
❯ Ошибка записи Program Distrib Error
Суть этой ошибки в чем-то схожа с рассмотренной выше. Отличие лишь в том, что при записи используется напряжение заметно большее, чем при чтении и за счет паразитных емкостных связей между элементами осуществляется воздействие и на соседние ячейки.
Этот эффект проявляется тем сильнее, чем меньше техпроцесс, который использовался для изготовления NAND.
Основной метод решения проблемы — простой перенос блока.
❯ Ошибка перепрограммирования Over-Programming Error
Ситуация возникает в случае, если при перепрограммировании страниц пороговое напряжение в соседних ячейках, находящихся в том же блоке, но не участвующих в операции изменения данных становится слишком высоким, т.е. не соответствующим исходным заданным значениям. Чаще всего это происходит с ячейками, в которых после стирания по каким-либо причинам сохраняется слишком высокое исходное напряжение. Такое чаще всего случается с ячейками у которых уже практически выработан ресурс.
Основной метод решения проблемы — простой перенос блока.
❯ Ошибка удержания заряда Retention Error
Данные в ячейках склонны к повреждению с течением времени и это, как правило, связано с падением уровня напряжения в плавающем затворе. Чем более изношенной является ячейка, тем более интенсивно происходит утечка заряда из плавающего затвора через слой изолятора, который при каждом цикле записи/стирания изнашивается.
Длительное нахождение ячеек в отключенном состоянии, повышенная температура, увеличение битности на каждую ячейку (MLC, TLC, QLC), уменьшение техпроцесса, уменьшение изолирующего слоя — все это ускоряет данный процесс.
Основной метод решения проблемы — регулярное использование накопителя и регулярная перезапись данных из одного блока в другой.
❯ «Плохие» блоки
Рассмотрим подробнее вопрос, касающийся «плохих» блоков в Raw NAND Flash. Данные блоки могут быть как в новых микросхемах в некотором объеме, который обычный оговаривается производителем так и могут появляться в ходе эксплуатации. Каждый из таких блоков маркируется контроллером в специальной Spare Area. Данные о плохих блоках как правило можно вычитать из Flash.
Нужно иметь ввиду, что в Raw NAND Flash (то есть не в eMMC) информация о маркерах плохих блоков помещается в обычные ячейки Flash-памяти Spare Area, которые также стираются при стирании всего блока памяти. Поэтому для сохранения информации перед стиранием, эта информация должна быть где-то сохранена отдельно.
Существует несколько наиболее распространенных способа обработки плохих блоков:
-
Пропуск «плохих» блоков. При записи анализируется в какой блок осуществляется запись и если он помечен как «плохой» — запись производится в следующий после «плохого».
-
Резервирование блоков. В этом случае память микросхемы делится на три части: User Block Area — пользовательская область, Block Reservoir — резервные блоки и таблицу соответствия плохих блоков хорошим. При выявлении плохого блока данные из User Block Area переносятся в Block Reservoir и в таблицу делается соответствующая запись о замене.
-
Контроль и коррекция ошибок. Даже в случаях когда блоки еще не изношены — бывают ситуации когда биты могут быть случайным образом перевернуты, что в целом приводит к повреждению сохраненных данных. Для осуществления проверки корректности записанных данных могут применяться алгоритмы контроля и коррекции ошибок (Error Checking and Correction — ECC). Эта информация, как правило, сохраняется в свободное пространство Spare Area.
❯ Что такое eMMC?
Теперь обратимся к устройству хранения, которое оснащено собственными внутренними механизмами оптимизации износа. Таким устройством является память eMMC. Аббревиатура eMMC означает Embedded Multimedia Memory Card или «встроенная мультимедийная карта памяти». Для применения во встраиваемых и портативных системах был придуман прибор, который позволял совместить в рамках одного чипа и контроллер и массив ячеек. По сути вся накладная функциональность для управления данными, мониторинга записанных и стертых блоков, выравнивания и перераспределения «плохих» блоков была вынесена во встроенный контроллер.
Каждая eMMC состоит как минимум из трех компонентов – интерфейса для взаимодействия с хост-системой, массива Flash-памяти и контроллера и как правило предлагается в стандартном для отрасли корпусе BGA (Ball Grid Array). Помимо этого, в соответствии со стандартом eMMC JEDEC, все микросхемы имеют целый ряд служебных регистров которые позволяют получать массу полезной информации о состоянии памяти.
Использование eMMC обеспечивает дополнительный уровень абстракции от управления процессами выравнивания, менеджмента «плохих» блоков и прочих служебных операций и можно без опасений использовать файловую систему, которая рассчитана на работу с блочными устройствами, например EXT4.
❯ Служебные регистры eMMC
Стандарт eMMC определяет некоторый набор служебных регистров, которые могут считаны из контроллера и обеспечивают возможность своевременного информирования пользователя о состоянии памяти. Наибольший интерес представляет регистр EXT_CSD, через который можно получить много интересного:
-
встроенный в контроллер отчет о работоспособности памяти, в котором могут быть реализованы счетчики ошибочных блоков и количества стираний блоков;
-
оценка срока службы устройства тип А, которая вычисляет состояние работоспособности с шагом в 10%, как правило относится к SLC-типу памяти;
-
оценка срока службы устройства тип B, которая вычисляет состояние работоспособности с шагом в 10%, как правило относится к MLC-типу памяти;
-
pre-EOL info, показывает процент задействованных резервных блоков, которые введены в использование взамен выведенным из строя.
❯ Работоспособность и ресурс Flash-памяти
Общая оценка работоспособности определяется процентом емкости Flash-памяти, которая помечена как «плохая» и выведена из использования. Поэтому, чтобы оценить общий ресурс Flash-памяти — можно посчитать значение в виде общего количества стираний или общего количества данных, которые могут быть записаны и стерты на устройстве.
Приведу формулы с помощью которых можно произвести соответствующую оценку. Чтобы оценить количество циклов стирания:
E — итоговое количество циклов стирания;
B — количество блоков;
L — средняя продолжительность жизни блока, выраженная в количестве стираний;
E — итоговый объем данных, которые могут быть записаны на Flash-память;
S — размер блока в байтах;
B — количество блоков;
L — средняя продолжительность жизни блока, выраженная в количестве стираний;
В этом случае общее количество циклов стирания является более точным, потому что итоговый износ блоков происходит именно после стирания блоков, а не после записи некоторого количества данных. Стоит конечно же отметить еще влияние температуры на срок работы памяти.
❯ Мониторинг состояния eMMC памяти в Linux
Поскольку данная статья предназначена разработчикам и тестировщикам которые работают со встраиваемыми системами на основе Embedded Linux — то рассмотрим основные средства мониторинга метрик работоспособности Flash-памяти в Linux.
Первым и основным источником информации о состоянии здоровья eMMC — информация из служебных регистров контроллера. Самый подходящий инструмент для получения данной информации — утилиты, которые предоставляет производитель или open-source набор утилит mmc-utils https://github.com/mhei/mmc-utils. Эти утилиты как правило реализуют большую часть протокольных функций, включая чтение данных из служебных регистров, таких как EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A, EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B, EXT_CSD_PRE_EOL_INFO.
На основании информации из этих регистров можно узнать срок службы устройства, как это определено в стандарте JEDEC eMMC. В первую очередь посмотрим, какая версия протокола у нас используется для реализации интерфейса:
root@zynq-7000:/bin# mmc extcsd read/dev/mmcblk1
=============================================
Extended CSD rev 1.7(MMC 5.0)
=============================================
Информация показывает, что мы имеем дело с eMMC, которая соответствует стандарту JEDEC 5.0. После можно сделать фильтрацию вывода и получить информацию о работоспособности:
root@zynq-7000:/bin# mmc extcsd read/dev/mmcblk1 | grep LIFE
Device lifetime estimation type B [DEVICE_LIFE_TIME_EST_TYP_B: 0x01]
Device lifetime estimation type A [DEVICE_LIFE_TIME_EST_TYP_A: 0x01]
eMMC Life Time Estimation B [EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]: 0x01
eMMC Life Time Estimation A [EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]: 0x01
root@zynq-7000:/bin# mmc extcsd read/dev/mmcblk1 | grep EOL
Pre EOL information [PRE_EOL_INFO: 0x01]
eMMC Pre EOL information [EXT_CSD_PRE_EOL_INFO]: 0x01
В даташите на каждую из моделей eMMC можно найти таблицу для расшифровки значений из этих регистров. Но чаще всего она имеет следующий вид:
Следовательно — можно сказать, что данная Flash-карта новая и с нормальным состоянием по всем метрикам.
Отдельно обращаю ваше внимание, что часть полезной информации, например счетчик bad-блоков, или количество стертых блоков могут быть не отображены при использовании стандартных утилит и доступны при чтении регистра EXT_CSD утилитой, которую должен предоставить вендор eMMC.
Иногда драйвер eMMC предоставляет возможность вычитать информацию о состоянии «здоровья» памяти из древа sysfs:
root@zynq-7000:/bin# cat /sys/class/mmc_host/mmc0/mmc0:0001/pre_eol_info
root@zynq-7000:/bin# cat /sys/class/mmc_host/mmc0/mmc0:0001/life_time
❯ Мониторинг ввода/вывода
Для того, чтобы спрогнозировать вероятную дату выхода из строя — необходимо понимать какие приложения записывают слишком много данных. Конечно, лучший способ использования Flash-памяти во встраиваемых системах — это смонтировать системный раздел в read-only режиме и все манипуляции с файлами и прочими данными делать при использовании RAM-FS диска, который будет работать с использованием оперативной памяти.
Вернемся к вопросу оценки потенциального времени выхода Flash-памяти из строя, и рассмотрим в самых общих чертах каким образом организован стек ввода/вывода в Linux. Тот или иной процесс может обращаться к ядру на выполнение файловых операций. То, как выполняются эти операции варьируется в зависимости от используемой библиотеки, языка программирования, но в какой-то момент происходит переход от user space к kernel space. Это тот самый момент, когда функции той или иной библиотеки будут выполнять системные вызовы ядра. После этого ядро Linux работает с этим вызовом через стек ввод/вывода и отправляет данные на устройство хранения через низкоуровневый драйвер, будь то Block Device драйвер или MTD-драйвер, в зависимости от типа Flash-памяти (Raw NAND, eMMC, etc.).
При таком рассмотрении устройства стека ввода/вывода можно подумать, что наблюдение за интенсивностью записи на Flash-памяти с течением времени может сделано из user space, но на самом деле получаемые данные получатся недостаточно точными.
Поскольку в ядре Linux реализован свой планировщик ввода/вывода, который управляет очередью запроса ввода/вывода и пытается максимизировать по своим алгоритмам производительность ввода/вывода, реализуя разнообразные слои кешей, буферов и прочего — очевидно, что любые действия с данными в ОС совсем не обязательно будут приводить к операциям с Flash-памятью.
Для того, чтобы мониторить операции ввода/вывода в user space — я для себя определил как лучшую утилиту iotop и blktrace/blkparse. Тут конечно есть другие утилиты и средства, которые можно использовать для трассировки ввода/вывода. Но остановимся на рассмотрении только iotop, blkparse и blktrace.
Для начала сделаем файл, который будем записывать на Flash-память:
root@zynq-7000:/bin# dd if=/dev/urandom bs=4k count=100000 | pv -L 25k> testfile
Для анализа процесса записи, счетчиков записи и процессов ответственных за запись используем утилиту iotop:
root@zynq-7000:/bin# iotop --only --batch --accumulated --kilobytes --time–quiet
Для того, чтобы проанализировать каждую операцию обратимся к трассировщику операций blktrace и отфильтруем из с помощью blktrace:
root@zynq-7000:/bin# blktrace -o - /dev/mmcblk1 | blkparse -i -
Помимо в blktrace и blkparse реализовано большое количество фильтров, которые облегчают анализ и работу с получаемой информацией. Подробнее можно ознакомиться в мануалах и туториалах.
❯ Оценка продолжительности жизни Flash-памяти (eMMC)
Еще один вариант для оценки общего ресурса памяти — это выделить несколько устройств (чем больше — тем более репрезентативная картина получится), произвести длительный процесс записи данных на Flash-память и отслеживать состояние памяти через служебные регистры. Чем больше устройств будет задействовано в этом тесте — тем более точные данные о средней картине насчёт конкретной модели Flash будут получены в итоге.
Чтобы провести данный тест рекомендуется подготовить:
-
Sideload версию Linux, которая загружается в RAMFS и функционирует полностью из оперативной памяти;
-
Утилиту stressdisk https://github.com/ncw/stressdisk. Позволяет циклически генерировать файлы записывая их на eMMC. При этом возможна генерация файлов различных размеров. Программа после записи проводит их проверку и выдает статистику по скорости чтения/записи.
-
Утилиту iostat, которая будет показывать статистику по операциям чтения/записи.
-
Утилиту mmc из состава mmc-utils, для вычитывания служебных регистров EXT_CSD, по информации из которых мы будем судить о текущем уровне «здоровья» eMMC.
Для итоговой оценки предлагается заполнить такую таблицу по каждому из исследуемых устройств:
Прежде чем начать какое-либо тестирование нужно помнить несколько важных моментов. Поскольку у каждой eMMC есть свой контроллер, который определяет каким образом будет осуществляться выравнивание износа блоков — то не нужно будет писать данные на весь объем памяти eMMC т.е. с начала адресного пространства до конца, а достаточно просто циклически записывать и стирать данные. В случае если выравнивание износа работает плохо — достаточно быстро можно будет увидеть эту проблему.
Второй важный момент — исчерпание резервных блоков и оценка контроллером может производиться исключительно на основании счетчика стертых/записанных блоков и служебный регистр может вам о том, что «здоровье» eMMC исчерпано, хотя на самом деле до реальных ошибок записи/чтения еще останется многие десятки терабайт, т.е. необходимо проводить тест до действительного выхода Flash-памяти из строя.
Общий смысл теста заключается в том, чтобы запустить процесс записи/стирания данных на Flash и по окончании каждой итерации теста выводить статистику из служебного регистра eMCC. Предлагаю общую концепцию и алгоритм теста, думаю скрипт для его автоматизации сможете подготовить самостоятельно:
-
Загрузить Sideload Linux на тестируемое устройство;
-
Загрузить все необходимые утилиты на устройство;
-
Проверить, что все утилиты функционируют нормально:
-
iostat -m — выводит статистику по использованию блочных устройств;
-
df -m — выводит статистику об использованном свободном месте на Flash-устройстве;
-
mmc extcsd read /dev/mmcblk0 — выведет содержимое регистра EXT_CSD;
-
-
Проверяем, смонтировано ли нужное блочное устройство;
-
Проверяем, что текущие счетчики Health Report Counter равны значениям «здоровой» Flash-памяти;
-
Запускаем в фоне утилиту stressdisk -s 1000 cycle /mnt/mmcblk0 &
-
Запускаем отображение статистики для сбора логов: watch -n10 'iostat -m --pretty --human; echo EOL registers:; mmc extcsd read /dev/mmcblk0 | grep -A2 EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A; echo; df -m /mnt/mmcblk0';
-
Наблюдаем за значениями регистров по мере износа eMMC. По мере износа счётчики будут увеличиваться. В среднем это происходит после многих единиц или десятков терабайт непрерывной записистирания блоков (но также зависит от объема eMMC).
После проведения теста и появления ошибок записи на Flash-карту у вас будет лог, в котором понятно будет количество итераций, которые были осуществлены и значения TWB (Total Write Bytes), которые приводили к инкременту счетчиков.
❯ Оценка продолжительности жизни Flash-памяти (Raw NAND)
Принцип проверки памяти Raw NAND не сильно отличается от проверки eMMC за исключением того, что подсчетом bad-блоков придется заниматься самостоятельно. Большая часть функциональности связанная с управлением «плохими» блоками в этом случае отходит к драйверу MTD который встроен в ядро Linux.
Для тестирования NAND на ресурс подходит две утилиты. Расскажу про каждую отдельно. Первая утилита nandwrite. Алгоритм тестирования следующий:
-
Загрузить Sideload Linux на тестируемое устройство;
-
Загрузить все необходимые утилиты на устройство;
-
Запускаем скрипт, который производит операции записи и стирания:
#!/bin/sh
i=1
while [ $i > 0 ]
do
echo "########################################"
echo " "
echo "Iteration: $i: "
echo " "
echo "########################################"
echo "Uptime start dd command: "; cat /proc/uptime;
dd if=/dev/urandom | nandwrite /dev/mtd2
cat /sys/class/mtd/mtd*/bad_blocks
sleep 3
i=$(( $i + 1 ))
echo "########################################"
done
-
Если требуется остановка теста после возникновения первого bad-блока можно использовать другой скрипт:
#!/bin/sh
i=1
while [ $i > 0 ]
do
echo "########################################"
echo " "
echo "Iteration: $i: "
echo " "
echo "########################################"
echo "Uptime start dd command: "; cat /proc/uptime;
sleep 1
dd if=/dev/urandom | nandwrite -m /dev/mtd2
cat /sys/class/mtd/mtd*/bad_blocks
sleep 1
i=$(( $i + 1 ))
echo "########################################"
done
-
Далее после появления первого или нового bad-блока фиксируется номер итерации и объем записанных данных.
-
Перезапускаем тест и наблюдаем за количеством итераций, после которой появляется следующий bad-блок.
-
Повторяем п.6 и высчитываем средний объем данных после которого появляется новый bad-блок.
-
Считаем количество итераций через которое будет превышено критическое значение bad-блоков (из datasheet) и NAND считается не пригодным к использованию.
-
Суммируем: объем записанных данных за первую итерацию + (объем данных второй итерации * количество bad-блоков после которой NAND признается неработоспособным) = общий ресурс NAND
-
Выносим вердикт — является ли такой объем данных достаточным.
Есть вторая утилита, которая подходит для тестирования Raw NAND — nandtest. Алгоритм тестирования похож на nandwrite и выглядит следующим образом:
-
Загрузить Sideload Linux на тестируемое устройство;
-
Загрузить все необходимые утилиты на устройство;
-
Запускаем утилиту nandtest в нужном режиме:
# Просто несколько циклов записи/чтения по целому разделу (bad-ы не помечаются)
nandtest --passes 100 --reads 2 /dev/mtd2 2>&1 | tee /tmp/nand_test.log
# Тест на износ (для nand-ов с размером erase block 128кБ параметр 0x80000 соответствует 4 блокам)
nandtest --passes 1000000 --reads 1 --offset 0 --length 0x80000 /dev/mtd2 2>&1 | tee /tmp/nand_test.log
# Если нужно помечать bad-блоки, то можно использовать параметр --markbad
-
Анализируем файл nand_test.log на наличие ошибок.
Таким вот нехитрым образом можно приблизительно оценить насколько долго прослужит выбранный чип памяти.
❯ Заключение
В заключение хотелось бы сказать, что данная информация лишь небольшой вводный фрагмент в понимании того, что такое Flash-память, как она работает и как организовать оценочное тестирование в ситуации, когда многое из того, что было доступно раньше пришлось заменить на китайские или иные аналоги, качество которых может оказаться непредсказуемым и как не оказаться в ситуации, когда выбранная память быстро выходит из строя и не соответствует ожиданиям.
На основании полученных знаний и результатах приведенных в статье тестов и собранной при их помощи информации можно сделать множество выводов о качестве работы: о том, какая скорость у выбранной Flash, каков ее реальный ресурс, как быстро она выйдет из строя, от чего она может выйти из строя, насколько качественно реализованы алгоритмы для оптимизации времени жизни массива ячеек и прочее. Если у вас есть, что дополнить к вышесказанному — добро пожаловать в комментарии и поделитесь тем, как вы тестируете Flash-память, будь то NAND или eMMC.
Спасибо за внимание.
Автор: megalloid