تحسين أوقات التشغيل

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

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

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

برنامج إقلاع تحسين الأداء

لتحسين برنامج الإقلاع من أجل تحسين أوقات التشغيل، اتّبِع الخطوات التالية:

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

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

تُعد تحسين كفاءة الإدخال والإخراج أمرًا بالغ الأهمية لتسريع وقت التمهيد والقراءة إلى تأجيل أي شيء غير ضروري إلى ما بعد التشغيل (على هاتف 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 باستخدام إعدادات النواة DM_VERITY_HASH_PREFETCH_MIN_size (الحجم التلقائي هو 128).
  • لتحسين استقرار نظام الملفات وإلغاء التحقق المفروض على في كل عملية تشغيل، يمكنك استخدام أداة الإنشاء ext4 الجديدة من خلال ضبط TARGET_USES_MKE2FS في BoardConfig.mk.

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

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

trace_event=block,ext4 in BOARD_KERNEL_CMDLINE

لتقسيم الوصول إلى الملف لكل ملف، أجرِ التغييرات التالية على النواة (kernel) (نواة التطوير فقط، لا تستخدمها في نواة الإنتاج):

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 لتوفير تفاصيل على مستوى النظام

تحسين init.*.rc

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

تنفيذ المهام بالتوازي

على الرغم من أن إعداد Android الحالي عبارة عن عملية سلسلة واحدة إلى حد ما، يمكنك لا يزال بإمكانك أداء بعض المهام بالتوازي.

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

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

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

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

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

استخدِم ضبط أداة الجدولة من أجل التشغيل المبكر. مثال من هاتف 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-start). عند القيام بذلك، تأكد من السماح بتشغيل zygote في جميع وحدات المعالجة المركزية (CPU) قد يؤدي إعداد تكلفة المشاهدة الخاطئ إلى فرض تشغيل الزيجوت في وحدات معالجة مركزية (CPU) محددة).

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

ضبط خيار توفير الطاقة لمكوّنات مثل 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، يجب أولاً لا تزال تظهر بشكل دوري لأسباب تتعلق بالسلامة، مما يؤدي إلى تأخير في وبدء خدمة التمهيد.

لبدء التشغيل مبكرًا، قسِّم حامل fstab إلى مرحلتين:

  • في المرحلة المبكرة، يجب تثبيت الأقسام فقط (مثل system/ وvendor/) التي لا تتطلب تنفيذًا المستخدم، ثم بدء خدمات تشغيل الرسوم المتحركة وتبعياتها (مثل servicemanager وSurfaceflinger).
  • وفي المرحلة الثانية، عليك تحميل أقسام (مثل data/) التي لا تتطلب إجراء عمليات تحقق.

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

إنهاء التنظيف

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

تحسين SELinux

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

  • استخدام تعبيرات عادية واضحة تعبير عادي غير صحيح يمكن أن يؤدي إلى الكثير من النفقات العامة عند مطابقة سياسة 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 لأنظمة الملفات. ويساعد ذلك أيضًا في إصلاح الملفات التي تم إنشاؤها بالنواة ذات التسمية الخاطئة، مما يمنع حالات السباق التي يمكن أن تحدث بين عمليات مساحة المستخدم التي تحاول الوصول هذه الملفات قبل حدوث إعادة تصنيفها.

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

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

رسم بياني أوّلي

يوفر مخطط Bootchart تفاصيل حمولة وحدة المعالجة المركزية (CPU) وإدخال/إخراج (I/O) لجميع العمليات بأكملها . ولا يتطلب هذا النظام إعادة إنشاء صورة النظام ويمكن استخدامها كطريقة سريعة والتحقق من السلامة قبل الانتقال إلى النظام.

لتمكين المخطط الأولي:

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

بعد بدء التشغيل، يمكنك استرجاع الرسم البياني للتشغيل:

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

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

إذا لم يعمل الرسم البياني للتشغيل وظهرت لك رسالة خطأ تفيد بأنّ 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 أثناء بدء التشغيل. يمكن أن يساعد مؤثرات عرض النظام في تحليل مشكلة محددة أثناء التشغيل. (ومع ذلك، للتحقق من متوسط العدد أو الرقم المتراكم أثناء للتشغيل بالكامل، يصبح من الأسهل النظر إلى آثار النواة بشكل مباشر).

لتفعيل تتبُّع النظام أثناء عملية التشغيل:

  • في 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