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

توفر هذه الصفحة مجموعة من النصائح، التي يمكنك الاختيار من بينها، لتحسين وقت التمهيد.

تجريد رموز التصحيح من الوحدات النمطية

على غرار كيفية تجريد رموز التصحيح من النواة على جهاز الإنتاج، تأكد من إزالة رموز التصحيح من الوحدات النمطية أيضًا. يساعد تجريد رموز التصحيح من الوحدات النمطية على وقت التمهيد عن طريق تقليل ما يلي:

  • الوقت المستغرق لقراءة الثنائيات من الفلاش.
  • الوقت المستغرق لفك ضغط القرص ramdisk.
  • الوقت المستغرق لتحميل الوحدات.

قد يؤدي تجريد رمز التصحيح من الوحدات النمطية إلى توفير عدة ثوانٍ أثناء التمهيد.

يتم تمكين تجريد الرموز افتراضيًا في إصدار نظام Android الأساسي، ولكن لتمكينها بشكل صريح، قم بتعيين BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES في التكوين الخاص بجهازك ضمن الجهاز/ vendor / device .

استخدم ضغط LZ4 للنواة وقرص الذاكرة

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

تمت إضافة دعم ضغط قرص الذاكرة LZ4 إلى نظام Android الأساسي من خلال BOARD_RAMDISK_USE_LZ4 . يمكنك ضبط هذا الخيار في التكوين الخاص بجهازك. يمكن ضبط ضغط Kernel من خلال kernel defconfig.

من المفترض أن يؤدي التبديل إلى LZ4 إلى توفير وقت تشغيل أسرع يتراوح بين 500 مللي ثانية إلى 1000 مللي ثانية.

تجنب الإفراط في تسجيل الدخول إلى برامج التشغيل الخاصة بك

في ARM64 وARM32، تحتاج استدعاءات الوظائف التي تكون على بعد أكثر من مسافة محددة من موقع الاتصال إلى جدول انتقال (يسمى جدول ربط الإجراء، أو PLT) لتتمكن من تشفير عنوان الانتقال الكامل. نظرًا لأنه يتم تحميل الوحدات ديناميكيًا، يجب إصلاح جداول الانتقال هذه أثناء تحميل الوحدة. تُسمى الاستدعاءات التي تحتاج إلى إعادة تحديد موقع بإدخالات إعادة تحديد الموقع ذات الإضافات الصريحة (أو RELA، للاختصار) إدخالات بتنسيق ELF.

تقوم نواة Linux ببعض عمليات تحسين حجم الذاكرة (مثل تحسين ذاكرة التخزين المؤقت) عند تخصيص PLT. مع هذا الالتزام المنبع ، فإن نظام التحسين له تعقيد O(N^2)، حيث N هو عدد RELAs من النوع R_AARCH64_JUMP26 أو R_AARCH64_CALL26 . لذا فإن وجود عدد أقل من RELAs من هذه الأنواع يعد مفيدًا في تقليل وقت تحميل الوحدة.

أحد أنماط الترميز الشائعة التي تزيد من عدد R_AARCH64_CALL26 أو R_AARCH64_JUMP26 RELAs هو تسجيل الدخول المفرط في برنامج التشغيل. عادةً ما تضيف كل مكالمة إلى printk() أو أي نظام تسجيل آخر إدخال CALL26 / JUMP26 RELA. في نص الالتزام في الالتزام المنبع ، لاحظ أنه حتى مع التحسين، يستغرق تحميل الوحدات الست حوالي 250 مللي ثانية - وذلك لأن تلك الوحدات الست كانت أعلى ست وحدات مع أكبر قدر من التسجيل.

يمكن أن يؤدي تقليل التسجيل إلى توفير حوالي 100 - 300 مللي ثانية في أوقات التمهيد اعتمادًا على مدى الإفراط في التسجيل الحالي.

تمكين التحقيق غير المتزامن، بشكل انتقائي

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

لتجنب أوقات التمهيد البطيئة، قم بتمكين الفحص غير المتزامن للوحدات النمطية التي تستغرق بعض الوقت لفحص أجهزتها. قد لا يكون تمكين الفحص غير المتزامن لجميع الوحدات مفيدًا لأن الوقت المستغرق لفصل الخيط وبدء تشغيل المسبار قد يكون بنفس الوقت المستغرق لفحص الجهاز.

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

لتمكين الفحص غير المتزامن لوحدة نمطية، لا يكفي فقط تعيين علامة PROBE_PREFER_ASYNCHRONOUS في رمز برنامج التشغيل. بالنسبة للوحدات، تحتاج أيضًا إلى إضافة module_name .async_probe=1 في سطر أوامر kernel أو تمرير async_probe=1 كمعلمة للوحدة عند تحميل الوحدة باستخدام modprobe أو insmod .

يمكن أن يؤدي تمكين الفحص غير المتزامن إلى توفير حوالي 100 - 500 مللي ثانية في أوقات التمهيد اعتمادًا على الأجهزة/برامج التشغيل لديك.

تحقق من برنامج تشغيل CPUfreq الخاص بك في أقرب وقت ممكن

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

مع الوحدات، يمكن أن يعتمد ترتيب التحميل على مستوى initcall وترتيب التجميع أو الارتباط لبرامج التشغيل. استخدم الاسم المستعار MODULE_SOFTDEP() للتأكد من أن برنامج التشغيل cpufreq من بين الوحدات القليلة الأولى التي سيتم تحميلها.

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

