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

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

Kernel कमांड लाइन

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

/dts-v1/;

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

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

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

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

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

libufdt

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

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

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

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

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

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

main.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_try में फ़्लैग फ़ील्ड के चार सबसे कम ज़रूरी बिट, डीटी एंट्री के कंप्रेशन फ़ॉर्मैट के बारे में बताते हैं.

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 के लिए एफ़डीटी हेडर पाने के लिए, ufdt_install_blob() का इस्तेमाल करें:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
      
    2. एफ़डीटी फ़ॉर्मैट में मर्ज किया गया डीटी पाने के लिए, DTO को 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);
}