تحسين أوقات التمهيد

يوفر هذا المستند إرشادات الشركاء لتحسين أوقات التشغيل لأجهزة Android محددة. يعد وقت التمهيد مكونًا مهمًا لأداء النظام حيث يجب على المستخدمين الانتظار حتى يكتمل التمهيد قبل أن يتمكنوا من استخدام الجهاز. بالنسبة للأجهزة مثل السيارات التي يحدث فيها التمهيد البارد بشكل متكرر، يعد الحصول على وقت تشغيل سريع أمرًا بالغ الأهمية (لا أحد يحب الانتظار لعشرات الثواني فقط لإدخال وجهة التنقل).

يسمح Android 8.0 بتقليل أوقات التشغيل من خلال دعم العديد من التحسينات عبر مجموعة من المكونات. يلخص الجدول التالي تحسينات الأداء هذه (كما تم قياسها على أجهزة Google Pixel وPixel XL).

عنصر تحسين
محمل الإقلاع
  • تم حفظ 1.6 ثانية عن طريق إزالة سجل UART
  • تم حفظ 0.4 ثانية عن طريق التغيير إلى LZ4 من GZIP
نواة الجهاز
  • تم توفير 0.3 ثانية عن طريق إزالة تكوينات kernel غير المستخدمة وتقليل حجم برنامج التشغيل
  • تم حفظ 0.3 ثانية مع تحسين الجلب المسبق لـ dm-verity
  • تم توفير 0.15 ثانية لإزالة الانتظار/الاختبار غير الضروري في برنامج التشغيل
  • تم حفظ 0.12 ثانية لإزالة CONFIG_CC_OPTIMIZE_FOR_SIZE
ضبط الإدخال/الإخراج
  • تم حفظ 2S على التمهيد العادي
  • تم حفظ 25 ثانية عند التمهيد الأول
الحرف الأول.*.rc
  • تم حفظ 1.5 ثانية عن طريق موازنة أوامر init
  • تم توفير 0.25 ثانية عن طريق بدء اللاقحة مبكرًا
  • تم حفظ 0.22 ثانية بواسطة نغمة cpuset
تمهيد الرسوم المتحركة
  • بدأ التشغيل مبكرًا لمدة ثانيتين عند التمهيد دون تشغيل fsck، وكان أكبر بكثير عند التمهيد مع التمهيد الذي تم تشغيله بواسطة fsck
  • تم حفظ 5 ثوانٍ على Pixel XL مع الإيقاف الفوري للرسوم المتحركة للتمهيد
سياسة سيلينوكس تم حفظ 0.2 ثانية بواسطة genfscon

تحسين محمل الإقلاع

لتحسين أداة تحميل التشغيل لتحسين أوقات التمهيد:

  • للتسجيل:
    • قم بتعطيل كتابة السجل إلى UART حيث قد يستغرق الأمر وقتًا طويلاً مع وجود الكثير من عمليات التسجيل. (على أجهزة Google Pixel، وجدنا أنه يبطئ أداة تحميل التشغيل لمدة 1.5 ثانية).
    • قم بتسجيل حالات الخطأ فقط وفكر في تخزين المعلومات الأخرى في الذاكرة باستخدام آلية منفصلة لاستردادها.
  • لإلغاء ضغط kernel، فكر في استخدام LZ4 للأجهزة المعاصرة بدلاً من GZIP (مثال التصحيح ). ضع في اعتبارك أن خيارات ضغط kernel المختلفة يمكن أن يكون لها أوقات تحميل وإلغاء ضغط مختلفة، وقد تعمل بعض الخيارات بشكل أفضل من غيرها لجهازك المحدد.
  • تحقق من أوقات الانتظار غير الضرورية للدخول في الوضع الخاص/الارتداد وقم بتقليلها.
  • قم بتمرير وقت التمهيد الذي يقضيه في أداة تحميل التشغيل إلى kernel كـ cmdline.
  • تحقق من ساعة وحدة المعالجة المركزية وفكر في التوازي (يتطلب دعمًا متعدد النواة) لتحميل kernel وتهيئة الإدخال/الإخراج.

تحسين كفاءة الإدخال/الإخراج

يعد تحسين كفاءة الإدخال/الإخراج أمرًا بالغ الأهمية لتسريع وقت التمهيد، ويجب تأجيل قراءة أي شيء غير ضروري إلى ما بعد التمهيد (على Google Pixel، تتم قراءة حوالي 1.2 جيجابايت من البيانات عند التمهيد).

ضبط نظام الملفات

تبدأ قراءة نواة Linux للأمام عند قراءة ملف من البداية أو عند قراءة الكتل بشكل تسلسلي، مما يجعل من الضروري ضبط معلمات جدولة الإدخال/الإخراج خصيصًا للتمهيد (الذي يتميز بتوصيف عبء عمل مختلف عن التطبيقات العادية).

