Показаны сообщения с ярлыком loader. Показать все сообщения
Показаны сообщения с ярлыком loader. Показать все сообщения

воскресенье, 2 декабря 2012 г.

Что нового?

Начнём с того, что я сменил работу, и теперь она напрямую связана с FreeBSD. Теперь у меня больше времени и возможностей, которые можно направить на улучшение системы. Правда, работодатель рассчитывает, что я буду прикладывать их в другое русло - оптимизация сетевой подсистемы и ipfw. Чем я и занимаюсь :)

Первой ласточкой стало то, чего давно хотелось. Ещё когда я не был коммитером, хотелось чтобы ipfw fwd работало без перекомпиляции ядра. Но тогда на моё предложение возразили, что этот функционал значительно снижает быстродействие сетевой подсистемы. Но как показали испытания, никакого снижения замечено не было. В системе хватает других мест, которые вносят значительные "тормоза".

Итак, вероятно некоторые уже заметили, что в src/UPDATING появилась запись, информирующая об удалении опции IPFIREWALL_FORWARD. Теперь этот функционал работает "из коробки", достаточно просто загрузить модуль ядра ipfw.ko. В stable/9 это изменение уже тоже есть, но в релиз оно не попадёт.

Другим крупным шагом был MFC изменений в загрузчике в stable/9. Теперь код загрузчиков в 9-ке практически идентичен тому, что в 10-ке. Я ещё думаю о переносе изменений в 8-ку, но, честно говоря не хочется этого делать. Уж очень сильно в 8-ке он отличается и придётся сделать MFC ещё для кучи ревизий. Так же, можно поблагодарить Андрея avg@ за исправление проблемы в загрузочном коде, которая обнаруживалась на некоторых "кривых" BIOS.

Кроме того, был осуществлён первых подход к изучению и тестированию IPv6 стека на производительность. Который показал плачевное состояние в этой области. Правда, благодаря профилированию и нескольким небольшим изменениям, удалось улучшить результаты почти в три раза. Не буду озвучивать цифры, они сильно зависят от железа. Но факт в том, что оптимизация IPv6 во FreeBSD - это ещё "напахано поле". Впрочем, в IPv4 базовая система тоже не блещет результатами и всего несколько строк в /boot/loader.conf и /etc/sysctl.conf может улучшить эти результаты в разы.

воскресенье, 30 сентября 2012 г.

loader(8): оптимизация и результаты.

Наконец-то я нашёл время и ресурсы на проведение оптимизации в загрузчике системы. Организовал стенд на базе VMWare ESXi, в которой я создал несколько виртуалок с FreeBSD 10, установленных с использованием различных комбинаций таблиц разделов и файловых систем. Расшарил по NFS рабочий каталог с исходниками системы со своей машины, подключил его к виртуалкам и начал отладку... Ну как "отладку", добавил несколько printf'ов в libstand и в драйвер диска biosdisk; включил отладку в недавно добавленном модуле с DISK API; в виртуалках создал файл /boot.config с опциями "-D -S115200", в VMWare настроил запись вывода с последовательного порта в файл и начал тесты.

Получив логи, начал смотреть код и искать способы уменьшения количества дисковых операций, которых оказалось великое множество. В итоге, в модуль с DISK API был добавлен код кеширования обращений к дискам. А нужно сказать, что почти каждое открытие файла с использованием libstand приводит к чтению метаданных таблиц разделов. Чтобы уменьшить это число обращений раньше использовался bcache - блочный кэш. Но, printf'ы внутри дискового драйвера показали, что его эффективность довольно низка, а при использовании GPT - совсем удручает.

Итак, новый кэш работает по другому. При открытии файла, запрос open() приводит к вызову функции devopen(), которая и "открывает" текущее устройство (обычно диск, с которого происходит загрузка), например, disk1p3. Открытие диска - это чтение его метаданных, поиск таблиц разделов и определение смещения, с которого начинается открываемый раздел. Каждое успешное открытие добавляет в кеш запись. Таким образом, при открытии следующего файла на этом диске, уже не нужно будет читать метаданные, а смещение будет прочитано из кэша. В результате, если раньше при загрузке с UFS чтение метаданных выполнялось примерно 50 раз (с учётом попаданий в блочный кеш - около 30), то сейчас это происходит 1 раз.

Далее меня заинтересовало почему при открытии, например, ядра или его модулей, в логе загрузки эта операция отображается несколько раз (от трёх до четырёх)? Т.е. конечно чтение всего ядра не происходит четыре раза, но каждое открытие сопровождается чтением некоторого объёма данных, и только последнее открытие читает заметно больший объём данных. Как оказалось, для архитектуры x86/x64 loader одновременно поддерживает несколько форматов ELF - 32-битные и 64-битные. Причём в массиве, где перечислены указатели на обработчики этих форматов первыми стоят 32-битные, а затем уже 64-битные. Поэтому loader при загрузке модулей ядра в цикле "пробует" модуль каждым обработчиком, пока не найдёт подходящий. И так как у меня тестовые машины 64-битные, то обработчик ядра стоит  3-им в этом массиве, а обработчик модулей ядра - 4-ым.

В общем, эта досадная несправедливость в отношении 64-битных систем была мной ликвидирована тоже. В итоге, я сравнил результаты по затратам времени загрузки с момента старта loader'а и до момента запуска ядра в разных конфигурациях системы:

