Оптимизируем SD-карту

2016-06-30

Не грусти

Ну что, дорогой читатель, тебя тоже задрали обещания высоких скоростей SD и microSD, однако на деле в твоем уютненьком Linux или Android или вообще на Windows всё, скажем так несколько медленнее, чем заявлено производителем.

Не переживай, и не сокрушайся - скорее всего есть способ тебе помочь.

Немного теории

Несмотря на то, что карта в системе видится, как “диск”, данные при записи на флеш пишутся немного по-другому.

Запись организована так называемыми erase-блоками или просто блоками. Блоки имеют определенный размер, в зависимости от размера твоих… флешек.
Для того, чтобы провести запись на диск, приходится стирать не определенный набор секторов, как на диске, а целый блок. Точнее, он не “стирается” физически, а лишь помечается стёртым.

Трансляция из “секторов и дорожек” выполняется “на лету” контроллером и операционной системой.

Короче, всё сложно.

И то, что у тебя SD/microSD “тормозит” - еще не значит что всё плохо. Вполне может быть, что партиции и служебная информация расположены на границах блоков и устройство “напрягается” из-за дополнительных действий. Ну или для записи приходится писать не в один блок, а в два.

Рецепт нулевой-самый простой случай

Если не нужна какая-то специфическая файловая система на SD, постарайся НЕ форматировать её ни в кард-ридере, ни в устройстве. Просто купи, вставь и пользуйся. Кстати никто не запрещает даже обратиться с претензией к продавцу в случае проблем.

Рецепт первый-если ты всё-таки отформатировал карту

Такое, конечно, бывает. И часто. Скорее всего ты нажал кнопочку “очистить карту” или вообще отформатировал её в Windows штатными средствами.

Что произошло

Ты снёс вендоровский FAT (от производителя) и создал новый. Но он создался не совсем там, где был. Таким образом, “стройная система” была нарушена и теперь при записи фоточки любимого кота или себя любимого оно пишется не в один блок, а в два.

Как лечить

На этот случай есть довольно полезная программа для Windows - SDFormatter, которая располагается ни где-то там, а на сайте SD Association, то есть авторы - те самые парни, которые SD придумали и поддерживают.

SD Formatter

Внизу есть подпись “FORMAT SIZE ADJUSTMENT OFF”. Вот это нас и интересует - нужно эти самые оптимизации включить.

Достаточно пнуть кнопку “Option”.

SD Formatter options

И перевести из режима “OFF” в “ON”.

Правда, некоторые “картоводы”, особенно полученные нашару из поднебесной или купленные у хачей в ларьке могут отказаться работать с этой программой, так что прекратите пользоваться этим говном и купите себе хотя бы подобие более-менее брендового кардридера - пригодится.

После этой процедуры ситуация должна улучшиться.

Всё, что будет нашкрябано ниже - будет иметь отношение в основном к Linux. Так что если ваш Инстаграмм ждет новых фоточек - пиздуйте его кормить, красноглазикам же и любителям выпуков post-PC эры (Orange Pi, Raspberry Pi) - нижеизложенное будет полезно.

Рецепт второй-оптимизируем для Linux (простой путь)

Покемоны вроде Raspberry Pi, Orange Pi, и прочие дроиды в массе своей грузятся с microSD, поэтому эта тема весьма актуальна.

Внимание, некоторое операции разрушают данные на вашей SD карте, так что сделайте с неё образ на всякий случай или любой другой бэкап, который осилите

Выше уже было про erase-блоки, короче, главная задача тут - расположить нашу партицию с данными ТАК, чтобы она попадала в аккурат в начало блока.

Перед этим нужно произвести некоторые замеры.

Я лично пользовался дешевой карточкой 10го класса от Silicon Power на 32ГБ. После оптимизации выросла скорость (не особо правда), НО резко уменьшилось latency при работе с кучей мелких файлов, что, в свою очередь помогло стабильности системы.

Silicon Power 32GB

В замерах нам поможет утилита flashbench, известная ещё со времен утопического проекта OLPC.

https://github.com/bradfa/flashbench

Придётся собирать - но там ничего сложного - всё как обычно: configure, make, make install. Впрочем make install даже не нужен - можно запускать с места сборки. Итак…

$ sudo ./flashbench -a /dev/sde --blocksize=1024

align 8589934592 pre 1.59ms on 2.01ms post 1.63ms diff 399µs

align 4294967296 pre 1.58ms on 2.01ms post 1.63ms diff 408µs

align 2147483648 pre 1.59ms on 2.06ms post 1.69ms diff 426µs

align 1073741824 pre 1.64ms on 2.09ms post 1.67ms diff 435µs

align 536870912 pre 1.55ms on 1.97ms post 1.59ms diff 397µs

align 268435456 pre 1.58ms on 1.99ms post 1.6ms diff 396µs

align 134217728 pre 1.63ms on 2.04ms post 1.67ms diff 389µs

align 67108864 pre 1.54ms on 1.95ms post 1.58ms diff 387µs

align 33554432 pre 1.62ms on 2.06ms post 1.64ms diff 428µs

align 16777216 pre 1.72ms on 2.13ms post 1.7ms diff 420µs

align 8388608 pre 1.69ms on 2.11ms post 1.7ms diff 411µs

align 4194304 pre 1.68ms on 2.15ms post 1.76ms diff 432µs

align 2097152 pre 1.65ms on 2.02ms post 1.69ms diff 354µs