تستفيد الأجهزة التي تدعم التحديثات السلسة (A/B) بشكل كبير من ضبط نظام الملفات عند التشغيل لأول مرة (على سبيل المثال، 20 ثانية على Google Pixel). على سبيل المثال، قمنا بضبط المعلمات التالية لجهاز Google Pixel:

on late-fs
  # boot time fs tune
    # boot time fs tune
    write /sys/block/sda/queue/iostats 0
    write /sys/block/sda/queue/scheduler cfq
    write /sys/block/sda/queue/iosched/slice_idle 0
    write /sys/block/sda/queue/read_ahead_kb 2048
    write /sys/block/sda/queue/nr_requests 256
    write /sys/block/dm-0/queue/read_ahead_kb 2048
    write /sys/block/dm-1/queue/read_ahead_kb 2048

on property:sys.boot_completed=1
    # end boot time fs tune
    write /sys/block/sda/queue/read_ahead_kb 512
    ...

متنوع

  • قم بتشغيل حجم الجلب المسبق لتجزئة dm-verity باستخدام تكوين kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (الحجم الافتراضي هو 128).
  • للحصول على استقرار أفضل لنظام الملفات والتحقق القسري الذي يحدث عند كل تشغيل، استخدم أداة إنشاء ext4 الجديدة عن طريق تعيين TARGET_USES_MKE2FS في BoardConfig.mk.

تحليل الإدخال/الإخراج

لفهم أنشطة الإدخال/الإخراج أثناء التمهيد، استخدم بيانات kernel ftrace (المستخدمة أيضًا بواسطة systrace):

trace_event=block,ext4 in BOARD_KERNEL_CMDLINE

لتقسيم الوصول إلى الملفات لكل ملف، قم بإجراء التغييرات التالية على النواة (نواة التطوير فقط؛ لا تستخدم في نواة الإنتاج):

diff --git a/fs/open.c b/fs/open.c
index 1651f35..a808093 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -981,6 +981,25 @@
 }
 EXPORT_SYMBOL(file_open_root);
 