UFS+GPTZFS+GPTZFS+GPT+несколько дисков
Старый loader7,203 сек20,584 сек26,079 сек
Обновлённый loader4,334 сек9,422 сек11,245 сек

Во всех случаях, кроме самого ядра загружалось ещё несколько модулей.

вторник, 7 августа 2012 г.

Обновление загрузчика

После долгого перерыва, не дождавшись каких-либо комментариев, я наконец-то закоммитил большую часть изменений в коде загрузчика в head/ ветку.

Немного об изменениях. Было добавлено два программных интерфейса, назовём их PART и DISK. Первый предоставляет функции для работы с различными таблицами разделов: поиск метаданных таблиц разделов, парсинг и формирование списков разделов, получение информации по каждому разделу и т.п. На данный момент поддерживаются GPT, MBR, EBR, BSD label и VTOC8. Набор поддерживаемых таблиц разделов определяется переменными make на этапе компиляции. Обычно это GPT, MBR+EBR и BSD label.

PART API можно использовать напрямую, как это теперь делает ZFS, либо через DISK API. DISK API предназначен для использования в дисковых драйверах загрузчика. Интерфейс вобрал в себя всё общее, что есть между драйверами дисков загрузчиков разных аппаратных архитектур. Это позволило, во-первых, значительно упростить код драйверов, а, во-вторых, унифицировать алгоритмы их работы относительно определения таблиц разделов. Причём, эти алгоритмы почти на 100% совпадают с используемыми ядром. Поэтому, теперь не должно возникать ситуаций, когда загрузчик видит одни разделы, а ядро другие. Раньше такое было вполне возможно.

Основные особенности, которые попали в CURRENT:
  • теперь loader умеет считать контрольную сумму для GPT заголовка и таблицы, а так же использовать резервную копию GPT;
  • PMBR так же научился работать с резервной GPT;
  • в качестве дополнительного бонуса, улучшенная поддержка EBR позволяет загрузить систему с логического тома. Правда boot0 делать этого не умеет, на сколько я помню.
  • Так как ZFS научилась читать таблицы разделов, теперь она не перебирает все возможные комбинации разделов, а тестирует только те, на которых ZFS может быть установлена. Т.е. это разделы с типом "freebsd" и "freebsd-zfs", так что, если у вас есть загрузочный пул на разделах с другим типом, это нужно исправлять.
От идеи с определением метаданных GEOM в загрузчике пока отказались. Так же остались ещё патчи для uboot и архитектур arm/powerpc, которые так никто и не протестировал.

Мой студент в GSoC прошёл первый "отборочный тур", пока с небольшим отставанием от графика, но надежда на то, что скоро у нас на x86 заработает загрузка через EFI есть.

Дальше я планирую провести серию тестов по загрузке системы в различных конфигурациях с разным размером дискового кеша. Сейчас по-умолчанию его размер всего 16 Кбайт, и как показали первые тесты, его увеличение даёт прирост в скорости загрузки на несколько секунд, по крайней мере на моей машине.

В свободное время почитал код различных библиотек, утилит, загрузчиков и UEFI шелла, а так же документацию, какую удалось найти. Теперь уже гораздо лучше представлю, как будет работать наш UEFI загрузчик. Так что, если студент не справится, его работа не пропадёт даром :)

среда, 27 июня 2012 г.

Тестирование патчей для загрузчика

Прошло уже почти три месяца со дня публикации сообщения о патчах к загрузочному коду. И вот, на прошлой неделе я решил заняться этим вплотную. В итоге, создал бранч в SVN, куда стал коммитить свои наработки. Теперь все жалющие принять участие в тестировании могут это сделать :)

Историю изменений можно посмотреть здесь: http://svn.freebsd.org/base/user/ae/bootcode/
Патч относительно 10-CURRENT тут: http://people.freebsd.org/~ae/boot.diff

Какие изменения были сделаны:
  1. На основе кода, используемого в GEOM_PART были написаны функции, предоставляющий интерфейс для поиска таблицы разделов на носителе и выдачи информации о разделах.
  2. Было удалено много старого, дублирующегося кода.
  3. Похожий по назнаению код в "драйверах" дисков  загрузчика был унифицирован и объединён в нескольких функциях, а так же переписан с использованием нового API работы с таблицами разделов.
  4. zfsloader был научен использовать информацию о таблицах разелов, что значительно ускорило его работу на системах, в которых установлено много жёстких дисков.
  5. loader теперь умеет полноценно работать с GPT, т.е. проверяеят контрольные суммы, в случае необходимости умеет находить резервную копию GPT.
  6. В код PMBR так же внесены изменения, которые научили его находить резервную копию GPT, только CRC он не проверяет из-за ограничений на объём кода.
  7. gptboot и PMBR при обнаружении повреждений в заголовке основной таблицы GPT ищут резервную копию в последнем секторе. Если же там её нет, но есть метаданные GEOM класса, то они смотрят в предыдущем секторе. Т.е. теперь, иметь GPT внутри GEOM_MIRROR стало ещё безопаснее, даже в случае поверждения основной таблицы, загрузочный код сможет найти резервную.
На 9-ку патчи пока не накладываются, возможно после выходных avg@ сделает MFC нескольких своих изменений в коде, обеспечивающем загрузку с ZFS, тогда будет возможность тестировать и на STABLE.