تحسين DTOs

تناقش هذه الصفحة التحسينات التي يمكنك إجراؤها على تنفيذ DTO، وتصف القيود المفروضة على تراكب العقدة الجذرية، وتفاصيل كيفية تكوين التراكبات المضغوطة في صورة DTBO. كما يوفر أيضًا نموذجًا لتعليمات التنفيذ والتعليمات البرمجية.

سطر أوامر النواة

يوجد سطر أوامر kernel الأصلي في شجرة الأجهزة في العقدة chosen/bootargs . يجب أن يقوم محمل الإقلاع بربط هذا الموقع مع مصادر أخرى لسطر أوامر kernel:

/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};

لا يمكن لـ DTO ربط القيم من DT الرئيسي وتراكب DT، لذلك يجب عليك وضع سطر أوامر kernel لـ DT الرئيسي في chosen/bootargs وسطر أوامر kernel لتراكب DT في chosen/bootargs_ext . يمكن لبرنامج Bootloader بعد ذلك ربط هذه المواقع وتمرير النتيجة إلى kernel.

main.dts تراكب.dts
/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};
/dts-v1/;
/plugin/;

&chosen {
  bootargs_ext = "...";
};

libufdt

في حين أن أحدث libfdt يدعم DTO، فمن المستحسن استخدام libufdt لتنفيذ DTO (مصدر AOSP على platform/system/libufdt ). يبني libufdt بنية شجرة حقيقية (شجرة الأجهزة غير المسطحة، أو ufdt ) من شجرة الأجهزة المسطحة (FDT)، بحيث يمكنه تحسين دمج ملفين .dtb من O(N 2 ) إلى O(N)، حيث N هو عدد العقد في الشجرة.

اختبار أداء

في اختبار Google الداخلي، أدى استخدام libufdt على 2405 .dtb و283 .dtbo DT إلى الحصول على أحجام ملفات تبلغ 70,618 و8,566 بايت بعد التجميع. بالمقارنة مع تنفيذ DTO المنقول من FreeBSD (وقت تشغيل 124 مللي ثانية)، فإن وقت تشغيل libufdt DTO هو 10 مللي ثانية.

اختبار الأداء لأجهزة Pixel مقارنة libufdt و libfdt . عدد تأثير العقد الأساسية مشابه، ولكنه يتضمن الاختلافات التالية:

  • 500 عملية تراكب (إلحاق أو تجاوز) لها فارق زمني يتراوح بين 6x إلى 8x
  • 1000 عملية تراكب (إلحاق أو تجاوز) لها فارق زمني يتراوح بين 8x و10x

مثال مع تعيين عدد الإلحاق على X:

الشكل 1. عدد الإلحاق هو X

مثال مع تعيين عدد التجاوز على X:

الشكل 2. العدد الغالب هو X

تم تطوير libufdt باستخدام بعض واجهات برمجة تطبيقات libfdt وهياكل البيانات. عند استخدام libufdt ، يجب عليك تضمين libfdt وربطه (ومع ذلك، في التعليمات البرمجية الخاصة بك، يمكنك استخدام libfdt API لتشغيل DTB أو DTBO).

واجهة برمجة تطبيقات libufdt DTO

واجهة برمجة التطبيقات الرئيسية لـ DTO في libufdt هي كما يلي:

struct fdt_header *ufdt_apply_overlay(
        struct fdt_header *main_fdt_header,
        size_t main_fdt_size,
        void *overlay_fdt,
        size_t overlay_size);

المعلمة main_fdt_header هي DT الرئيسية و overlay_fdt هو المخزن المؤقت الذي يحتوي على محتويات ملف .dtbo . القيمة المرجعة هي مخزن مؤقت جديد يحتوي على DT المدمج (أو null في حالة حدوث خطأ). يتم تنسيق DT المدمج بتنسيق FDT، والذي يمكنك تمريره إلى النواة عند بدء تشغيل النواة.

يتم إنشاء المخزن المؤقت الجديد من القيمة المرجعة بواسطة dto_malloc() ، والذي يجب عليك تنفيذه عند نقل libufdt إلى أداة تحميل التشغيل. للتعرف على التطبيقات المرجعية، راجع sysdeps/libufdt_sysdeps_*.c .

قيود العقدة الجذرية

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

