เพิ่มประสิทธิภาพองค์กร DTO

หน้านี้จะกล่าวถึงการเพิ่มประสิทธิภาพที่คุณทำได้กับการติดตั้งใช้งาน Device Tree Overlay (DTO) อธิบายข้อจำกัดในการซ้อนทับโหนดรูท และให้รายละเอียดเกี่ยวกับวิธี กำหนดค่าการซ้อนทับที่บีบอัดในอิมเมจ DTBO นอกจากนี้ ยังมีตัวอย่าง วิธีการติดตั้งใช้งานและโค้ดด้วย

บรรทัดคำสั่งเคอร์เนล

บรรทัดคำสั่งเคอร์เนลเดิมใน Device Tree (DT) จะอยู่ในโหนด chosen/bootargs Bootloader ต้องต่อตำแหน่งนี้ กับแหล่งที่มาอื่นๆ ของบรรทัดคำสั่งเคอร์เนล

/dts-v1/;

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

DTO ไม่สามารถต่อค่าจาก DT หลักและ DT การวางซ้อนได้ ดังนั้น คุณต้องใส่บรรทัดคำสั่งเคอร์เนลของ DT หลักใน chosen/bootargs และบรรทัดคำสั่งเคอร์เนลของ DT การวางซ้อนใน chosen/bootargs_ext จากนั้น Bootloader จะต่อตำแหน่งเหล่านี้ และส่งผลลัพธ์ไปยังเคอร์เนล

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

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

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

libufdt

แม้ว่า libfdt เวอร์ชันล่าสุด libfdt จะรองรับ DTO แต่เราขอแนะนำให้ใช้ libufdt เพื่อใช้ DTO (แหล่งที่มาของ AOSP ที่ platform/system/libufdt) libufdt สร้างโครงสร้างแบบต้นไม้จริง (Device Tree ที่ไม่ได้ Flatten หรือ ufdt) จาก Device Tree ที่ Flatten (FDT) จึงช่วยปรับปรุง การผสานไฟล์ .dtb 2 ไฟล์จาก O(N2) เป็น O(N) โดยที่ N คือ จำนวนโหนดในโครงสร้างแบบต้นไม้

การทดสอบประสิทธิภาพ

ในการทดสอบภายในของ Google การใช้ libufdt ใน 2405 .dtb และ 283 .dtbo โหนด DT จะทำให้ไฟล์มีขนาด 70,618 และ 8,566 ไบต์หลังจากคอมไพล์ เมื่อเทียบกับการติดตั้งใช้งาน DTO ที่พอร์ตมาจาก FreeBSD (รันไทม์ 124 มิลลิวินาที) libufdt รันไทม์ DTO คือ 10 มิลลิวินาที

การทดสอบประสิทธิภาพสำหรับอุปกรณ์ Pixel เทียบกับ libufdt และ libfdt จำนวนโหนดฐานมีผลคล้ายกัน แต่มีความแตกต่างดังนี้

  • การดำเนินการซ้อนทับ (ต่อท้ายหรือลบล้าง) 500 รายการมีเวลาต่างกัน 6-8 เท่า
  • การดำเนินการซ้อนทับ (ต่อท้ายหรือลบล้าง) 1,000 รายการใช้เวลาต่างกัน 8-10 เท่า

ตัวอย่างที่มีการตั้งค่าการต่อท้ายจำนวนเป็น X

รูปที่ 1 การต่อท้ายจำนวนคือ X

ตัวอย่างที่มีการตั้งค่าการลบล้างจำนวนเป็น X

รูปที่ 2 การลบล้างจำนวนคือ X

libufdt พัฒนาขึ้นด้วย API และโครงสร้างข้อมูลlibfdtบางส่วน เมื่อใช้ libufdt คุณต้องรวมและลิงก์ libfdt (อย่างไรก็ตาม ในโค้ด คุณสามารถใช้ libfdt API เพื่อดำเนินการ DTB หรือ DTBO ได้)

libufdt DTO API

API หลักไปยัง 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 ไปยัง Bootloader ดูการติดตั้งใช้งานอ้างอิงได้ที่ sysdeps/libufdt_sysdeps_*.c

ข้อจำกัดของโหนดรูท

คุณไม่สามารถวางซ้อนโหนดหรือพร็อพเพอร์ตี้ใหม่ลงในโหนดรูทของ DT หลักได้ เนื่องจากการดำเนินการวางซ้อนต้องอาศัยป้ายกำกับ เนื่องจาก DT หลักต้องกำหนดป้ายกำกับและ DT การวางซ้อนจะกำหนดโหนดที่จะวางซ้อนด้วยป้ายกำกับ คุณจึงไม่สามารถกำหนดป้ายกำกับสำหรับโหนดรูท (และวางซ้อนโหนดรูทไม่ได้)

ผู้ให้บริการ SoC ต้องกำหนดความสามารถในการซ้อนทับของ DT หลัก ส่วน ODM/OEM จะทำได้เพียง ต่อท้ายหรือลบล้างโหนดที่มีป้ายกำกับที่กำหนดโดยผู้ให้บริการ SoC วิธีแก้ปัญหาเบื้องต้นคือ คุณสามารถกำหนดโหนด odm ภายใต้โหนดรูทใน DT ฐาน ซึ่งจะช่วยให้โหนด ODM ทั้งหมดใน DT การวางซ้อนเพิ่มโหนดใหม่ได้ หรือจะใส่โหนดที่เกี่ยวข้องกับ SoC ทั้งหมดใน DT ฐานลงในโหนด 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 เพิ่มการรองรับการใช้การวางซ้อนที่บีบอัด ในรูปภาพ DTBO เมื่อใช้ส่วนหัวของตาราง DT เวอร์ชัน 1 เมื่อใช้ส่วนหัว DTBO v1 บิตที่มีนัยสำคัญน้อยที่สุด 4 บิตของฟิลด์แฟล็ก ใน 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 เพื่อช่วยคุณ ยืนยันความถูกต้องของแอปภาพซ้อนทับ

ตัวอย่างการใช้งาน DTO

วิธีการต่อไปนี้จะแนะนำการติดตั้งใช้งาน DTO ตัวอย่าง ด้วย libufdt (โค้ดตัวอย่างด้านล่าง)

ตัวอย่างวิธีการ DTO

  1. รวมไลบรารี หากต้องการใช้ libufdt ให้ใส่ libfdt สำหรับโครงสร้างข้อมูลและ API
    #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. ซ้อนทับ DT ดังนี้
    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() เพื่อรับ 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);
}