این صفحه نکاتی برای بهبود زمان بوت ارائه میدهد.
نمادهای اشکالزدایی را از ماژولها حذف کنید
مشابه نحوه حذف نمادهای اشکالزدایی از هسته در یک دستگاه عملیاتی، مطمئن شوید که نمادهای اشکالزدایی را از ماژولها نیز حذف میکنید. حذف نمادهای اشکالزدایی از ماژولها با کاهش موارد زیر به زمان بوت شدن کمک میکند:
- مدت زمانی که طول میکشد تا فایلهای باینری از فلش خوانده شوند.
- مدت زمانی که طول میکشد تا ramdisk از حالت فشرده خارج شود.
- مدت زمان لازم برای بارگذاری ماژولها.
حذف نماد اشکالزدایی از ماژولها ممکن است در طول بوت شدن چندین ثانیه صرفهجویی کند.
حذف نمادها به طور پیشفرض در ساخت پلتفرم اندروید فعال است، اما برای فعال کردن صریح آنها، BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES را در پیکربندی مخصوص دستگاه خود در زیر device/ vendor / device تنظیم کنید.
از فشردهسازی LZ4 برای هسته و رمدیسک استفاده کنید
Gzip در مقایسه با LZ4 خروجی فشردهشدهی کوچکتری تولید میکند، اما LZ4 سریعتر از Gzip از حالت فشرده خارج میشود. برای هسته و ماژولها، کاهش مطلق حجم ذخیرهسازی با استفاده از Gzip در مقایسه با مزیت زمان رفع فشار LZ4 چندان قابل توجه نیست.
پشتیبانی از فشردهسازی رمدیسک LZ4 از طریق BOARD_RAMDISK_USE_LZ4 به نسخه ساخت پلتفرم اندروید اضافه شده است. میتوانید این گزینه را در پیکربندی مخصوص دستگاه خود تنظیم کنید. فشردهسازی هسته را میتوان از طریق kernel defconfig تنظیم کرد.
تغییر به LZ4 باید زمان بوت را ۵۰۰ تا ۱۰۰۰ میلیثانیه سریعتر کند.
از ورود بیش از حد به درایورهای خود خودداری کنید
در ARM64 و ARM32، فراخوانیهای تابعی که بیش از یک فاصله مشخص از محل فراخوانی هستند، برای رمزگذاری آدرس کامل پرش، به یک جدول پرش (به نام جدول پیوند رویه یا PLT) نیاز دارند. از آنجایی که ماژولها به صورت پویا بارگذاری میشوند، این جداول پرش باید در طول بارگذاری ماژول اصلاح شوند. فراخوانیهایی که نیاز به جابجایی دارند، ورودیهای جابجایی با افزودنیهای صریح (یا به اختصار RELA) در قالب ELF نامیده میشوند.
هسته لینوکس هنگام تخصیص PLT، بهینهسازی اندازه حافظه (مانند بهینهسازی میزان مصرف حافظه پنهان) را انجام میدهد. با این کامیت بالادستی ، طرح بهینهسازی دارای پیچیدگی O(N^2) است، که در آن N تعداد RELAهای نوع R_AARCH64_JUMP26 یا R_AARCH64_CALL26 است. بنابراین داشتن RELAهای کمتر از این نوعها در کاهش زمان بارگذاری ماژول مفید است.
یکی از الگوهای کدنویسی رایج که تعداد R_AARCH64_CALL26 یا R_AARCH64_JUMP26 RELA را افزایش میدهد، ثبت بیش از حد وقایع در یک درایور است. هر فراخوانی printk() یا هر طرح ثبت وقایع دیگر معمولاً یک ورودی CALL26 / JUMP26 RELA اضافه میکند. در متن کامیت در کامیت بالادستی ، توجه کنید که حتی با بهینهسازی، بارگذاری شش ماژول حدود ۲۵۰ میلیثانیه طول میکشد - به این دلیل که این شش ماژول، شش ماژول برتر با بیشترین میزان ثبت وقایع بودند.
کاهش ثبت وقایع میتواند حدود ۱۰۰ تا ۳۰۰ میلیثانیه در زمان بوت صرفهجویی کند، البته بسته به اینکه ثبت وقایع موجود چقدر زیاد باشد.
فعال کردن کاوش ناهمزمان، به صورت انتخابی
وقتی یک ماژول بارگذاری میشود، اگر دستگاهی که از آن پشتیبانی میکند قبلاً از DT (devicetree) پر شده و به هسته درایور اضافه شده باشد، کاوش دستگاه در چارچوب فراخوانی module_init() انجام میشود. وقتی کاوش دستگاه در چارچوب module_init() انجام میشود، ماژول نمیتواند بارگذاری را تا زمانی که کاوش کامل شود، به پایان برساند. از آنجایی که بارگذاری ماژول عمدتاً سریالی است، دستگاهی که کاوش آن زمان نسبتاً زیادی طول میکشد، زمان بوت را کند میکند.
برای جلوگیری از زمان بوت کندتر، کاوش ناهمزمان را برای ماژولهایی که مدتی طول میکشد تا دستگاههای خود را کاوش کنند، فعال کنید. فعال کردن کاوش ناهمزمان برای همه ماژولها ممکن است مفید نباشد زیرا زمان لازم برای انشعاب یک رشته و شروع کاوش ممکن است به اندازه زمان لازم برای کاوش دستگاه باشد.
دستگاههایی که از طریق یک گذرگاه کند مانند I2C متصل میشوند، دستگاههایی که بارگذاری میانافزار را در تابع پروب خود انجام میدهند و دستگاههایی که مقدار زیادی راهاندازی سختافزار انجام میدهند، میتوانند منجر به مشکل زمانبندی شوند. بهترین راه برای شناسایی زمان وقوع این اتفاق، جمعآوری زمان پروب برای هر درایور و مرتبسازی آن است.
برای فعال کردن کاوش ناهمزمان برای یک ماژول، فقط تنظیم پرچم PROBE_PREFER_ASYNCHRONOUS در کد درایور کافی نیست . برای ماژولها، باید module_name .async_probe=1 نیز در خط فرمان هسته اضافه کنید یا هنگام بارگذاری ماژول با استفاده modprobe یا insmod async_probe=1 را به عنوان پارامتر ماژول ارسال کنید.
فعال کردن کاوش ناهمزمان میتواند بسته به سختافزار/درایور شما، حدود ۱۰۰ تا ۵۰۰ میلیثانیه در زمان بوت صرفهجویی کند.
درایور CPUfreq خود را در اسرع وقت بررسی کنید
هرچه درایور CPUfreq شما زودتر بررسی کند، زودتر میتوانید فرکانس CPU را در طول بوت به حداکثر (یا حداکثری که از نظر حرارتی محدود شده است) برسانید. هرچه CPU سریعتر باشد، بوت سریعتر خواهد بود. این دستورالعمل همچنین در مورد درایورهای devfreq که فرکانس DRAM، حافظه و اتصالات داخلی را کنترل میکنند، صدق میکند.
در مورد ماژولها، ترتیب بارگذاری میتواند به سطح initcall ) و ترتیب کامپایل یا لینک درایورها بستگی داشته باشد. از یک نام مستعار MODULE_SOFTDEP() استفاده کنید تا مطمئن شوید که درایور cpufreq جزو چند ماژول اول برای بارگذاری است.
جدا از بارگذاری زودهنگام ماژول، باید مطمئن شوید که تمام وابستگیهای لازم برای بررسی درایور CPUfreq نیز بررسی شدهاند. به عنوان مثال، اگر برای کنترل فرکانس پردازنده خود به یک دسته کلاک یا تنظیمکننده نیاز دارید، مطمئن شوید که ابتدا آنها بررسی شدهاند. یا اگر احتمال دارد پردازندههای شما هنگام بوت شدن خیلی داغ شوند، ممکن است لازم باشد درایورهای حرارتی قبل از درایور CPUfreq بارگذاری شوند. بنابراین، هر کاری از دستتان برمیآید انجام دهید تا مطمئن شوید که درایورهای CPUfreq و devfreq مربوطه در اسرع وقت بررسی میشوند.
صرفهجویی حاصل از بررسی زودهنگام درایور CPUfreq میتواند بسیار کم تا بسیار زیاد باشد، بسته به اینکه چقدر زود بتوانید این بررسی را انجام دهید و بوتلودر با چه فرکانسی CPUها را فعال نگه میدارد.
ماژولها را به پارتیشن init مرحله دوم، vendor یا vendor_dlkm منتقل کنید
از آنجا که فرآیند راهاندازی مرحله اول به صورت سریالی انجام میشود، فرصتهای زیادی برای موازیسازی فرآیند بوت وجود ندارد. اگر ماژولی برای اتمام راهاندازی مرحله اول مورد نیاز نیست، با قرار دادن آن در پارتیشن vendor یا vendor_dlkm ، ماژول را به راهاندازی مرحله دوم منتقل کنید.
راهاندازی اولیه مرحله اول نیازی به بررسی چندین دستگاه برای رسیدن به راهاندازی اولیه مرحله دوم ندارد. فقط قابلیتهای کنسول و حافظه فلش برای یک جریان بوت عادی مورد نیاز است.
درایورهای ضروری زیر را بارگیری کنید:
-
watchdog -
reset -
cpufreq
برای بازیابی و حالت fastbootd فضای کاربر، init مرحله اول به دستگاههای بیشتری برای بررسی (مانند USB) و نمایش نیاز دارد. یک کپی از این ماژولها را در ramdisk مرحله اول و در پارتیشن vendor یا vendor_dlkm نگه دارید. این به آنها اجازه میدهد تا در init مرحله اول برای بازیابی یا جریان بوت fastbootd بارگذاری شوند. با این حال، ماژولهای حالت بازیابی را در init مرحله اول در طول جریان بوت عادی بارگذاری نکنید. ماژولهای حالت بازیابی را میتوان به init مرحله دوم موکول کرد تا زمان بوت کاهش یابد. تمام ماژولهای دیگری که در init مرحله اول مورد نیاز نیستند باید به پارتیشن vendor یا vendor_dlkm منتقل شوند.
با داشتن لیستی از دستگاههای برگ (مثلاً UFS یا سریال)، اسکریپت dev needs.sh تمام درایورها، دستگاهها و ماژولهای مورد نیاز برای وابستگیها یا تأمینکنندهها (مثلاً کلاکها، رگولاتورها یا gpio ) را برای بررسی پیدا میکند.
انتقال ماژولها به مرحله دوم init، زمان بوت را به روشهای زیر کاهش میدهد:
- کاهش حجم رمدیسک
- این باعث میشود وقتی بوتلودر، رمدیسک (مرحله بوت سریالی) را بارگذاری میکند، سرعت خواندن فلش افزایش یابد.
- این باعث میشود وقتی هسته، ramdisk (مرحله بوت سریالی) را از حالت فشرده خارج میکند، سرعت خارج کردن از حالت فشرده افزایش یابد.
- init مرحله دوم به صورت موازی کار میکند، که زمان بارگذاری ماژول را با کاری که در init مرحله دوم انجام میشود، پنهان میکند.
انتقال ماژولها به مرحله دوم میتواند بسته به تعداد ماژولهایی که میتوانید به مرحله دوم راهاندازی (init) منتقل کنید ، ۵۰۰ تا ۱۰۰۰ میلیثانیه در زمان بوت صرفهجویی کند.
تدارکات بارگیری ماژول
جدیدترین نسخه اندروید شامل پیکربندیهای بورد است که کنترل میکند کدام ماژولها به هر مرحله کپی شوند و کدام ماژولها بارگذاری شوند. این بخش بر زیرمجموعههای زیر تمرکز دارد:
-
BOARD_VENDOR_RAMDISK_KERNEL_MODULES. این لیست ماژولهایی است که باید در ramdisk کپی شوند. -
BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD. این لیست از ماژولهایی است که باید در مرحله اول init بارگذاری شوند. -
BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD. این لیست از ماژولهایی است که هنگام انتخاب recovery یاfastbootdاز ramdisk بارگذاری میشوند. -
BOARD_VENDOR_KERNEL_MODULES. این لیست از ماژولها باید در پارتیشن vendor یاvendor_dlkmدر دایرکتوری/vendor/lib/modules/کپی شوند. -
BOARD_VENDOR_KERNEL_MODULES_LOAD. این لیست از ماژولهایی است که باید در مرحله دوم init بارگذاری شوند.
ماژولهای بوت و ریکاوری در ramdisk نیز باید در پارتیشن vendor یا vendor_dlkm در /vendor/lib/modules کپی شوند. کپی کردن این ماژولها در پارتیشن vendor تضمین میکند که ماژولها در طول init مرحله دوم نامرئی نیستند، که برای اشکالزدایی و جمعآوری modinfo برای گزارشهای خطا مفید است.
این تکثیر باید حداقل فضای ممکن را در پارتیشن vendor یا vendor_dlkm اشغال کند، البته تا زمانی که مجموعه ماژولهای بوت به حداقل برسد. مطمئن شوید که فایل modules.list فروشنده دارای لیست فیلتر شدهای از ماژولها در /vendor/lib/modules باشد. لیست فیلتر شده تضمین میکند که زمان بوت تحت تأثیر بارگذاری مجدد ماژولها (که یک فرآیند پرهزینه است) قرار نگیرد.
مطمئن شوید که ماژولهای حالت ریکاوری به صورت گروهی بارگذاری میشوند. بارگذاری ماژولهای حالت ریکاوری میتواند یا در حالت ریکاوری یا در ابتدای مرحله دوم init در هر جریان بوت انجام شود.
شما میتوانید از فایلهای Board.Config.mk دستگاه برای انجام این اقدامات، همانطور که در مثال زیر مشاهده میکنید، استفاده کنید:
# All kernel modules
KERNEL_MODULES := $(wildcard $(KERNEL_MODULE_DIR)/*.ko)
KERNEL_MODULES_LOAD := $(strip $(shell cat $(KERNEL_MODULE_DIR)/modules.load)
# First stage ramdisk modules
BOOT_KERNEL_MODULES_FILTER := $(foreach m,$(BOOT_KERNEL_MODULES),%/$(m))
# Recovery ramdisk modules
RECOVERY_KERNEL_MODULES_FILTER := $(foreach m,$(RECOVERY_KERNEL_MODULES),%/$(m))
BOARD_VENDOR_RAMDISK_KERNEL_MODULES += \
$(filter $(BOOT_KERNEL_MODULES_FILTER) \
$(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES))
# ALL modules land in /vendor/lib/modules so they could be rmmod/insmod'd,
# and modules.list actually limits us to the ones we intend to load.
BOARD_VENDOR_KERNEL_MODULES := $(KERNEL_MODULES)
# To limit /vendor/lib/modules to just the ones loaded, use:
# BOARD_VENDOR_KERNEL_MODULES := $(filter-out \
# $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES))
# Group set of /vendor/lib/modules loading order to recovery modules first,
# then remainder, subtracting both recovery and boot modules which are loaded
# already.
BOARD_VENDOR_KERNEL_MODULES_LOAD := \
$(filter-out $(BOOT_KERNEL_MODULES_FILTER), \
$(filter $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)))
BOARD_VENDOR_KERNEL_MODULES_LOAD += \
$(filter-out $(BOOT_KERNEL_MODULES_FILTER) \
$(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))
# NB: Load order governed by modules.load and not by $(BOOT_KERNEL_MODULES)
BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD := \
$(filter $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))
# Group set of /vendor/lib/modules loading order to boot modules first,
# then the remainder of recovery modules.
BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD := \
$(filter $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))
BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD += \
$(filter-out $(BOOT_KERNEL_MODULES_FILTER), \
$(filter $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)))
این مثال، زیرمجموعهای از BOOT_KERNEL_MODULES و RECOVERY_KERNEL_MODULES را که مدیریت آسانتری دارند و باید به صورت محلی در فایلهای پیکربندی برد مشخص شوند، به نمایش میگذارد. اسکریپت قبلی، هر یک از ماژولهای زیرمجموعه را از ماژولهای هسته موجود انتخاب شده پیدا و پر میکند و ماژولهای reamining را برای init مرحله دوم باقی میگذارد.
برای شروع مرحله دوم، توصیه میکنیم بارگذاری ماژول را به عنوان یک سرویس اجرا کنید تا جریان بوت را مسدود نکند. از یک اسکریپت پوسته برای مدیریت بارگذاری ماژول استفاده کنید تا در صورت لزوم، سایر تدارکات، مانند مدیریت و کاهش خطا یا تکمیل بارگذاری ماژول، قابل گزارش (یا نادیده گرفتن) باشند.
شما میتوانید خطای بارگذاری ماژول اشکالزدایی که در نسخههای کاربری وجود ندارد را نادیده بگیرید. برای نادیده گرفتن این خطا، ویژگی vendor.device.modules.ready را طوری تنظیم کنید که مراحل بعدی بوتفلو اسکریپتنویسی init rc را برای ادامه در صفحه راهاندازی، فعال کند. اگر کد زیر را در /vendor/etc/init.insmod.sh دارید ، به اسکریپت نمونه زیر مراجعه کنید:
#!/vendor/bin/sh
. . .
if [ $# -eq 1 ]; then
cfg_file=$1
else
# Set property even if there is no insmod config
# to unblock early-boot trigger
setprop vendor.common.modules.ready
setprop vendor.device.modules.ready
exit 1
fi
if [ -f $cfg_file ]; then
while IFS="|" read -r action arg
do
case $action in
"insmod") insmod $arg ;;
"setprop") setprop $arg 1 ;;
"enable") echo 1 > $arg ;;
"modprobe") modprobe -a -d /vendor/lib/modules $arg ;;
. . .
esac
done < $cfg_file
fi
در فایل rc سختافزار، سرویس one shot میتواند با دستور زیر مشخص شود:
service insmod-sh /vendor/etc/init.insmod.sh /vendor/etc/init.insmod.<hw>.cfg
class main
user root
group root system
Disabled
oneshot
بهینهسازیهای اضافی را میتوان پس از انتقال ماژولها از مرحله اول به مرحله دوم انجام داد. میتوانید از ویژگی modprobe blocklist برای تقسیم جریان بوت مرحله دوم استفاده کنید تا بارگذاری ماژولهای غیرضروری به تعویق افتاده را نیز شامل شود. بارگذاری ماژولهایی که منحصراً توسط یک HAL خاص استفاده میشوند را میتوان به تعویق انداخت تا ماژولها فقط هنگام شروع HAL بارگذاری شوند.
برای بهبود زمان بوت ظاهری، میتوانید بهطور خاص ماژولهایی را در سرویس بارگذاری ماژول انتخاب کنید که برای بارگذاری پس از صفحه راهاندازی مناسبتر باشند. بهعنوان مثال، میتوانید بهطور صریح ماژولهای مربوط به رمزگشای ویدیو یا Wi-Fi را پس از پاک شدن جریان بوت اولیه (مثلاً سیگنال ویژگی sys.boot_complete Android) با تأخیر بارگذاری کنید. مطمئن شوید که HALها برای ماژولهای با تأخیر بارگذاری، زمانی که درایورهای هسته وجود ندارند، بهاندازه کافی طولانی مسدود میشوند.
به عنوان یک روش جایگزین، میتوانید از دستور wait<file>[<timeout>] در اسکریپتنویسی جریان بوت rc برای منتظر ماندن برای ورودیهای sysfs انتخاب شده استفاده کنید تا نشان دهید که ماژولهای درایور عملیات بررسی را تکمیل کردهاند. نمونهای از این حالت، انتظار برای تکمیل بارگذاری درایور نمایشگر در پسزمینه recovery یا fastbootd قبل از نمایش گرافیک منو است.
فرکانس پردازنده را در بوت لودر به مقدار معقولی تنظیم کنید
ممکن است همه SoCها/محصولات به دلیل نگرانیهای حرارتی یا توان در طول تستهای حلقه بوت، نتوانند CPU را در بالاترین فرکانس بوت کنند. با این حال، مطمئن شوید که بوتلودر فرکانس همه CPUهای آنلاین را تا حد امکان ایمن برای SoC یا محصول تنظیم میکند. این بسیار مهم است زیرا با یک هسته کاملاً ماژولار، فشردهسازی init ramdisk قبل از بارگذاری درایور CPUfreq انجام میشود. بنابراین، اگر CPU توسط بوتلودر در انتهای فرکانس پایین خود قرار گیرد، زمان فشردهسازی ramdisk میتواند بیشتر از یک هسته کامپایل شده استاتیک (پس از تنظیم اختلاف اندازه ramdisk) طول بکشد زیرا فرکانس CPU هنگام انجام کارهای فشرده CPU (فشردهسازی) بسیار پایین خواهد بود. همین امر در مورد فرکانس حافظه و اتصالات داخلی نیز صدق میکند.
مقداردهی اولیه فرکانس پردازندههای بزرگ در بوتلودر
قبل از بارگذاری درایور CPUfreq ، هسته از فرکانسهای CPU بیاطلاع است و ظرفیت زمانبندی CPU را برای فرکانس فعلی آنها مقیاسبندی نمیکند. اگر بار روی CPU کوچک به اندازه کافی زیاد باشد، هسته ممکن است نخها را به CPU بزرگتر منتقل کند.
مطمئن شوید که پردازندههای بزرگ حداقل در فرکانسی که بوتلودر آنها را در نظر میگیرد، به اندازه پردازندههای کوچک عملکرد داشته باشند. برای مثال، اگر پردازنده بزرگ در فرکانس یکسان، دو برابر پردازنده کوچک عملکرد داشته باشد، اما بوتلودر فرکانس پردازنده کوچک را روی ۱.۵ گیگاهرتز و فرکانس پردازنده بزرگ را روی ۳۰۰ مگاهرتز تنظیم کند، در صورت انتقال هسته به پردازنده بزرگ، عملکرد بوت کاهش مییابد. در این مثال، اگر بوت کردن پردازنده بزرگ با فرکانس ۷۵۰ مگاهرتز بیخطر باشد، باید این کار را انجام دهید، حتی اگر قصد ندارید صریحاً از آن استفاده کنید.
درایورها نباید در مرحله اول راهاندازی، میانافزار را بارگذاری کنند
ممکن است موارد اجتنابناپذیری وجود داشته باشد که در آنها نیاز به بارگذاری میانافزار در مرحله اول init باشد. اما بهطورکلی، درایورها نباید هیچ میانافزاری را در مرحله اول init بارگذاری کنند، بهویژه در زمینه بررسی دستگاه. بارگذاری میانافزار در مرحله اول init باعث میشود کل فرآیند بوت متوقف شود اگر میانافزار در ramdisk مرحله اول در دسترس نباشد. و حتی اگر میانافزار در ramdisk مرحله اول وجود داشته باشد، باز هم باعث تأخیر غیرضروری میشود.