این صفحه نکاتی برای بهبود زمان راهاندازی ارائه میدهد.
حذف نمادهای اشکالزدایی از پیمانهها
مشابه با نحوه حذف نمادهای اشکالزدایی از هسته در دستگاه تولید، مطمئن شوید که نمادهای اشکالزدایی را از واحدها نیز حذف کنید. حذف نمادهای اشکالزدایی از واحدها با کاهش موارد زیر به زمان راهاندازی کمک میکند:
- مدتزمان لازم برای خواندن فایلهای باینری از حافظه فلش.
- مدت زمانی که برای ازهم فشرده کردن ramdisk لازم است.
- مدت زمانی که طول میکشد تا واحدها بار شوند.
حذف نماد اشکالزدایی از واحدها ممکن است چند ثانیه درطول راهاندازی صرفهجویی کند.
حذف نماد بهطور پیشفرض در ساخت پلاتفرم Android فعال است، اما
برای فعال کردن صریح آنها،
BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES را در پیکربندی ویژه دستگاه
در device/vendor/device تنظیم کنید.
استفاده از فشردهسازی LZ4 برای هسته و ramdisk
Gzip در مقایسه با LZ4 برونداد فشرده کوچکتری تولید میکند، اما LZ4 سریعتر از Gzip فشردهسازی را انجام میدهد. برای هسته و واحدها، کاهش اندازه فضای ذخیرهسازی مطلق ناشی از استفاده از Gzip در مقایسه با مزیت زمان باز کردن فشرده LZ4 چندان قابلتوجه نیست.
پشتیبانی از فشردهسازی دیسک مجازی LZ4 به ساخت پلاتفرم Android ازطریق BOARD_RAMDISK_USE_LZ4 اضافه شده است. میتوانید این گزینه را در پیکربندی
ویژه دستگاهتان تنظیم کنید. فشردهسازی هسته را میتوان ازطریق defconfig هسته تنظیم کرد.
با جابهجایی به LZ4، زمان راهاندازی ۵۰۰ تا ۱۰۰۰ میلیثانیه سریعتر میشود.
از ثبت گزارش بیشازحد در درایورهایتان خودداری کنید
در ARM64 و ARM32، فراخوانیهای تابع که بیشتر از فاصله مشخصی از سایت فراخوانی هستند، به جدول پرش (بهنام جدول پیوند رویه، یا PLT) نیاز دارند تا بتوانند نشانی پرش کامل را کدگذاری کنند. ازآنجاییکه واحدها بهصورت پویا بار میشوند، این جدولهای پرش باید درطول بار واحد اصلاح شوند. فراخوانهایی که نیاز به جابهجایی دارند، ورودیهای جابهجایی با افزایههای صریح (یا بهاختصار RELA) در قالب ELF نامیده میشوند.
هسته Linux هنگام اختصاص دادن PLT، برخی بهینهسازیهای اندازه حافظه (مانند بهینهسازی اصابت حافظه نهان) را انجام میدهد. با این تعهد
بالادستی،
طرح بهینهسازی دارای پیچیدگی O(N^2) است، که در آن N تعداد
RELAs از نوع R_AARCH64_JUMP26 یا R_AARCH64_CALL26 است. بنابراین داشتن تعداد کمتر از این نوع RELA
در کاهش زمان بار کردن واحد مفید است.
یکی از الگوهای کدنویسی رایج که تعداد
R_AARCH64_CALL26 یا R_AARCH64_JUMP26 RELA را افزایش میدهد، ثبت گزارش بیشازحد در
راهانداز است. هر تماس با printk() یا هر طرح گزارشگیری دیگری معمولاً یک ورودی RELA CALL26/JUMP26 اضافه میکند. در متن تعهد در تعهد بالادستی،
توجه کنید که حتی با بهینهسازی، بار کردن شش واحد حدود ۲۵۰ میلیثانیه طول میکشد—به این دلیل که این شش واحد، شش واحد برتر با
بیشترین مقدار گزارشگیری بودند.
کاهش ثبت گزارش میتواند حدود ۱۰۰ تا ۳۰۰ میلیثانیه در زمانهای راهاندازی صرفهجویی کند، بسته به اینکه گزارشگیری موجود چقدر بیشازحد باشد.
فعال کردن کاوش ناهمزمان، بهصورت انتخابی
When a module is loaded, if the device that it supports has already been
populated from the DT (devicetree) and added to driver core, then the device
probe is done in the context of the module_init() call. وقتی کاوش دستگاه در بافت module_init() انجام میشود، واحد نمیتواند تا
کامل شدن کاوش بارگیری را تمام کند. ازآنجاییکه بار کردن واحد عمدتاً بهصورت سریال است، دستگاهی که
زمان نسبتاً طولانی برای کاوش نیاز دارد زمان راهاندازی را کند میکند.
برای جلوگیری از طولانیتر شدن زمان راهاندازی، کاوش ناهمگام را برای پیمانههایی که کاوش دستگاههایشان طول میکشد فعال کنید. فعال کردن کاوش ناهمزمان برای همه واحدها ممکن است مفید نباشد زیرا زمان لازم برای انشعاب یک رشته و شروع کاوش ممکن است به اندازه زمان لازم برای کاوش دستگاه باشد.
دستگاههایی که ازطریق گذرگاه کندی مثل I2C متصل شدهاند، دستگاههایی که بارگیری سفتافزار را در تابع کاوشگر خود انجام میدهند، و دستگاههایی که مقدار زیادی مقداردهی اولیه سختافزار انجام میدهند میتوانند منجر به مشکل زمانبندی شوند. بهترین راه برای شناسایی زمان وقوع این اتفاق، جمعآوری زمان کاوش برای هر راننده و مرتب کردن آن است.
برای فعال کردن کاوش ناهمزمان برای یک واحد، فقط تنظیم کردن پرچم PROBE_PREFER_ASYNCHRONOUS در کد درایور کافی نیست. برای واحدها، باید
module_name.async_probe=1 را در خط فرمان هسته
اضافه کنید یا async_probe=1 را بهعنوان پارامتر واحد هنگام بار کردن واحد بااستفاده از
modprobe یا insmod ارسال کنید.
فعال کردن کاوش ناهمگام میتواند حدود ۱۰۰ تا ۵۰۰ میلیثانیه در زمان راهاندازی صرفهجویی کند که به سختافزار/درایورهای شما بستگی دارد.
درایور CPUfreq را در اسرع وقت کاوش کنید
هرچه زودتر کاوشگر درایور CPUfreq را انجام دهید، زودتر میتوانید فرکانس CPU را درطول بوت به حداکثر (یا حداکثر محدودشده حرارتی) برسانید. هرچه
پردازنده سریعتر باشد، بوت سریعتر انجام میشود. این دستورالعمل برای درایورهای devfreq که فرکانس DRAM، حافظه، و اتصال داخلی را کنترل میکنند نیز اعمال میشود.
با واحدها، ترتیب بارگذاری میتواند به initcall سطح و
ترتیب پیوند یا ترجمه درایورها بستگی داشته باشد. از نام مستعار MODULE_SOFTDEP() استفاده کنید تا مطمئن شوید درایور cpufreq جزو اولین چند ماژولی است که بار میشود.
علاوهبر بار کردن زودهنگام ماژول، باید مطمئن شوید که همه وابستگیها برای کاوش درایور CPUfreq نیز کاوش شدهاند. برای مثال، اگر برای کنترل کردن بسامد واحد پردازش مرکزی (CPU) به ساعت یا دستگیره تنظیمکننده نیاز دارید، مطمئن شوید که ابتدا آنها را کاوش کنید. یا ممکن است لازم باشد درایورهای حرارتی قبلاز درایور CPUfreq بارگیری شوند، اگر این احتمال وجود دارد که CPU شما درطول راهاندازی بیشازحد داغ شود. بنابراین، هر کاری که میتوانید انجام دهید تا مطمئن شوید که CPUfreq و درایورهای devfreq مربوطه در اسرع وقت بررسی میشوند.
صرفهجویی در مصرف انرژی با کاوش زودهنگام درایور CPUfreq میتواند بسیار کم تا بسیار زیاد باشد، بسته به اینکه چقدر زود بتوانید این درایورها را کاوش کنید و بوتلودر CPUها را در چه فرکانسی قرار میدهد.
انتقال واحدها به مرحله دوم init، پارتیشن فروشنده یا vendor_dlkm
ازآنجاییکه فرایند اولیه مرحله اول سریالسازی میشود، فرصتهای زیادی برای موازیسازی فرایند راهاندازی وجود ندارد. اگر واحدی برای
تکمیل مرحله اول راهاندازی لازم نیست، با قرار دادن واحد در
بخش تأمینکننده یا vendor_dlkm، آن را به مرحله دوم راهاندازی منتقل کنید.
راهاندازی مرحله اول نیازی به کاوش چندین دستگاه برای رسیدن به راهاندازی مرحله دوم ندارد. برای جریان راهاندازی عادی، فقط قابلیتهای کنسول و حافظه فلش لازم است.
بار کردن درایورهای ضروری زیر:
watchdogresetcpufreq
برای بازیابی و حالت فضای کاربر fastbootd، مرحله اول راهاندازی به دستگاههای بیشتری برای کاوش (مانند USB) و نمایش نیاز دارد. نسخهای از این واحدها در
ramdisk مرحله اول و در پارتیشن فروشنده یا vendor_dlkm نگه داشته شود. این کار باعث میشود
در مرحله اول راهاندازی برای بازیابی یا جریان راهاندازی fastbootd بارگیری شوند. بااینحال،
در جریان راهاندازی عادی،
واحدهای حالت بازیابی را در مرحله اول init بار نکنید. واحدهای حالت بازیابی را میتوان به مرحله دوم مقداردهی اولیه موکول کرد تا زمان
راهاندازی کاهش یابد. همه واحدهای دیگر که در مرحله اولیه راهاندازی لازم نیستند باید به
تأمینکننده یا پارتیشن vendor_dlkm منتقل شوند.
با درنظر گرفتن فهرستی از دستگاههای برگ (برای مثال، UFS یا سریال)،
dev needs.sh
برنامه همه درایورها، دستگاهها، و واحدهای موردنیاز برای وابستگیها یا
تأمینکنندگان (برای مثال، ساعتها، تنظیمکنندهها، یا gpio) را برای کاوش پیدا میکند.
انتقال واحدها به مرحله دوم مقداردهی اولیه زمانهای راهاندازی را به روشهای زیر کاهش میدهد:
- کاهش اندازه Ramdisk.
- این کار باعث میشود وقتی راهانداز سیستم دیسک حافظه دسترسی تصادفی را بار میکند، خواندن فلش سریعتر انجام شود (مرحله راهاندازی سریالی).
- این کار باعث میشود وقتی هسته دیسک مجازی را از حالت فشرده خارج میکند (مرحله راهاندازی سریالی)، سرعت خارج کردن از حالت فشرده بیشتر شود.
- راهاندازی مرحله دوم بهصورت موازی کار میکند، که زمان بار کردن واحد را با کاری که در راهاندازی مرحله دوم انجام میشود پنهان میکند.
انتقال پیمانهها به مرحله دوم میتواند بسته به اینکه چند پیمانه را میتوانید به مرحله دوم راهاندازی منتقل کنید، ۵۰۰ تا ۱۰۰۰ میلیثانیه در زمانهای راهاندازی صرفهجویی کند.
تدارکات بارگیری واحد
جدیدترین ساختار Android دارای پیکربندیهای تختهای است که کنترل میکند کدام واحدها در هر مرحله کپی شوند و کدام واحدها بار شوند. این بخش روی زیرمجموعه زیر تمرکز دارد:
BOARD_VENDOR_RAMDISK_KERNEL_MODULES. این فهرست از ماژولها باید در دیسک RAM کپی شود.BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD. این فهرست واحدها در مرحله اول راهاندازی بار میشود.BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD. این فهرست واحدها برای بار شدن هنگام انتخاب بازیابی یاfastbootdاز ramdisk.BOARD_VENDOR_KERNEL_MODULES. این فهرست واحدها در پارتیشن فروشنده یاvendor_dlkmدر دایرکتوری/vendor/lib/modules/کپی میشود.BOARD_VENDOR_KERNEL_MODULES_LOAD. این فهرست از ماژولها در مرحله دوم راهاندازی بار میشود.
مدولهای راهاندازی و بازیابی در ramdisk نیز باید در فروشنده یا
vendor_dlkm پارتیشن در /vendor/lib/modules کپی شوند. کپی کردن این واحدها به
پارتیشن فروشنده تضمین میکند که واحدها درطول مقداردهی اولیه مرحله دوم نامرئی نباشند،
که برای اشکالزدایی و جمعآوری modinfo برای گزارشهای اشکال مفید است.
تا زمانی که مجموعه واحد راهاندازی به حداقل برسد، تکثیر باید حداقل فضای فروشنده یا vendor_dlkm
پارتیشن
را اشغال کند. مطمئن شوید که فایل
modules.list فروشنده دارای فهرست فیلترشدهای از ماژولها در /vendor/lib/modules باشد.
فهرست فیلترشده تضمین میکند که زمانهای راهاندازی تحت تأثیر بارگیری مجدد ماژولها (که فرایندی پرهزینه است) قرار نمیگیرد.
مطمئن شوید که واحدهای حالت بازیابی بهصورت گروهی بارگیری میشوند. بار کردن واحدهای حالت بازیابی میتواند در حالت بازیابی یا در ابتدای مرحله دوم راهاندازی در هر جریان راهاندازی انجام شود.
میتوانید از فایلهای دستگاه 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 را نشان میدهد که مدیریت آن آسانتر است و باید بهصورت محلی در فایلهای پیکربندی برد مشخص شود. برنامه قبلی هریک از واحدهای زیرمجموعه را از واحدهای هسته دردسترس انتخابشده پیدا و تکمیل میکند و واحدهای باقیمانده را برای مرحله دوم 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 برای تقسیم جریان راهاندازی مرحله دوم استفاده کنید تا بار کردن واحد معوقه واحدهای غیرضروری را دربر بگیرد. بار کردن ماژولهایی که منحصراً توسط HAL خاصی استفاده میشوند را میتوان بهتعویق انداخت تا ماژولها فقط هنگام شروع HAL بار شوند.
برای بهبود زمانهای راهاندازی ظاهری، میتوانید بهطور خاص واحدهایی را در
خدمات بارگیری واحد انتخاب کنید که برای بارگیری پساز صفحه
راهاندازی مناسبتر هستند. برای مثال، میتوانید ماژولهای مربوط به
رمزگشای ویدیو یا Wi-Fi را پساز پاک شدن جریان راهاندازی اولیه
(sys.boot_complete
سیگنال دارایی Android، برای مثال) بهطور صریح دیر بار کنید. مطمئن شوید که HALهای مربوط به واحدهای دیر بارگیری
وقتی درایورهای هسته وجود ندارند، بهاندازه کافی مسدود میشوند.
یا میتوانید از فرمان wait<file>[<timeout>] init در
نوشتن کد rc جریان راهاندازی برای منتظر ماندن برای نمایش ورودیهای sysfs انتخابشده استفاده کنید تا نشان دهد واحدهای درایور
عملکرد کاوش را تکمیل کردهاند. نمونهای از این مورد، انتظار برای تکمیل بارگیری درایور نمایشگر در پسزمینه بازیابی یا fastbootd، قبلاز ارائه گرافیک منو است.
فرکانس CPU را در راهانداز سیستم روی مقدار معقولی مقداردهی اولیه کنید
بهدلیل نگرانیهای حرارتی یا توان درطول آزمایشهای حلقه راهاندازی مجدد، ممکن است همه «سیستم روی تراشه»/ محصولات نتوانند CPU را در بالاترین فرکانس راهاندازی کنند. بااینحال، مطمئن شوید که راهانداز بوت فرکانس همه CPUهای آنلاین را تا جایی که برای SoC یا محصول ایمن است افزایش دهد. این بسیار مهم است زیرا با هسته کاملاً واحدی، فشردهسازی init ramdisk قبلاز بار شدن درایور CPUfreq انجام میشود. بنابراین، اگر بارگذارنده CPU را در پایینترین سطح فرکانس خود قرار دهد، زمان فشردهسازی ramdisk میتواند بیشتر از هسته کامپایلشده ایستا (پساز اصلاح تفاوت اندازه ramdisk) طول بکشد، زیرا فرکانس CPU در هنگام انجام کارهای فشرده CPU (فشردهسازی) بسیار پایین خواهد بود. همین امر برای حافظه و فراوانی اتصال متقابل نیز اعمال میشود.
مقداردهی اولیه فرکانس واحد پردازش مرکزی هستههای بزرگ در راهانداز سیستم
قبلاز بار شدن درایور CPUfreq، هسته از
فرکانسهای CPU مطلع نیست و ظرفیت زمانبندی CPU را برای فرکانس کنونی
مقیاسبندی نمیکند. اگر بار در «واحد پردازش مرکزی» کوچک بهاندازه کافی زیاد باشد، هسته ممکن است رشتهها را به «واحد پردازش مرکزی» بزرگ منتقل کند.
مطمئن شوید که «واحد پردازش مرکزی» بزرگ حداقل به اندازه «واحد پردازش مرکزی» کوچک برای فرکانسی که بارکننده آنها را در آن حالت قرار میدهد عملکرد داشته باشد. برای مثال، اگر CPU بزرگ در همان بسامد ۲ برابر CPU کوچک عملکرد داشته باشد، اما بارکننده بسامد CPU کوچک را روی ۱٫۵ گیگاهرتز و بسامد CPU بزرگ را روی ۳۰۰ مگاهرتز تنظیم کند، دراینصورت اگر هسته رشتهای را به CPU بزرگ منتقل کند، عملکرد بار کردن کاهش مییابد. در این مثال، اگر راهاندازی CPU بزرگ در ۷۵۰ مگاهرتز ایمن است، باید این کار را انجام دهید حتی اگر قصد ندارید بهطور صریح از آن استفاده کنید.
درایورها نباید سفتافزار را در مرحله اول راهاندازی بار کنند
ممکن است مواردی اجتنابناپذیر وجود داشته باشد که در آنها باید میانافزار در مرحله اول راهاندازی بار شود. اما بهطورکلی، درایورها نباید هیچگونه میانافزاری را در مرحله اول init بار کنند، بهویژه در زمینه کاوش دستگاه. بار کردن سفتافزار در مرحله اول مقداردهی اولیه باعث میشود اگر سفتافزار در مرحله اول ramdisk دردسترس نباشد، کل فرایند راهاندازی متوقف شود. و حتی اگر سفتافزار در ramdisk مرحله اول وجود داشته باشد، بازهم باعث تأخیر غیرضروری میشود.