align 1048576 pre 1.67ms on 2.04ms post 1.69ms diff 355µs

align 524288 pre 1.72ms on 2.08ms post 1.72ms diff 361µs

align 262144 pre 1.64ms on 2.04ms post 1.68ms diff 378µs

align 131072 pre 1.59ms on 1.96ms post 1.61ms diff 367µs

align 65536 pre 1.6ms on 1.98ms post 1.62ms diff 365µs

align 32768 pre 1.61ms on 2.02ms post 1.64ms diff 397µs

align 16384 pre 1.61ms on 1.99ms post 1.68ms diff 347µs

align 8192 pre 1.69ms on 2.04ms post 1.71ms diff 335µs

align 4096 pre 1.62ms on 2ms post 1.63ms diff 371µs

align 2048 pre 1.65ms on 1.66ms post 1.65ms diff 7.25µs

Утилита пытается работать с блоками разного размера и замеряет скорость работы, точнее время.

В этом потоке сознания нас будут интересовать точки с максимальным “выбросом”. Городская легенда (а точнее Gentoo Wiki) гласит, что по ним можно определить такие параметры, как:

  • Allocation group
  • Erase block
  • Multiplane
  • Page

Судя по картине, получаем такое:

Allocation group = 1GB Erase block = 4M Multiplane = 32K Page = 4K

На ваших SD цифры могут различаться, но принцип ясен.

Расчет параметров для утилиты fdisk, чтобы партиция попала в нужное место:

4*1024^2/512=8192

Для тех кто хреново учил информатику в школе - напомню, что операция ^ - возведение в степень в BASIC, и не только. И она имеет больший приоритет в математике (это для тех, кто прогулял математику).

512 - размер блока при работе с fdisk. Ниже пример создания партиции:

`Диск /dev/sde: 31.1 Гб, 31104958464 байт
255 головок, 63 секторов/треков, 3781 цилиндров, всего 60751872 секторов
Units = секторы of 1 * 512 = 512 bytes
Размер сектора (логического/физического): 512 байт / 512 байт
I/O size (minimum/optimal): 512 bytes / 512 bytes
Идентификатор диска: 0x000cb560

Устр-во Загр Начало Конец Блоки Id Система

Команда (m для справки): n
Partition type:
p primary (0 primary, 0 extended, 4 free)
e расширенный
Select (default p): p
Номер раздела (1-4, по умолчанию 1): 1
Первый сектор (2048-60751871, по умолчанию 2048): 8192`

Ну дальше просто - делаем нужный размер и вся недолга.

На самом деле, похоже, это ключевой момент для ускорения работы. Следующий рецепт конечно тоже добавляет “скорости”, но не так драматично.

But wait! А что, если у нас вначале диска должна быть какая-нибудь загрузочная запись или DOS-партиция, как в случае с AllWinner вообще и Orange Pi в частности ?

В этом случае нам нужно создавать партицию на расстоянии кратном erase-block. Так, если у вас свободное место начинается с 66 мегабайта, то создавать нужно соответственно на 68ом.

Следующий рецепт - тонкая настройка EXT4

Рецепт третий-оптимизируем для Linux (путь истинного красноглазика)

Собственно вернемся к оптимизации - было бы неплохо, если бы и EXT4 была выровненной.

Чтож, формула проста (смотри результаты предыдущего рецепта):

filesystem block = page stride = multi-plane access / page stripe-width = erase block / page

В нашем случае команда:

$ sudo mkfs.ext4 -O ^has_journal -E stride=8,stripe-width=1024 -b 4096 -L linuxroot /dev/sde1

По ощущениям предыдущий рецепт увеличивает скорость работы, а этот уменьшает тот самый latency.

Что ещё подправить в системе

Swap

Очевидно, оптимизацию swap, если он имеется в наличии.

Вот эту хрень:

echo 0 > /proc/sys/vm/swappiness

нужно прописать в rc.local ну или что там у вас. После этого свап будет “в работе”, только если исчерпается физический RAM.

Drive scheduler

Это механизм, который отвечает за алгоритм обращения к диску. По умолчанию он скорее всего стоит в режиме cfq, что соответствует обычному HDD. Для microSD или SSD рекомендуется сменить значение на noop или deadline. Я использую noop.

Посмотреть текущий scheduler:

cat /sys/block/{DEVICE-NAME}/queue/scheduler

В нашем случае нужно дать команду (и записать её в тот же rc.local)

echo {SCHEDULER-NAME} > /sys/block/{DEVICE-NAME}/queue/scheduler

Да, не забываем поменять значения в {} на реальные.

TRIM

Еще неплохо бы включить технологию Trim. Для Raspberry Pi она поддержана, а вот на нищебродном Orange Pi - нет. Ну уж этого добра в интернетах - как говна за баней, найдете сами.

Какие ваши доказательства??

Ясное дело, чтобы проверить что всё стало быстрее - надо померить “до” и “после”. Измерять можно так:

“Один большой файл”

sync; rm testing; sync; time ( dd if=/dev/zero of=testing bs=16k count=10000; sync)

“Много маленьких файлов”

sync; rm -rf testing*; sync; time ( for item in `seq 1 1000`; do dd if=/dev/zero of=testing.$item bs=16k count=10; sync; done; )

Запишите результаты до и после изменений. Свои, к сожалению привести не могу - делалось всё в разное время и сложно сказать, что именно было “прорывом”.

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


В массы

В трубу