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

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

कर्नेल कमांड लाइन

डिवाइस ट्री (डीटी) में मौजूद ओरिजनल कर्नल कमांड लाइन, 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 में DTO का इस्तेमाल किया जा सकता है, लेकिन क्या DTO को लागू करने के लिए libufdt का इस्तेमाल करना सही है (AOSP सोर्स platform/system/libufdt पर उपलब्ध है). libufdt, फ़्लैट किए गए डिवाइस ट्री (एफ़डीटी) से असली ट्री स्ट्रक्चर (अनफ़्लैट किया गया डिवाइस ट्री या ufdt) बनाता है. इससे दो .dtb फ़ाइलों को मर्ज करने की प्रोसेस को O(N2) से O(N) तक बेहतर बनाया जा सकता है. यहां N, ट्री में मौजूद नोड की संख्या है.

परफ़ॉर्मेंस टेस्टिंग

Google की इंटरनल टेस्टिंग में, 2405 .dtb और 283 .dtbo DT नोड पर libufdt का इस्तेमाल करने पर, कंपाइल करने के बाद फ़ाइल का साइज़ 70,618 और 8,566 बाइट होता है. FreeBSD से पोर्ट किए गए DTO implementation (124 मि॰से॰ रनटाइम) की तुलना में, 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 के रूट नोड में कोई नया नोड या प्रॉपर्टी ओवरले नहीं की जा सकती, क्योंकि ओवरले ऑपरेशन लेबल पर निर्भर करते हैं. मुख्य DT को एक लेबल तय करना होता है और ओवरले DT, लेबल के साथ ओवरले किए जाने वाले नोड असाइन करता है. इसलिए, रूट नोड के लिए लेबल नहीं दिया जा सकता. इस वजह से, रूट नोड को ओवरले नहीं किया जा सकता.

SoC वेंडर को मुख्य डीटी की ओवरले करने की क्षमता तय करनी होगी. ओडीएम/ओईएम सिर्फ़ 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 के साथ DTO को लागू करने का तरीका बताया गया है. इसका सैंपल कोड यहां दिया गया है.

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

  1. लाइब्रेरी शामिल करें. libufdt का इस्तेमाल करने के लिए, डेटा स्ट्रक्चर और एपीआई के लिए libfdt शामिल करें:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
  2. मुख्य डीटी और ओवरले डीटी लोड करें. स्टोरेज से .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. मुख्य डीटी के लिए, FDT हेडर पाने के लिए ufdt_install_blob() का इस्तेमाल करें:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
    2. डीटीओ को ufdt_apply_overlay() कॉल करें, ताकि आपको FDT फ़ॉर्मैट में मर्ज किया गया डीटी मिल सके:
      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);
}