يجب على بائعي SoC تحديد قدرة التراكب لـ DT الرئيسي؛ يمكن لـ ODM/OEMs فقط إلحاق أو تجاوز العقد ذات التصنيفات المحددة بواسطة بائع SoC. كحل بديل، يمكنك تحديد عقدة odm ضمن العقدة الجذرية في DT الأساسية، مما يتيح لجميع عقد ODM في DT المتراكبة إضافة عقد جديدة. وبدلاً من ذلك، يمكنك وضع جميع العقد المتعلقة بـ SoC في DT الأساسي في عقدة soc ضمن العقدة الجذرية كما هو موضح أدناه:

main.dts تراكب.dts
/dts-v1/;

/ {
    compatible = "corp,bar";
    ...

    chosen: chosen {
        bootargs = "...";
    };

    /* nodes for all soc nodes */
    soc {
        ...
        soc_device@0: soc_device@0 {
            compatible = "corp,bar";
            ...
        };
        ...
    };

    odm: odm {
        /* reserved for overlay by odm */
    };
};
/dts-v1/;
/plugin/;

/ {
};

&chosen {
    bootargs_ex = "...";
};

&odm {
    odm_device@0 {
        ...
    };
    ...
};

باستخدام تراكبات مضغوطة

يضيف Android 9 دعمًا لاستخدام التراكبات المضغوطة في صورة DTBO عند استخدام الإصدار 1 من رأس جدول شجرة الجهاز. عند استعمال رأسية DTBO الإصدار 1، تشير البتات الأربع الأقل أهمية لحقل الأعلام في dt_table_entry إلى نسق الضغط لإدخال DT.

struct dt_table_entry_v1 {
  uint32_t dt_size;
  uint32_t dt_offset;  /* offset from head of dt_table_header */
  uint32_t id;         /* optional, must be zero if unused */
  uint32_t rev;        /* optional, must be zero if unused */
  uint32_t flags;      /* For version 1 of dt_table_header, the 4 least significant bits
                        of 'flags' will be used to indicate the compression
                        format of the DT entry as per the enum 'dt_compression_info' */
  uint32_t custom[3];  /* optional, must be zero if unused */
};

حاليًا، يتم دعم ضغطات zlib و gzip .

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

يضيف Android 9 دعمًا لاختبار التراكبات المضغوطة إلى اختبار VtsFirmwareDtboVerification لمساعدتك في التحقق من صحة تطبيق التراكب.

نموذج لتنفيذ DTO

ترشدك الإرشادات التالية خلال نموذج تنفيذ DTO باستخدام libufdt (نموذج التعليمات البرمجية أدناه).

نموذج لتعليمات DTO

  1. تشمل المكتبات. لاستخدام libufdt ، قم بتضمين libfdt لهياكل البيانات وواجهات برمجة التطبيقات:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
    
  2. تحميل DT الرئيسي وتراكب DT. قم بتحميل .dtb و .dtbo من وحدة التخزين إلى الذاكرة (تعتمد الخطوات الدقيقة على تصميمك). عند هذه النقطة، يجب أن يكون لديك المخزن المؤقت وحجم .dtb / .dtbo :
    main_size = my_load_main_dtb(main_buf, main_buf_size)
    
    overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
    
  3. تراكب DTs:
    1. استخدم ufdt_install_blob() للحصول على رأس FDT لـ DT الرئيسي:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
      
    2. اتصل بـ ufdt_apply_overlay() إلى DTO للحصول على DT مدمج بتنسيق FDT:
      merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                      overlay_buf, overlay_size);
      
    3. استخدم merged_fdt للحصول على حجم dtc_totalsize() :
      merged_fdt_size = dtc_totalsize(merged_fdt);
      
    4. قم بتمرير DT المدمج لبدء النواة:
      my_kernel_entry(0, machine_type, merged_fdt);
      

نموذج لرمز DTO

#include <libfdt.h>
#include <ufdt_overlay.h>

…

{
  struct fdt_header *main_fdt_header;
  struct fdt_header *merged_fdt;

  /* load main dtb into memory and get the size */
  main_size = my_load_main_dtb(main_buf, main_buf_size);

  /* load overlay dtb into memory and get the size */
  overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);

  /* overlay */
  main_fdt_header = ufdt_install_blob(main_buf, main_size);
  main_fdt_size = main_size;
  merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                  overlay_buf, overlay_size);
  merged_fdt_size = dtc_totalsize(merged_fdt);

  /* pass to kernel */
  my_kernel_entry(0, machine_type, merged_fdt);
}