Цель написания: Познакомить с тем, как оптимизировать скорость запуска под TinaLinux.
Скорость запуска — важный показатель производительности встроенных продуктов. Чем выше скорость запуска, тем удобнее будет для клиентов.
В некоторых аспектах это также сэкономит потребление энергии, поскольку его можно выключить напрямую, без перехода в спящий режим.
Оптимизация скорости запуска может повысить конкурентоспособность вашего продукта. Для некоторых систем скорость запуска является жестким требованием.
Текущий процесс запуска системы TinaLinux выглядит следующим образом:
brom --> boot0 --> (monitor/secure os) --> uboot --> rootfs --> app
Бром затвердевает внутри микросхемы и не может быть заменен после того, как чип покинет завод.
Далее мы поэтапно представим метод оптимизации запуска, начиная с boot0.
Для некоторых решений будут использоваться мониторные или безопасные ОС, оба из которых отнимают очень много времени и в этой статье будут пропущены.
Ниже приведены некоторые файлы конфигурации, которые будут объяснены здесь заранее.
Путь к файлу конфигурации env:
tina/device/config/chips/<chip>/configs/<board>/env.cfg #высокий приоритет
tina/device/config/chips/<chip>/configs/<board>/linux/env-<kernel-version>.cfg #priorityсередина
tina/device/config/chips/<chip>/configs/default/env.cfg #низкий приоритет
Путь sys_config.fex:
tina/device/config/chips/<chip>/configs/<board>/sys_config.fex
Путь uboot-board.dts:
tina/device/config/chips/<chip>/configs/<board>/uboot-board.dts
! Внимание: если файл uboot-board.dts существует, uboot будет использовать конфигурацию из uboot-board.dts; если uboot-board.dts не существует, uboot будет использовать конфигурацию из sys_config.fex. (AW1886/V853 использует uboot-board.dts)
Откройте конфигурацию ядра и включите следующие параметры:
kernel hacking --->
[*] Show timing information on printks
linux4.9
kernel hacking --->
printk and dmesg options --->
[*] Show timing information on printks
Метка времени будет добавлена в журнал ядра.
Примечание. Этот метод в основном используется для измерения времени, затрачиваемого на каждом этапе процесса запуска ядра.
Измените файл env и добавьте параметры в командную строку ядра.
# Добавьте переменную initcall_debug
initcall_debug=1
#initial initcall_debug=${initcall_debug} input setargs_xxx, default setargs_nand, setargs_mmc, setargs_nor, setatgs_nand_ubi,
setargs_nand=setenv bootargs console=${console} earlyprintk=${earlyprintk} root=${nand_root} initcall_debug=${initcall_debug} init=${init}
После его включения каждый вызов функции initcall и его время будут распечатаны во время запуска.
Примечание. Этот метод в основном используется для измерения времени, затрачиваемого на инициализацию вызова ядра.
Как правило, таблица символов ядра, то есть опция kallsyms, должна быть настроена одновременно для печати имени функции.
В исходный код ядра входит инструмент (scripts/bootgraph.pl), который можно использовать для анализа времени запуска. Вам необходимо добавить log_buff. Большой, иначе самая ранняя информация о запуске будет потеряна:
make kernel_menuconfig
General setup --->
(17) Kernel log buffer size (16 => 64KB, 17 => 128KB)
Kernel hacking --->
printk and dmesg options --->
[*] Show timing information on printks
Примечание. Этот метод в основном используется для измерения времени, затрачиваемого на каждом этапе процесса запуска ядра.
Bootchart — это программный инструмент с открытым исходным кодом, используемый для анализа производительности процесса запуска Linux. Он автоматически собирает данные о ЦП во время процесса запуска системы. Такая информация, как уровень занятости, процесс и т. д., а также результаты анализа отображаются графически, что можно использовать для оптимизации процесса запуска системы.
Примечание. Этот метод в основном используется для измерения трудоемкого процесса от монтирования файловой системы до запуска основного приложения.
Добавьте код для работы gpio в соответствующем месте и захватите форму сигнала с помощью осциллографа, чтобы получить время, затраченное на каждом этапе.
Примечание. Этот метод можно использовать для измерения времени, затрачиваемого на каждом этапе всего запуска.
Grabserial — это инструмент захвата последовательного порта, написанный Тимом Бердом на Python. Этот инструмент может захватывать каждую полученную строку информации. Добавьте временную метку к информации. Его можно загрузить и использовать по следующему пути: https://github.com/tbird20d/grabserial.
Вводный документ: http://elinux.org/Grabserial.
Общее использование:
sudo grabserial -v -S -d /dev/ttyUSB0 -e 30 -t
Если вы хотите сбросить временную метку в определенной строке, вы можете использовать параметр -m:
sudo grabserial -v -S -d /dev/ttyUSB0 -e 30 -t -m "Starting kernel"
Для дополнительной настройки вы можете использовать параметр -h для просмотра справки.
Примечание. Этот метод можно использовать для измерения времени, затрачиваемого на каждом этапе всего запуска.
Примечание. В этом разделе представлены некоторые методы оптимизации. Не все из них интегрированы в Tina. Основные причины:
boot0 работает в SRAM. Его основная функция — инициализировать DRAM и хранить uboot, Monitor и Secure-OS. Подождите загрузки в DRAM.
В boot0 не так много мест, которые можно оптимизировать. Что можно сделать:
Для решения spinor вы также можете запустить непосредственно из boot0. Вам нужно только загрузить ядро и dtb в boot0. Нет необходимости проходить через uboot, а затем сразу переходить к ядру для запуска, что может сэкономить определенное количество времени. Если boot0 используется для запуска Если ОС запускается, объем данных, считываемых boot0, будет большим, и его прошивальщик также необходимо оптимизировать, например, увеличить тактовую частоту и включить двух/четырехканальную линию. Линия/DMA/Кэш и т. д.
Для решений безопасности boot0 также будет выполнять проверку подписи на uboot, мониторе, Secure-OS и т. д., поскольку во время запуска Когда вам нужно загрузить SecoreOS, вам нужно выполнить переключение среды, и процессор переключится из безопасного состояния в небезопасное состояние, поэтому для Что касается решений безопасности, не поддерживается запуск непосредственно из boot0, затем загрузка dtb и ядра в память, а затем прямой запуск ядра. Ядро, есть несколько основных методов оптимизации. Что можно сделать, так это:
Основными функциями uboot являются загрузка ядра, массовое обновление, управление питанием, загрузочная музыка/логотип, прошивка fastboot и т. д.
uboot содержит множество важных функций и обычно сохраняется. В некоторых случаях это можно устранить и загрузить ядро прямо из boot0 и запустить. Сэкономьте немного времени.
Для плат, на которых включена поддержка записи ключей и которые не использовали инструмент DragonSN для записи ключа, каждый раз при загрузке uboot попытается взаимодействовать с инструментами ПК для создания следующего журнала, что приведет к задержкам.
[1.334]usb burn from boot
...
[1.400]usb prepare ok
usb sof ok
[1.662]usb probe ok
[1.664]usb setup ok
...
[4.698]do_burn_from_boot usb : have no handshake
Если для продукта не требуется ключ записи, вы можете изменить [target] в uboot-board.dts или sys_config.fex. burn_key установлен в 0.
Или используйте инструмент DragonSN, чтобы один раз записать ключ и установить флаг записи, чтобы последующие запуски могли пропустить обнаружение.
Вы можете установить boot_clock в разделе [target] в uboot-board.dts или sys_config.fex, чтобы изменить работу uboot. время Частота процессора ( Примечание. Максимальная частота SPEC не может быть превышена. )。
Для спинора/спинанда используйте более высокую тактовую частоту (обычно 100M) и используйте четырехпроводный или двухпроводной режим (см. Поддерживает ли это оборудование), чтобы улучшить скорость загрузки.
Его можно отключить, установив debug_mode в разделе [platform] в uboot-board.dts или sys_config.fex равным 0. Выход последовательного порта uboot.
Вы можете установить debug_mode в разделе [platform] в sys_config.fex равным 0, чтобы отключить вывод последовательного порта boot0.
Если после настройки объем вывода все еще остается небольшим, есть две возможные причины:
Во-первых, эти выходные данные генерируются до получения процесса debug_mode.
Вторая причина заключается в том, что puts используется непосредственно в исходном коде вместо printf.
В обоих случаях необходимо изменить исходный код, чтобы полностью отключить вывод последовательного порта.
Если адрес, по которому uboot загружает ядро в DRAM, не совпадает с адресом загрузки в ядре, необходимо переместить ядро в Правильная позиция, это приведет к потере определенного количества времени. Таким образом, uboot можно напрямую изменить для загрузки ядра по правильному адресу.
В частности, измените переменные boot_normal и boot_recovery файла env (путь см. выше).
В соответствии с разными форматами изображений ядра необходимо установить разные значения. 。
Предположим, что адрес загрузки ядра — 0x40008000.
#uImage/raw
boot_normal=sunxi_flash read 40007fc0 ${boot_partition};bootm 40007fc
boot_recovery=sunxi_flash read 40007fc0 recovery;bootm 40007fc
#boot.img/raw
boot_normal=sunxi_flash read 40007800 ${boot_partition};bootm 40007800
boot_recovery=sunxi_flash read 40007800 recovery;bootm 40007800
Если адрес ядра загрузки uboot не совпадает с адресом загрузки, выходные данные последовательного порта во время процесса uboot могут содержать:
Loading Kernel Image ... OK
Если они совпадают, вывод последовательного порта во время процесса uboot может содержать:
XIP Kernel Image ... OK
Последний код будет считывать только необходимый размер на основе информации заголовка uImage/boot.img, и этот элемент оптимизации можно игнорировать.
Для старых кодов, когда uboot загружает ядро, в некоторых случаях uboot-2018 автоматически считывает весь раздел. Прочтите размер образа ядра.
То есть, если ядро имеет только 2М, а раздел — 4М, uboot будет читать 4М. В этом случае его можно разделить на Размер области установлен ровно настолько, чтобы вместить ядро, что предотвращает потерю времени uboot при загрузке ядра.
Схема nor изменяет размер загрузочного раздела sys_partiton_nor.fex.
nand/emmc может изменить размер загрузочного раздела в sys_partition.fex.
Конкретный размер, считываемый uboot, обычно содержит информацию журнала, которую можно сравнить с размером реального образа ядра.
После того, как uboot загрузит ядро, он проверит ядро по умолчанию, что можно увидеть в выводе последовательного порта:
Verifying Checksum ... OK
Если проверять не хотите, то можете удалить. В текущей ситуации его можно сократить на десятки миллисекунд (разные платформы, разные размеры ядра, разное время). время запуска.
В частности, измените файл конфигурации env (путь см. выше) и добавьте новую строку «verify=no».
В текущем процессе запуска uboot выполнит перемещение во время выполнения. Это значение можно распечатать в последовательном порту, а затем. Измените адрес загрузки uboot так, чтобы когда boot0 загружал uboot в DRAM, он загружался непосредственно по этому адресу.
c #define CONFIG_SYS_TEXT_BASE=0x
c CONFIG_SYS_TEXT_BASE=0x
Однако у этого метода есть недостаток. Если впоследствии код uboot будет изменен, возможно, его придется сбросить.
В настоящее время эта операция занимает очень мало времени (на определенной платформе оно превышает десять миллисекунд). Не рекомендуется вносить эту модификацию, если в ней нет необходимости.
Даже если процесс не упрощать, уменьшение размера uboot может сократить время загрузки uboot.
В зависимости от конкретной ситуации модули с функциями, которые не требуются uboot, можно обрезать, чтобы избежать ненужных процессов при запуске. Уменьшите время загрузки uboot.
Вы можете попробовать включить загрузочный логотип/музыку в uboot, чтобы как можно скорее воспроизвести первый кадр/звук, чтобы улучшить взаимодействие с пользователем.
Эта операция задержит время достижения ОС/приложения, но если определение продукта/пользовательский опыт основаны на первом кадре/звуке, это будет более эффективно. Отличное соотношение цены и качества.
Вообще говоря, запуск ядра занимает больше времени и требует более глубокой оптимизации.
Сравните время запуска и использование флэш-памяти при различных методах сжатия и выберите тот, который соответствует реальной ситуации.
Определенные результаты испытаний приведены здесь для справки. При фактической оптимизации вам необходимо провести повторное тестирование и сделать выбор, исходя из реальной ситуации.
Метод сжатия | Размер ядра/М | Время загрузки/с | Время декомпрессии/с | Общее время/с |
---|---|---|---|---|
LZO | 2.4 | 0.38 | 0.23 | 0.61 |
GZIP | 1.9 | 0.35 | 0.44 | 0.79 |
XZ | 1.5 | 0.25 | 2.17 | 2.42 |
Образ ядра может быть распакован ядром самостоятельно или с помощью uboot.
В случае самораспаковки ядра, если адрес сжатого ядра конфликтует с адресом распакованного ядра, оно сначала распакует себя. Скопируйте в безопасное место, а затем разархивируйте, чтобы предотвратить самоперезапись. Это требует времени на копирование.
Например, для ядра, работающего по адресу 0x40008000, загрузчик может загрузить его по адресу 0x41008000. Конечно, возможны и другие места.
Отсечение ядра приводит к ускорению двумя способами. Во-первых, становится меньше размер и сокращается время загрузки и декомпрессии, во-вторых, исходное;
контента становится меньше.
Адаптация должна основываться на реальной ситуации с продуктом, а ненужные функции и модули должны быть удалены.
В частности, выполните «make kernel_menuconfig» и отключите ненужные параметры. Пожалуйста, обратитесь к «Руководству по разработке системной адаптации TinaLinux_». Юг.pdf》.
LPJ — это циклическое значение_per_jiffy, которое вычисляется при каждом запуске. Однако, если не вноситься никаких изменений, это значение будет рассчитываться при каждом запуске. Все расчеты одинаковы, и вы можете напрямую указать числовое значение, чтобы пропустить расчет.
Как показано в следующем журнале, он пропускается, lpj рассчитывается по таймеру, и нет необходимости калибровать калибровку.
[ 0.019918] Calibrating delay loop (skipped), value calculated using timer frequency..
48.00 BogoMIPS (lpj=240000)
Если ничего не пропущено, вы можете добавить lpj=XXX в cmdline для предустановки.
Установите initcall_debug=1 в cmdline, чтобы печатать и отслеживать последовательность вызовов initcall во время всех процессов инициализации ядра. последовательность и трудоемкость.
В частности, измените файл конфигурации env (путь см. выше), добавьте новую строку «initcall_debug=1» и добавьте «setargs_*» после « initcall_debug=${initcall_debug}", как показано ниже.
setargs_nand=setenv bootargs console=${console} console=tty0 root=${nand_root} init=${init}
loglevel=${loglevel} partitions=${partitions} initcall_debug=${initcall_debug}
После его добавления при запуске ядра появится сообщение, подобное следующему. Для трудоемкого initcall можно провести глубокую оптимизацию.
[ 0.021772] initcall sunxi_pinctrl_init+0x0/0x44 returned 0 after 9765 usecs
[ 0.067694] initcall param_sysfs_init+0x0/0x198 returned 0 after 29296 usecs
[ 0.070240] initcall genhd_device_init+0x0/0x88 returned 0 after 9765 usecs
[ 0.080405] initcall init_scsi+0x0/0x90 returned 0 after 9765 usecs
[ 0.090384] initcall mmc_init+0x0/0x84 returned 0 after 9765 usecs
инициализационный вызов Существует множество уровней ядра. Среди них самая трудоемкая часть запуска середина — это инициализация каждого модуля. Для многоядерных решений можно. рассмотреть модуль initcalls выполняются параллельно для экономии времени.
В настоящее время вызовы do_initcalls ядра выполняются один за другим и могут быть изменены для создания нового потока ядра для выполнения.
Примечание. Тина еще не добавила эту оптимизацию.
После добавления печати initcall некоторые платформы обнаружили, что инициализация pty/tty занимает много времени, и это число можно уменьшить, чтобы сократить время инициализации.
initcall pty_init+0x0/0x3c4 returned 0 after 239627 usecs
initcall chr_dev_init+0x0/0xdc returned 0 after 36581 usecs
Необходимо учитывать определение скорости запуска. Есть два основных момента по оптимизации модуля ядра:
Например, если приложение открывает основной интерфейс для работы в сети, а скорость запуска зависит от внешнего вида основного интерфейса, то вы можете рассмотреть возможность включения в него disp. Ядро и Wi-Fi компилируются в модули, а затем динамически загружаются, когда это необходимо.
Вводная страница и патч: http://elinux.org/Deferred_Initcalls.
После применения этого патча вы можете пометить некоторые инициализирующие вызовы как Deferred_Initcall. Эти отмеченные функции инициализации номер, не будет вызываться при запуске системы
После входа в файловую систему в подходящее время, например, после запуска основного приложения, запустите эти отложенные приложения через интерфейс файловой системы. вызов для полного завершения инициализации.
Оптимизация запуска Rootfs в основном предназначена для оптимизации монтирования rootfs при выполнении процесса инициализации.
initramfs — это файловая система памяти, которая занимает больше DRAM.
Некоторые продукты могут использовать initramfs для перехода на rootfs, и их идеи по оптимизации в целом аналогичны rootfs. Пожалуйста, обратитесь к этому разделу План дальнейшей оптимизации.
жить середина, тип файловой системы, метод сжатия оказывает большое влияние на монтирование rootfs.
Определенные результаты испытаний приведены здесь для справки. При фактической оптимизации вам необходимо провести повторное тестирование и сделать выбор, исходя из реальной ситуации.
тип | сжатие | середина | Общее время/с |
---|---|---|---|
squashfs | gzip | emmc | 0.12 |
squashfs | xz | emmc | 0.27 |
squashfs | xz | nand | 0.26 |
ext4 | - | emmc | 0.12 |
Чем меньше файловая система, тем быстрее она загружается. Основная идея обрезки заключается в следующем: удалить и заменить, то есть удалить неиспользуемые части и заменить их более мелкими.
, выберите подходящий метод сжатия.
Когда ядро существует, монтирует rootfs,Встреча Идет пробный процесс типа файловой системы. Вы можете указать это напрямую с помощью cmdline,Экономьте время между.
Конкретносуществоватьcmdlineсерединадобавить в"rootfstype=",Его серединатип — это тип файловой системы.,нравитьсяext4、squashfs ждать.
Для узлов в рамках разработки можно создавать их заранее в соответствии с реальной ситуацией, а не динамически генерировать их после запуска системы. сэкономь немного временимежду.
Rootfs можно разделить на две части: небольшая файловая система монтируется и выполняется первой, а большая файловая система монтируется динамически по мере необходимости. нагрузка.
Основное приложение в основном разрабатывается клиентами, поэтому именно клиенты берут на себя инициативу по оптимизации. Вот некоторые меры по оптимизации:
Оптимизация запуска в Tina в основном опирается на макрос CONFIG_BOOT_TIME_OPTIMIZATION. Этот макрос выполнит следующие шаги: Следующая работа:
Примечание. Предполагается, что с помощью этого макроса можно достичь около 70 % эффекта оптимизации. Если оптимизация все же необходима, обратитесь к содержанию Главы 2.
Выполните команду make menuconfig в корневом каталоге tina, чтобы включить CONFIG_BOOT_TIME_OPTIMIZATION. Подробности следующие:
Tina Configuration
└─> Target Images
└─>[*] kernel compression mode setting ----
└─>Compression (Gzip) --->
└─> ( ) Gzip
( ) LZMA
( ) XZ
(X) LZO
└─>[*] Boot Time Optimization
Примечание. Если вы не видите эту опцию, используйте ? Выполните поиск по ключу, и вы обнаружите, что этот элемент имеет некоторые параметры зависимости. Вы можете увидеть это, включив параметры зависимости.
Boot Time Optimization
После включения CONFIG_BOOT_TIME_OPTIMIZATION в определенном решении norflash скорость запуска увеличивается. следующее:
Примечание. Для различных решений в зависимости от скорости вычислений ЦП, размера памяти, размера и размера ядра, размера и размера корневой файловой системы,
В зависимости от размера, основного приложения и т. д. результаты оптимизации будут иметь определенные различия. См. фактические результаты оптимизации.