يمكن أن يكون التوفير الناتج عن فحص برنامج تشغيل CPUfreq مبكرًا صغيرًا جدًا إلى كبير جدًا اعتمادًا على مدى الوقت الذي يمكنك فيه إجراء هذه الاختبارات وبأي تردد يترك برنامج bootloader وحدات المعالجة المركزية (CPUs) فيها.

انقل الوحدات النمطية إلى قسم init أو بائع أو بائع_dlkm للمرحلة الثانية

نظرًا لأن المرحلة الأولى من عملية init يتم تسلسلها، فلا توجد فرص كثيرة لموازاة عملية التمهيد. إذا لم تكن هناك حاجة إلى وحدة نمطية حتى تنتهي المرحلة الأولى من init، فانقل الوحدة النمطية إلى المرحلة الثانية من init عن طريق وضعها في قسم المورد أو قسم vendor_dlkm .

لا تتطلب المرحلة الأولى من init اختبار عدة أجهزة للوصول إلى المرحلة الثانية من init. هناك حاجة فقط إلى وظيفة تخزين وحدة التحكم والفلاش لتدفق التمهيد العادي.

قم بتحميل برامج التشغيل الأساسية التالية:

  • الوكالة الدولية للطاقة
  • إعادة ضبط
  • com.cpufreq

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

بالنظر إلى قائمة الأجهزة الطرفية (على سبيل المثال، UFS أو المسلسل)، يبحث البرنامج النصي dev needs.sh عن جميع برامج التشغيل والأجهزة والوحدات النمطية اللازمة للتبعيات أو الموردين (على سبيل المثال، الساعات أو المنظمات أو gpio ) للتحقيق فيها.

يؤدي نقل الوحدات إلى المرحلة الثانية إلى تقليل أوقات التمهيد بالطرق التالية:

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

يمكن أن يؤدي نقل الوحدات إلى المرحلة الثانية إلى توفير ما بين 500 إلى 1000 مللي ثانية في أوقات التمهيد اعتمادًا على عدد الوحدات التي يمكنك نقلها إلى المرحلة الثانية من init.

وحدة تحميل الخدمات اللوجستية

يتميز أحدث إصدار من Android بتكوينات اللوحة التي تتحكم في الوحدات التي يتم نسخها إلى كل مرحلة، وأي الوحدات يتم تحميلها. يركز هذا القسم على المجموعة الفرعية التالية:

  • BOARD_VENDOR_RAMDISK_KERNEL_MODULES . قائمة الوحدات التي سيتم نسخها إلى قرص الذاكرة.
  • BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD . قائمة الوحدات التي سيتم تحميلها في المرحلة الأولى من init.
  • BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD . قائمة الوحدات التي سيتم تحميلها عند تحديد الاسترداد أو fastbootd من قرص ذاكرة الوصول العشوائي.
  • BOARD_VENDOR_KERNEL_MODULES . قائمة الوحدات النمطية التي سيتم نسخها إلى قسم البائع أو قسم vendor_dlkm في الدليل /vendor/lib/modules/ .
  • BOARD_VENDOR_KERNEL_MODULES_LOAD . قائمة الوحدات التي سيتم تحميلها في المرحلة الثانية init.

يجب أيضًا نسخ وحدات التمهيد والاسترداد الموجودة في 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 ليتم تحديدها محليًا في ملفات تكوين اللوحة. يبحث البرنامج النصي السابق عن كل وحدة من وحدات المجموعة الفرعية من وحدات kernel المتاحة المحددة ويملأها، تاركًا وحدات إعادة التوسيع للمرحلة الثانية من init.

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

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

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

بدلاً من ذلك، يمكنك استخدام أمر init's wait<file>[<timeout>] في البرمجة النصية لتدفق التمهيد rc لانتظار إدخالات sysfs المحددة لإظهار أن وحدات برنامج التشغيل قد أكملت عمليات الاختبار. مثال على ذلك هو انتظار اكتمال تحميل برنامج تشغيل العرض في خلفية الاسترداد أو fastbootd ، قبل تقديم رسومات القائمة.

قم بتهيئة تردد وحدة المعالجة المركزية إلى قيمة معقولة في أداة تحميل التشغيل

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

تهيئة تردد وحدة المعالجة المركزية لوحدات المعالجة المركزية الكبيرة في أداة تحميل التشغيل

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

تأكد من أن أداء وحدات المعالجة المركزية الكبيرة على الأقل يعادل أداء وحدات المعالجة المركزية الصغيرة بالنسبة للتردد الذي يتركها فيه برنامج تحميل التشغيل. على سبيل المثال، إذا كانت وحدة المعالجة المركزية الكبيرة تتمتع بأداء ضعف أداء وحدة المعالجة المركزية الصغيرة لنفس التردد، ولكن يقوم برنامج تحميل التشغيل بتعيين تردد وحدة المعالجة المركزية الصغيرة إلى 1.5 جيجا هرتز وتردد وحدة المعالجة المركزية الكبيرة إلى 300 ميجا هرتز، سينخفض ​​أداء التمهيد إذا قامت النواة بنقل خيط إلى وحدة المعالجة المركزية الكبيرة. في هذا المثال، إذا كان من الآمن تشغيل وحدة المعالجة المركزية الكبيرة بسرعة 750 ميجاهرتز، فيجب عليك القيام بذلك حتى إذا كنت لا تخطط لاستخدامها بشكل صريح.

يجب على برامج التشغيل عدم تحميل البرامج الثابتة في المرحلة الأولى

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