Каталог статей
Главная » Статьи » Статьи из мира Linux » Настройка и оптимизация операционных систем Linux |
"Насколько сильно его можно сжать?" - такой вопрос часто задают разработчику встраиваемых систем в начале работы над проектом. В большинстве случаев клиент подразумевает, до какой степени можно уменьшить затраты оперативной и Flash-памяти в проектируемом устройстве, с целью уменьшения его стоимости и снижения энергозатрат. Изначально операционная система Linux и ее соответствующее окружение были предназначены для настольных и серверных систем, поэтому в обычной конфигурации она не оптимизирована по объему занимаемой памяти. Однако когда Linux начал проникать во встраиваемые системы, задача сделать Linux "маленьким" стала весьма актуальной. Есть несколько подходов к уменьшению расхода памяти системы. Многие разработчики начинают уменьшать размер ядра; но есть также и более простые способы. В этой статье будут подробно описаны подходы к уменьшению размера ядра за счет удаления кода, неиспользуемого во встраиваемых системах. Пожалуй, больше всего памяти отъедает корневая файловая система (root filesystem, RFS). Корневая файловая система содержит код инфраструктуры, используемой приложениями и библиотекой C. Тип файловой системы RFS накладывает значительный отпечаток на итоговый размер системы. Стандартная файловая система типа ext3 страшно неэффективна при использовании во встраиваемых системах, но это уже тема для отдельной статьи. На самом деле, насколько?Даже в самом маленьком дистрибутиве Linux есть как минимум две части - ядро и корневая файловая система. Иногда эти компоненты размещают в одном и том же файле, но тем не менее они логически разделены и являются отдельными компонентами. Если убрать из ядра почти все функции (поддержка сети, журналирование ошибок и драйверы большинства устройств) и сделать корневую файловую систему простым приложением, размер системы можно с легкостью сократить до 1 Мб. Однако, многие пользователи выбирают Linux из-за широких возможностей работы с сетью и множеством устройств, поэтому это не совсем реалистичный сценарий. ЯдроЯдро Linux интересно тем, что хотя оно зависит от GCC на стадии компиляции, но не имеет зависимостей во время исполнения. Инженерам, которые являются новичками в Linux, обычно непонятна концепция начального RAM-диска (так называемого initrd) с зависимостью от ядра времени выполнения. Сначала ядром монтируется initrd, и запускается программа, которая общается с системой и выясняет, какие модули нужно загрузить, чтобы заработали все устройства. Затем монтируется "настоящая" файловая система. На самом деле, такое двухуровневое монтирование, когда за initrd следует загрузка основной файловой системы, редко находит применение во встраиваемых системах, так как увеличение гибкости в системе, которая в течение своей жизни не будет изменяться, совершенно не стоит дополнительных расходов памяти и времени. Эта тема относится к корневой файловой системе и будет раскрыта далее. Наибольший эффект в уменьшении размера ядра дает удаление ненужного кода. Обычно ядро настраивается для настольных и серверных систем, поэтому по умолчанию в нем включено множество функций, которые не понадобятся во встраиваемых системах. Поддержка загружаемых модулейЗагружаемые модули ядра - это перемещаемый код, который ядро связывает с собой во время исполнения. Обычно это используется для загрузки драйверов устройств в ядро из пространства пользователя (как правило, после некоторых системных проверок), и позволяет обновлять драйвера устройств без перезагрузки всей системы. В большинстве встраиваемых систем смена корневой файловой системы непрактична либо невозможна, поэтому разработчик сразу связывает модули с ядром, таким образом необходимость в загружаемых модулях отпадает. Помимо кода поддержки загружаемых модулей в ядре, мы также можем сэкономить место и на пользовательских программах для загрузки модулей (insmod, rmmod и lsmod). Патчи Linux-tinyНабор патчей Linux-tiny - это периодически развивающийся проект, поддерживаемый Мэттом Макаллом (Matt Mackall). Consumer Electronics Linux Forum (CELF) приложило определенные усилия к возрождению проекта, и на момент написания статьи на вики CELF Developer были размещены патчи для ядра 2.6.22.5. В то же время, многие изменения из проекта Linux-tiny перетекли в основную ветку ядра. Итак, в самом наборе Linux-tiny есть следующие экономичные патчи:
Патчи Linux-tiny распространяются в tar-архиве и могут быть применены с помощью утилиты quilt, либо вручную. Дополнительные рекомендации по настройке ядраПроект Linux-tiny дает значительный выигрыш в объеме занимаемой памяти, но все равно можно еще уменьшить размер системы:
Как увидеть результатКоманда size печатает объем кода и данных в объектном файле. Это не то, что выводит ls (ls печатает количество байт, занимаемых файлом в файловой системе). К примеру, для ядра, скомпилированного кросс-компилятором armv5l, объемы следующие: # armv5l-linux-size vmlinx text data bss dec hex filename 2080300 99904 99312 2279516 22c85c vmlinux Секция text - это исполняемый код, генерируемый компилятором (название text имеет исторические корни). Секция data содержит значения глобальных переменных и другие значения, используемые для инициализации статических символов. Секция bss содержит статические данные, которые зануляются в процессе инициализации. Какие-то сведения есть, но не показано, сколько памяти занимает каждая часть системы. Получить более подробные сведения из файла ядра vmlinux невозможно. Но мы можем взглянуть на файлы, из которых это ядро собирается. Чтобы получить информацию о размерах компонентов системы, нужно найти все файлы built-in.o, содержащиеся в проекте ядра, и передать их все программе size: # find . -name "built-in.o" | xargs armv5l-linux-size --totals | sort -n -k4 У меня вывод данной команды такой: text data bss dec hex filename 189680 16224 33944 239848 3a8e8 ./kernel/built-in.o 257872 10056 5636 273564 42c9c ./net/ipv4/built-in.o 369396 9184 34824 413404 64edc ./fs/built-in.o 452116 15820 11632 479568 75150 ./net/built-in.o 484276 36744 14216 535236 82ac4 ./drivers/built-in.o 3110478 180000 159241 3449719 34a377 (TOTALS) Таким образом, можно сразу увидеть, код какого компонента занимает больше всего места, и уже целенаправленно работать именно с этим компонентом, думать, какие функции можно убрать, а какие оставить. При таком подходе инженер не должен забывать делать make clean между сборками, ведь удаление функции из ядра не приводет к тому, что будет удален объектный файл из прошлой сборки. У тех, кто в первый раз собирает ядро Linux, может возникнуть вопрос, как соединить файл built-in.o с опцией в программе конфигурирования ядра. Взгляните на файлы Makefile и Kconfig. Makefile содержит строку следующего вида: obj-$(CONFIG_ATALK) += p8022.o psnap.o Эта строка приводит к тому, что объектные файлы справа от знака равенства будут собраны, когда включена переменная опции CONFIG_ATALK. Однако, программа конфигурирования ядра обычно не показывает, какая переменная ассоциирована с данной опцией. Чтобы найти связь между именем переменной и опцией, возьмите имя переменной, уберите CONFIG_, и поищите оставшееся в файлах Kconfig (именно они используются редактором конфигурации ядра): find . -name Kconfig -exec fgrep -H -C3 "config ATALK" {} \; Команда дает следующий вывод: ./drivers/net/appletalk/Kconfig-# ./drivers/net/appletalk/Kconfig-# Appletalk driver configuration ./drivers/net/appletalk/Kconfig-# ./drivers/net/appletalk/Kconfig:config ATALK ./drivers/net/appletalk/Kconfig- tristate "Appletalk protocol support" ./drivers/net/appletalk/Kconfig- select LLC ./drivers/net/appletalk/Kconfig- ---help--- Еще правда нужно поискать, где в меню находится это самое "Appletalk protocol support", но общий порядок поиска, думаю, ясен. Корневая файловая системаДля многих разработчиков встраиваемых систем, только начавших работать с Linux, корневая файловая система на встраиваемом устройстве - это незнакомое понятие. До Linux во встраиваемых системах стандартным решением было включение кода приложения в ядро. В Linux же присутствует явное разделение ядра и корневой файловой системы, поэтому работа над уменьшением системы не заканчивается на уменьшении размеров ядра. В общем, есть множество приемов по уменьшению размера этого компонента. Первый вопрос, которым нужно задаться: "Нужна ли мне вообще файловая система?" В большинстве случаев, да. В конце процесса загрузки ядра идет поиск корневой файловой системы, она монтируется и запускается первый процесс (обычно это init; чтобы узнать какой, скомандуйте на своей системе ps aux | head -2). Если отсутствует корневая файловая система или начальная программа, ядро паникует и перестает работать. Наименьшей корневой файловой системой может быть один файл - приложение для устройства. В этом случае параметр ядра init указывает на файл, и это будет первый (и единственный) процесс в пространстве пользователя. Пока этот процесс запущен, система будет работать нормально. Однако если по какой-либо причине эта программа завершится, ядро будет паниковать и перестанет работать, а устройству для восстановления работоспособности потребуется перезапуск. Уже по одной этой причине даже системы с существенно ограниченным объемом памяти выбирают вариант с программой init. При небольших накладных расходах это обеспечивает перезапуск умершего процесса, таким образом предотвращаю панику ядра в случае краха приложения. Все равно, большинство Linux-систем куда более сложные, содержат несколько исполняемых файлов и зачастую разделяемые библиотеки, общие для нескольких приложений. Для таких файловых систем существует множество способов существенно сократить размер RFS. Смена библиотеки CСтандартная библиотека C, как правило, распространяется вместе с компилятором GCC, поэтому пользователи обычно не отделяют их друг от друга. Тем не менее это отдельные компоненты. Сам по себе язык C состоит из 32 ключевых слов (плюс-минус несколько), поэтому основную часть кода в программе C все-таки занимают вызовы функций стандартной библиотеки. Обычная GNU-реализация стандартной библиотеки C - glibc - спроектирована с расчетом на совместимость и интернационализацию, и итоговый размер разработчиков не столь волнует. В то же время существует несколько альтернатив, создаваемых с прицелом на экономию занимаемой памяти:
Использование альтернативной библиотеки CКак Newlib, так и dietlibc работают через скрипт-обертку, который вызывает компилятор с требуемым набором параметров. Благодаря этому игнорируется стандартная реализация библиотеки C, входящая в комплект компилятора, и вместо нее используется альтернативная реализация. uClibc немного отличается от этих реализаций, используемый для работы с ней инструментарий нужно собрать отдельно. Теперь вы знаете, как вызывать GCC, чтобы использовался нужный компилятор. Следующий шаг - нужно подправить файлы Makefile или скрипты сборки проекта. В большинстве случаев, команды сборки содержатся в Makefile, а именно в строке следующего вида: CC=CROSS_COMPILE-gcc В этом случаев, все, что нужно сделать инженеру - это запустить make с измененным аргументом CC, примерно следующим образом: make CC=dietc Теперь для компиляции программы будет использована библиотека diet в связке с компилятором C. Если нужно будет добавить какие-либо параметры компиляции, нужно вставлять их не в эту команду, а в переменную CFLAGS. Например, вместо make CC="gcc -Os" нужно писать: make CC=gcc CFLAGS="-Os" Это важно, ведь в некоторых случаях CC вызывается не для компиляции, и эти аргументы не будут иметь смысла, произойдет ошибка. Вернемся к корневой файловой системеПосле выбора альтернативной библиотеки C, нужно перекомпилировать весь код в корневой файловой системе. На данном этапе будет важно оценить, что предпочтительнее - статические приложения либо разделяемые библиотеки. Разделяемые библиотеки нужно выбирать, когда устройство будет выполнять произвольный код, неизвестный на момент создания устройства; к примеру, у устройства будет какое-либо API, и для него, как задумывается, другие инженеры будут писать модули. В этом случае нужно иметь библиотеки на устройстве, таким образом для других разработчиков будет предоставляться гибкость в реализации новых функций. Разделяемые библиотеки - хороший выбор в случае, когда в файловой системе устройства хранится множество отдельных программ, а не одна или две. Одна копия разделяемого кода будет занимать меньше места, чем две копии кода в разных файлах в случае статической сборки. Системы с небольшим количеством программ заслуживают более подробного рассмотрения. Когда используется лишь несколько программ, лучше всего создать два варианта системы и сравнить получившийся результат. В большинстве случаев, меньшей системой окажется система без разделяемых библиотек. Дополнительным плюсом статического подхода является то, что программы будут запускаться быстрее (так как здесь нет стадии связывания). ЗаключениеХотя и не существует волшебного способа сделать систему меньше, но в то же время не наблюдается дефицита инструментария для достижения этой цели. Более того, сделать Linux меньше - это не только ужать ядро; также необходимо уменьшать размер корневой файловой системы. Нужно критически рассмотреть все ее компоненты и исключить все ненужное. В данной статье было рассмотрено, как уменьшить размер образа системы. Как уменьшить потребление памяти программами в процессе работы устройства - это тема для отдельной статьи. Источник: http://rus-linux.net | |
Категория: Настройка и оптимизация операционных систем Linux | Добавил: Diskosuperstar (10.08.2009) | |
Просмотров: 1288
| Теги: |
Всего комментариев: 0 | |