डीटीओ ऑप्टिमाइज़ करें

इस पेज पर, डिवाइस ट्री ओवरले (डीटीओ) को लागू करने के लिए किए जा सकने वाले ऑप्टिमाइज़ेशन के बारे में बताया गया है. साथ ही, रूट नोड को ओवरले करने से जुड़ी पाबंदियों के बारे में बताया गया है. इसके अलावा, डीटीबीओ इमेज में कंप्रेस किए गए ओवरले को कॉन्फ़िगर करने का तरीका भी बताया गया है. इसमें, लागू करने के निर्देश और कोड का सैंपल भी दिया जाता है.

Kernel कमांड लाइन

डिवाइस ट्री (DT) में ओरिजनल कर्नेल कमांड लाइन, chosen/bootargs नोड में मौजूद होती है. बूटलोडर को इस जगह को, कर्नेल कमांड लाइन के अन्य सोर्स के साथ जोड़ना होगा:

/dts-v1/;

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

डीटीओ, मुख्य डीटी और ओवरले डीटी की वैल्यू को जोड़ नहीं सकता. इसलिए, आपको मुख्य डीटी की कर्नेल कमांड लाइन को chosen/bootargs में और ओवरले डीटी की कर्नेल कमांड लाइन को chosen/bootargs_ext में डालना होगा. इसके बाद, बूटलोडर इन जगहों को जोड़ सकता है और नतीजे को कर्नेल को पास कर सकता है.

main.dts overlay.dts
/dts-v1/;

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

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

libufdt

libfdt के नए वर्शन में डीटीओ की सुविधा काम करती है. हालांकि, हमारा सुझाव है कि डीटीओ को लागू करने के लिए libufdt का इस्तेमाल करें. libufdt, फ़्लैट किए गए डिवाइस ट्री (FDT) से रीयल ट्री स्ट्रक्चर (नॉन-फ़्लैट किए गए डिवाइस ट्री या ufdt) बनाता है. इससे दो .dtb फ़ाइलों को मर्ज करने की प्रोसेस को बेहतर बनाया जा सकता है. यह प्रोसेस, O(N2) से O(N) तक की जा सकती है. यहां N, ट्री में मौजूद नोड की संख्या है.platform/system/libufdt

परफ़ॉर्मेंस की जांच

Google की इंटरनल टेस्टिंग में, 2,405 .dtb और 283 .dtbo DT नोड पर libufdt का इस्तेमाल करने पर, कंपाइल करने के बाद फ़ाइल का साइज़ 70,618 और 8,566 बाइट हो गया. FreeBSD (124 मिलीसेकंड का रनटाइम) से पोर्ट किए गए DTO लागू करने की तुलना में, libufdt के DTO का रनटाइम 10 मिलीसेकंड है.

Pixel डिवाइसों की परफ़ॉर्मेंस की जांच, libufdt और libfdt की तुलना में. बेस नोड की संख्या का असर एक जैसा होता है. हालांकि, इसमें ये अंतर होते हैं:

  • 500 ओवरले (अडैप या बदलाव) ऑपरेशन में 6 से 8 गुना समय का अंतर होता है
  • 1,000 ओवरले (अनलिंक या बदलाव) ऑपरेशन में, समय में 8 से 10 गुना का अंतर होता है

X पर सेट की गई गिनती जोड़ने का उदाहरण:

पहली इमेज. जोड़ने की संख्या X है.

X पर सेट की गई गिनती को बदलने का उदाहरण:

दूसरी इमेज. ओवरराइड करने की संख्या X है.

libufdt को कुछ libfdt एपीआई और डेटा स्ट्रक्चर के साथ डेवलप किया गया है. libufdt का इस्तेमाल करते समय, आपको libfdt को शामिल करना होगा और लिंक करना होगा. हालांकि, अपने कोड में DTB या DTBO को चलाने के लिए, libfdt एपीआई का इस्तेमाल किया जा सकता है.

libufdt DTO API

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 के रूट नोड में नया नोड या प्रॉपर्टी ओवरले नहीं की जा सकती, क्योंकि ओवरले ऑपरेशन लेबल पर निर्भर करते हैं. मुख्य डीटी में लेबल तय करना ज़रूरी है और ओवरले डीटी, लेबल के साथ ओवरले किए जाने वाले नोड असाइन करता है. इसलिए, रूट नोड के लिए लेबल नहीं दिया जा सकता. साथ ही, रूट नोड को ओवरले नहीं किया जा सकता.

SoC वेंडर को मुख्य DT की ओवरले करने की सुविधा तय करनी होगी. ODM/OEM, सिर्फ़ SoC वेंडर के तय किए गए लेबल के साथ नोड जोड़ सकते हैं या उन्हें बदल सकते हैं. इस समस्या को हल करने के लिए, बेस डीटी के रूट नोड के नीचे odm नोड तय किया जा सकता है. इससे ओवरले डीटी के सभी ओडीएम नोड, नए नोड जोड़ पाएंगे. इसके अलावा, आपके पास मुख्य डेटाटेंप्लेट में SoC से जुड़े सभी नोड को रूट नोड के नीचे soc नोड में डालने का विकल्प है. इसके बारे में यहां बताया गया है:

main.dts overlay.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 में, DT टेबल हेडर के वर्शन 1 का इस्तेमाल करते समय, DTBO इमेज में कंप्रेस किए गए ओवरले इस्तेमाल करने की सुविधा जोड़ी गई है. DTBO हेडर v1 का इस्तेमाल करते समय, 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' are 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 टेस्ट में संपीड़ित किए गए ओवरले की जांच करने की सुविधा जोड़ी गई है. इससे, ओवरले ऐप्लिकेशन के सही होने की पुष्टि करने में मदद मिलती है.

डीटीओ लागू करने का सैंपल

यहां दिए गए निर्देशों में, libufdt (सैंपल कोड नीचे दिया गया है) के साथ डीटीओ को लागू करने का सैंपल बताया गया है.

डीटीओ के निर्देशों के सैंपल

  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. डीटी को ओवरले करें:
    1. मुख्य DT के लिए FDT हेडर पाने के लिए, ufdt_install_blob() का इस्तेमाल करें:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
    2. एफ़डीटी फ़ॉर्मैट में मर्ज किया गया डीटी पाने के लिए, ufdt_apply_overlay() को डीटीओ पर कॉल करें:
      merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                      overlay_buf, overlay_size);
    3. dtc_totalsize() का साइज़ पाने के लिए, merged_fdt का इस्तेमाल करें:
      merged_fdt_size = dtc_totalsize(merged_fdt);
    4. कर्नेल शुरू करने के लिए, मर्ज किए गए DT को पास करें:
      my_kernel_entry(0, machine_type, merged_fdt);

डीटीओ कोड का सैंपल

#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);
}