+static void _trace_do_sys_open(struct file *filp, int flags, int mode, long fd)
+{
+       char *buf;
+       char *fname;
+
+       buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return;
+       fname = d_path(&filp-<f_path, buf, PAGE_SIZE);
+
+       if (IS_ERR(fname))
+               goto out;
+
+       trace_printk("%s: open(\"%s\", %d, %d) fd = %ld, inode = %ld\n",
+                     current-<comm, fname, flags, mode, fd, filp-<f_inode-<i_ino);
+out:
+       kfree(buf);
+}
+
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 {
 	struct open_flags op;
@@ -1003,6 +1022,7 @@
 		} else {
 			fsnotify_open(f);
 			fd_install(fd, f);
+			_trace_do_sys_open(f, flags, mode, fd);

استخدم البرامج النصية التالية للمساعدة في تحليل أداء التمهيد.

  • system/extras/boottime_tools/bootanalyze/bootanalyze.py يقيس وقت التمهيد مع تفصيل الخطوات المهمة في عملية التمهيد.
  • system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace يوفر معلومات الوصول لكل ملف.
  • system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace يعطي تفصيلاً على مستوى النظام.

تحسين الحرف الأول.*.rc

Init هو الجسر من النواة حتى يتم إنشاء إطار العمل، وعادةً ما تقضي الأجهزة بضع ثوانٍ في مراحل init مختلفة.

تشغيل المهام بالتوازي

على الرغم من أن عملية init الحالية لنظام Android عبارة عن عملية مترابطة واحدة تقريبًا، إلا أنه لا يزال بإمكانك تنفيذ بعض المهام بالتوازي.

  • قم بتنفيذ الأوامر البطيئة في خدمة البرنامج النصي Shell وانضم إليها لاحقًا عن طريق انتظار خاصية معينة. يدعم Android 8.0 حالة الاستخدام هذه باستخدام أمر wait_for_property الجديد.
  • تحديد العمليات البطيئة في init. يقوم النظام بتسجيل أمر init exec/wait_for_prop أو أي إجراء يستغرق وقتًا طويلاً (في Android 8.0، يستغرق أي أمر أكثر من 50 مللي ثانية). على سبيل المثال:
    init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms

    قد تشير مراجعة هذا السجل إلى فرص التحسينات.

  • ابدأ الخدمات وقم بتمكين الأجهزة الطرفية في المسار الحرج مبكرًا. على سبيل المثال، تتطلب بعض مراكز عمليات الأمان (SOCs) بدء تشغيل الخدمات المتعلقة بالأمان قبل بدء تشغيل SurfaceFlinger. قم بمراجعة سجل النظام عندما يقوم ServiceManager بإرجاع "انتظار الخدمة" - وعادةً ما تكون هذه علامة على أنه يجب بدء تشغيل خدمة تابعة أولاً.
  • قم بإزالة أية خدمات وأوامر غير مستخدمة في init.*.rc. أي شيء لم يتم استخدامه في المرحلة المبكرة من init يجب تأجيله حتى اكتمال التمهيد.

ملاحظة: تعد خدمة الخاصية جزءًا من عملية init، لذا فإن استدعاء setproperty أثناء التمهيد يمكن أن يؤدي إلى تأخير طويل إذا كان init مشغولاً بالأوامر المضمنة.

باستخدام ضبط الجدولة

استخدم ضبط المجدول للتمهيد المبكر. مثال من Google Pixel:

on init
    # boottime stune
    write /dev/stune/schedtune.prefer_idle 1
    write /dev/stune/schedtune.boost 100
    on property:sys.boot_completed=1
    # reset stune
    write /dev/stune/schedtune.prefer_idle 0
    write /dev/stune/schedtune.boost 0

    # or just disable EAS during boot
    on init
    write /sys/kernel/debug/sched_features NO_ENERGY_AWARE
    on property:sys.boot_completed=1
    write /sys/kernel/debug/sched_features ENERGY_AWARE

قد تحتاج بعض الخدمات إلى تعزيز الأولوية أثناء التمهيد. مثال:

init.zygote64.rc:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
...

بدء الزيجوت في وقت مبكر

يمكن للأجهزة التي تحتوي على تشفير قائم على الملفات بدء تشغيل zygote مبكرًا عند مشغل بدء zygote (افتراضيًا، يتم تشغيل zygote في الفئة الرئيسية، والتي تكون متأخرة كثيرًا عن بدء zygote). عند القيام بذلك، تأكد من السماح بتشغيل الزيجوت في جميع وحدات المعالجة المركزية (حيث أن إعداد وحدة المعالجة المركزية الخاطئة قد يجبر الزيجوت على التشغيل في وحدات المعالجة المركزية المحددة).

تعطيل توفير الطاقة

أثناء تشغيل الجهاز، يمكن تعطيل إعداد توفير الطاقة لمكونات مثل UFS و/أو حاكم وحدة المعالجة المركزية.

تحذير: يجب تمكين توفير الطاقة في وضع الشاحن لتحقيق الكفاءة.

on init
    # Disable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 0
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 0
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0
    write /sys/module/lpm_levels/parameters/sleep_disabled Y
on property:sys.boot_completed=1
    # Enable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
    write /sys/module/lpm_levels/parameters/sleep_disabled N
on charger
    # Enable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
    write /sys/class/typec/port0/port_type sink
    write /sys/module/lpm_levels/parameters/sleep_disabled N

تأجيل التهيئة غير الحرجة

يمكن تأجيل التهيئة غير الحرجة مثل ZRAM إلى boot_Complete.

on property:sys.boot_completed=1
   # Enable ZRAM on boot_complete
   swapon_all /vendor/etc/fstab.${ro.hardware}

تحسين الرسوم المتحركة للتمهيد

استخدم النصائح التالية لتحسين الرسوم المتحركة للتمهيد.

تكوين البداية المبكرة

يتيح Android 8.0 بدء الرسوم المتحركة للتمهيد مبكرًا، قبل تثبيت قسم بيانات المستخدم. ومع ذلك، حتى عند استخدام سلسلة أدوات ext4 الجديدة في Android 8.0، لا يزال يتم تشغيل fsck بشكل دوري لأسباب تتعلق بالسلامة، مما يتسبب في تأخير بدء تشغيل خدمة التمهيد.

لبدء تشغيل الرسوم المتحركة للتمهيد مبكرًا، قم بتقسيم قاعدة تثبيت fstab إلى مرحلتين:

  • في المرحلة المبكرة، قم بتثبيت الأقسام فقط (مثل system/ vendor/ ) التي لا تتطلب عمليات فحص التشغيل، ثم ابدأ تشغيل خدمات الرسوم المتحركة للتمهيد وتبعياتها (مثل مدير الخدمة وsurfaceflinger).
  • في المرحلة الثانية، قم بتثبيت الأقسام (مثل data/ ) التي تتطلب عمليات فحص التشغيل.

سيتم بدء تشغيل الرسوم المتحركة للتمهيد بشكل أسرع (وفي وقت ثابت) بغض النظر عن fsck.

تشطيب نظيف

بعد تلقي إشارة الخروج، تقوم الرسوم المتحركة للتمهيد بتشغيل الجزء الأخير، والذي يمكن أن يؤدي طوله إلى إبطاء وقت التمهيد. لا يحتاج النظام الذي يتم تشغيله بسرعة إلى رسوم متحركة طويلة يمكن أن تخفي بشكل فعال أي تحسينات تم إجراؤها. نوصي بجعل كل من حلقة التكرار والنهاية قصيرة.

تحسين SELinux

استخدم النصائح التالية لتحسين SELinux لتحسين أوقات التشغيل.

  • استخدم التعبيرات العادية النظيفة (regex) . يمكن أن يؤدي التعبير العادي الذي تم صياغته بشكل سيء إلى الكثير من الحمل عند مطابقة سياسة SELinux لـ sys/devices في file_contexts . على سبيل المثال، التعبير العادي /sys/devices/.*abc.*(/.*)? يفرض عن طريق الخطأ فحصًا لجميع الدلائل الفرعية /sys/devices التي تحتوي على "abc"، مما يتيح التطابقات لكل من /sys/devices/abc و /sys/devices/xyz/abc . هل تريد تحسين هذا التعبير العادي إلى /sys/devices/[^/]*abc[^/]*(/.*)? سيتم تمكين المطابقة فقط لـ /sys/devices/abc .
  • انقل التسميات إلى genfscon . تقوم ميزة SELinux الموجودة هذه بتمرير بادئات مطابقة الملفات إلى النواة في ثنائي SELinux، حيث تقوم النواة بتطبيقها على أنظمة الملفات المولدة بواسطة kernel. يساعد هذا أيضًا في إصلاح الملفات التي تم إنشاؤها بواسطة kernel والتي تم تسميتها بشكل خاطئ، مما يمنع حالات السباق التي يمكن أن تحدث بين عمليات مساحة المستخدم التي تحاول الوصول إلى هذه الملفات قبل حدوث إعادة التسمية.

الأداة والأساليب

استخدم الأدوات التالية لمساعدتك في جمع البيانات لأهداف التحسين.

مخطط التمهيد

يوفر Bootchart تحليلًا لأحمال وحدة المعالجة المركزية والإدخال/الإخراج لجميع العمليات للنظام بأكمله. لا يتطلب الأمر إعادة بناء صورة النظام ويمكن استخدامه كفحص سريع للسلامة قبل الغوص في systrace.

لتمكين مخطط التمهيد:

adb shell 'touch /data/bootchart/enabled'
adb reboot

بعد التمهيد، قم بإحضار مخطط التمهيد:

$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh

عند الانتهاء، احذف /data/bootchart/enabled لمنع جمع البيانات في كل مرة.

إذا لم يعمل bootchart وظهرت لك رسالة خطأ تفيد بأن bootchart.png غير موجود، فقم بما يلي:
  1. قم بتشغيل الأوامر التالية:
          sudo apt install python-is-python3
          cd ~/Documents
          git clone https://github.com/xrmx/bootchart.git
          cd bootchart/pybootchartgui
          mv main.py.in main.py
        
  2. قم بتحديث $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh للإشارة إلى النسخة المحلية من pybootchartgui (الموجود في ~/Documents/bootchart/pybootchartgui.py )

سيستراس

يسمح Systrace بجمع آثار كل من kernel وAndroid أثناء التمهيد. يمكن أن يساعد تصور systrace في تحليل مشكلة معينة أثناء عملية التمهيد. (ومع ذلك، للتحقق من الرقم المتوسط ​​أو العدد المتراكم أثناء التمهيد بأكمله، فمن الأسهل النظر في تتبع النواة مباشرة).

لتمكين systrace أثناء التمهيد:

  • في frameworks/native/cmds/atrace/atrace.rc ، قم بتغيير:
      write /sys/kernel/debug/tracing/tracing_on 0
      write /sys/kernel/tracing/tracing_on 0

    ل:

      #    write /sys/kernel/debug/tracing/tracing_on 0
      #    write /sys/kernel/tracing/tracing_on 0
  • يؤدي هذا إلى تمكين التتبع (الذي يتم تعطيله افتراضيًا).

  • في ملف device.mk ، أضف السطر التالي:
    PRODUCT_PROPERTY_OVERRIDES +=    debug.atrace.tags.enableflags=802922
    PRODUCT_PROPERTY_OVERRIDES +=    persist.traced.enable=0
  • في ملف BoardConfig.mk الخاص بالجهاز، أضف ما يلي:
    BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
  • للحصول على تحليل تفصيلي للإدخال/الإخراج، أضف أيضًا block وext4 وf2fs.

  • في ملف init.rc الخاص بالجهاز، أضف ما يلي:
    on property:sys.boot_completed=1          // This stops tracing on boot complete
    write /d/tracing/tracing_on 0
    write /d/tracing/events/ext4/enable 0
    write /d/tracing/events/f2fs/enable 0
    write /d/tracing/events/block/enable 0
    
  • بعد التمهيد، جلب التتبع:

    adb root && adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace
    adb pull /data/local/tmp/boot_trace
    $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=boot_trace