Технологии 21-го века стремительно движутся вперед. Одна из таких технологий - SSD, призванная сменить (а на практике дополнить) устаревшую дисковую технологию HDD.
Основные достоинства SSD перед HDD уже знакомы всем, это - скорость доступа, скорость доступа к произвольным блокам, уменьшенные габариты, уменьшенное энергопотребление и как следствие нагрев.
Несмотря на преимущества SSD перед традиционными дисками, этой технологии очень много лет. Я бы даже сказал больше чем жестким дискам, однако в силу дороговизны, тогда (в конце 70-хх - 80-е) они стоили не в полтора-два раза больше обычных дисков, а раз в двадцать. При этом очень быстро изнашивались и занимали чуть ли не столько же, сколько и материнская плата.
На данный момент SSD - это фактически флешка с интерфейсом...а вот мы и плавно подошли к главной теме. Если кратко, то интерфейс носителя информации - это шина со своими стандартами, плюсами и минусами, со своим набором команд, при помощи которой девайс подключается к компьютеру (центральному процессору, или южному мосту - не имеет значения). Этот интерфейс - уровень между устройством и операционной системой, с которым одинаково успешно работает и устройство и операционная система. Не стоит путать интерфейс с форм-фактором разъема, поскольку интерфейс - программная штука, а разъем - аппаратная, и скажем так, вам ничто не помешает сделать кабель соединения вашего жесткого диска из LAN-кабеля с разъемами RJ-45, правда сетевым от этого ваш диск не станет. Итак, разъем (или форм-фактор, хотя не совсем корректно) - это всего лишь реализация подключения устройства. Интерфейс, он же протокол - набор программных стандартов для работы ОС с устройством, подключенным через этот разъем.
Достаточно старый интерфейс для работы с носителями информации - ATA. В настоящий момент ванильная версия этого интерфейса-протокола безнадежно устарела, и вытеснена более новыми стандартами тем же самым ATA, обросшим костылями, которые позволяют адресовать больше пространства, добавляют очередь команд и прочие нововведения, актуальные для современного мира.
Одним из таких интерфейсов является SATA, а точнее AHCI. В этом случае наименования вообще запутаны. Изначально SATA - был полноценным стандартом, затем из него сделали общее название для системы носителей информации, подключаемого при помощи шести проводов, последовательным подключением (т.е. одно устройство на порт) и набором AHCI-команд, которые в свою очередь поддерживают стандарт NCQ - очередь, если по нашему.
Чтобы устройству быть SATA, ему не обязательно иметь SATA-разъем, оно может быть выполнено в формате eSATA, в формате mSATA (больше напоминающем MiniPCI), даже в формате полноценного PCI и подключаться через эту шину. Просто оно будет эмулироваться, и система не будет его видеть как PCI, а будет видеть как SATA и работать с ним как с SATA.
На данный момент максимальная скорость чтения через SATA - 600 Мбс, и это продиктовано в первую очередь электрическими ограничениями, не так легко передать через 4 провода на высоких скоростях. И 600 Мбс - вполне себе отличная скорость, учитывая что скорость отдачи информации с блина жесткого диска - физически порядка 90 Мбс, а скорость чтения флешки вообще 60 Мбс, теоретическая, максимальная. В общем 600 Мбс вполне хватало с головой для жестких дисков. Пока не появились SSD. Набор микросхем памяти отдает информацию на очень высоких скоростях, кроме всего ему не свойственно большое время поиска, и не свойствены простои при записи. Прогрессу понадобился всего лишь год, чтобы приблизиться вплотную к ограничению порта, и еще год, чтобы в несколько раз перегнать его.
Чтобы нивелировать эти простои, был придуман новый интерфейс - NVM Express. Компании которые его разрабатывали, продумали все до мелочей. Уменьшение задержек, стандартизация всех костылей, управление доступом, параллельный доступ (многоядерные CPU одобряют), механизм очередей, обработка прерываний, упрощение управляющих команд, и много чего другого. Получившаяся солянка вполне способна удивить родившихся в 20-м веке людей: средняя скорость чтения - 2.5 Гбс. Потрясающе.
Однако очень скоро обнаружился тот же самый недостаток что и в случае микросхем памяти с SATA-интерфейсом, и в том месте, где его совсем не ждали - в архитектуре программного обеспечения.
Представьте себе двух людей, один слушает, второй вслух читает книгу. Количество времени, за которое слушатель успеет познать эту книгу, первоначально зависит от скорости читающего, и это обыкновенное положение вещей. А теперь представьте, что читающий книгу, ускоряет чтение. Книга будет услышана быстрее. Если читающий еще постарается - то ввод этой книги в уши слушателя состоится еще быстрее. Но если скорость увеличить ЕЩЕ, то поток слов станет бессвязным, и слушатель его попросту не поймет. Получается, что на самом деле количество времени на ввод книги в уши слушателя, зависит не только от скорости читающего, а еще и от возможности слушателя различать слова. Подобная ситуация произошла и с Linux. Читающий книгу (суть носитель информации) стал передавать информацию слишком быстро, слушатель (система ввода-вывода) перестала за ним успевать, в итоге вся система работает на максимальных возможностях слушателя, при умеющем быстрее читателе. Ничего страшного в этом нет, такая система будет работать в три раза быстрее, чем системы двухлетней давности. Плохо то, что физически она может работать быстрее в пять раз. И будет.
Итак, тема статьи - ускорение Linux на SSD NVM Express - Samsung N950 Pro
Вводные данные:
Материнская плата MiniITX MSI B150I Gaming Pro
Процессор Intel Pentium G4400 Skylake
ОЗУ 8Gb DDR4 2133MHz
SSD M.2 NVME Samsung 950Pro, скорость чтения - 2500 Мб/c, скорость записи - 1500 Мб/c
Операционная система Debian 8.4 (на самом деле не имеет значения)
Жуткие тормоза при загрузке, и при работе. С установленным DE Cinnamon, эта конфигурация открывает Firefox за 2-3 секунды, что не есть гут. Должна мгновенно.
Рассмотрим последовательно процесс загрузки от начала и до готовности работы:
Сперва загружается BIOS. Или UEFI - не суть важно. Эта микропрограмма инициализирует устройства и ищет загрузчик на одном из носителей информации. Этот загрузчик - MBR или файл UEFI, в свою очередь загружает полноценный лоадер, в нашем случае это GRUB. Лоадер читает свой конфигурационный файл, /boot/grub/grub.cfg и загружает субмодули, шрифты и выполняет скрипты, выводя список возможных ОС и их меню.
Когда мы нажимаем ввод на том или ином меню (с Линуксом, разумеется), наш GRUB подгружает дополнительные модули необходимые для доступа к разделу диска, некоторые графические модули. Потом он загружает в память ядро с строкой параметров, и так называемый ramdisk, initrd - сжатый набор модулей и библиотек, необходимый для начального старта. После загрузки рамдиска, ядро передает управление файлу /init, который находится на том разделе, который был указан параметром root= в строке параметров ядра. Система инициализации, она же init - набор скриптов разной степени извращенности в разное время, по сути являющихся автозагрузчиками сервисов, устройств, и так далее. Последним из этих скриптов является менеджер дисплеев, либо менеджер консолей. Дальнейшая загрузка зависит от настроек конкретной ОС, они бывают разными, но чаще всего два варианта - либо выдается приглашение в случае менеджера консолей, либо выдается графическое приглашение в случае с дисплейным менеджером. Но не всегда. Оба способа могут иметь автологин (т.е. будет залогинен под пользователем без приглашения). Затем грузится интерпретатор (как правило это bash) в случае с консольной загрузкой, либо оконный менеджер(рабочий стол) в случае с графической загрузкой. Эти программы являются практически конечными, за исключением их собственных автозагрузок, которые могут содержать в себе подключаемые вкусности вроде докбара, панелей, расцветок, и прочего мусора. Но это уже неважно.
Как видим, этапов загрузки много. На самом деле их еще больше, поскольку многие драйверы устройств могут быть встроены в ядро, но многие лежат в виде отдельных модулей и подгружаются по мере необходимости.
Итак, первое что мы должны уяснить, как и в случае с HDD, лучше один большой файл, чем много мелких. "Лучше" здесь может варьироваться в широких пределах: десятимегабайтный файл загрузится быстрее, чем десят стокилобайтных (в сумме дающих всего лишь мегабайт). Как этого достичь - мы узнаем позже.
Второе - принцип KISS не всегда хорош, и отсутствие принципа KISS не всегда хорошо тоже. Напомню, этот принцип гласит делать одну вещь одним инструментом, не изобретая комбайны. В нашем случае загрузки, даже не вдаваясь в подробности видно, что некоторые нюансы делаются по нескольку раз. Пример - загрузка драйверов на диск и ФС. Ну бред же, если GRUB загрузился, значит диск УЖЕ доступен, и не нужно подгружать драйверы в initrd, а затем в ядре. Как от этого избавиться - мы тоже узнаем позже.
Третье - всегда нужно осознавать что базовое ядро и вообще базовая система построена на основе наиболее распространенных конфигураций, и с одной стороны раздуто для как можно большей совместимости, а с другой стороны, не поддерживает многие фичи опять же для как можно большей совместимости. Драйверы видео, драйверы дисков, драйверы USB работают на средней арифметической оптимизации и скорости. А это чаще всего медленно. Туда же относятся и всякие новые технологии, вроде нашего nvme
Что же нам нужно сделать?
Во-первых, избавиться от прокладок. Прокладки от которых легче всего избавиться без лишней головной боли - это как ни странно initrd и дисплейный менеджер. Для того чтобы избавиться от первого - нужно всего лишь закомментировать одну строчку. Чтобы избавиться от второго - его нужно просто не ставить, или удалить если уже поставили. То есть добиться консольной загрузки.
Во-вторых, заставить нашу ОС грузить все фичи для ускорения работы.
В-третьих, сделать так, чтобы по возможности все грузилось только одним файлом.
Поскольку простое избавление от initrd приведет к невозможности загрузки (ядро не сможет загрузиться), да и фичи просто так не появятся, единственный способ сделать это - пересобрать ядро.
Это легко. Особенно на debian-based системах, Debian, Ubuntu, Elementary, Mint и прочих. На других конфигурирование будет точно таким же, но сборка может немного отличаться. Какие пакеты нужно качать и ставить, я объяснять не буду, об этом можно почитать здесь (откроется в новом окне)
Нам стоит создать первоначальную конфигурацию командой make localyesconfig - эта команда создаст предварительную конфигурацию на основе работающих в данный момент модулей, с опцией включения этого всего в ядро (помним, мы формируем один большой файл). Поэтому будет лучше если на этом этапе вы вставите в ваш компьютер все устройства, которые потенциально могут использоваться - вебки, флешки, сетевые карты.
Далее я просто напишу какие параметры нужно сконфигурировать для пущего ускорения и поддержки фич на устройствах NVM Express:
General setup ---> Kernel compression mode ---> выбираем XZ. Этот алогоритм сжатия наиболее быстр, пусть и не очень экономен.
General setup ---> Timers subsystem ---> Выбираем Periodic timer ticks (constant rate, no dynticks) - наш процессор сам разберется как ему работать с задачами, не нужно ему мешать
Processor type and features ---> Выбираем максимально приближенный процессор к нашему, и его некоторые фичи, поддержку Hyperthreading, или просто многоядерности.
Preemption Model ---> Preemptible Kernel (Low-Latency Desktop) - это позволит максимально быстро обрабатывать все задачи
Timer frequency ---> 300 HZ - выше нет смысла, процессор будет зря дергаться, ниже - тоже, иначе реакция системы будет запоздалой.
Device Drivers ---> <*> NVM Express block device - ставим звездочку, этот драйвер должен быть вкомпилирован в ядро
Device Drivers ---> SCSI device support ---> [*] SCSI: use blk-mq I/O path by default - обязательно. Это позволит системе ввода вывода использовать параллелизм при чтении или записи на NVM-носителе
Остальные параметры вы должны выставить сами, исходя из наличия или отсутствия устройств на вашем компьютере
Идем дальше.
File systems ---> <*> The Extended 4 (ext4) filesystem - в случае если вы используете ext4 или ext3. Иными словами, вы должны вкомпилировать в ядро ту ФС, которая установлена у вас.
File systems ---> <*> FUSE (Filesystem in Userspace) support - это позволит монтировать диски в графических оболочках
File systems ---> DOS/FAT/NT Filesystems ---> Здесь можно поставить все звездочки, или все модули, это нужно только если у вас есть файловые системы отличные от корневой. Флешки, диски, и так далее.
Не забудьте так же выставить необходимые вашим НЕлинукс ФС, кодировки в меню Native language support --->
После компиляции и установки нового ядра, нам стоит отредактировать файл /boot/grub/grub.cfg и закомментировать строчку с вызовом нашего initrd. Если вы его оставите - ничего страшного не случится, но система будет загружать два раза одни и те же модули. Если вы его закомментируете - ничего страшного так же не произойдет, ведь вся ваша информация никуда не удалится. После этого в строке загрузки вашего ядра, нужно изменить параметр root с символьного UUID-устройства, на его блочный путь, например root=/dev/nvme0n1p2
После перезагрузки по идее, новое ядро и в целом система, должны загружаться ощутимо быстрее, и занимать меньше места на диске и в памяти. Если вы не смогли загрузить ядро (точнее оно не смогло примонтировать системный раздел и упало в "kernel panic-not syncing: VFS: unable to mount root fs" - это означает что вы неверно указали системный раздел в параметрах ядра, или забыли вкомпилировать драйвер, специфичный для вашей ОС (например вкомплилировали поддержку ext4, но забыли btrfs, и именно на нем расположена ваша система).
Продолжение следует...