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

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

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

บรรทัดคำสั่งของเคอร์เนลดั้งเดิมในแผนผังอุปกรณ์ (DT) อยู่ใน chosen/bootargs โหนด Bootloader ต้องเชื่อมต่อ ตำแหน่งที่มีแหล่งที่มาอื่นๆ ของบรรทัดคำสั่งเคอร์เนล:

/dts-v1/;

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

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

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 2 ไฟล์จาก O(N2) ไปยัง O(N) โดย N คือ จำนวนโหนดในโครงสร้าง

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

ในการทดสอบภายในของ Google โดยใช้ libufdt ใน 2405 .dtb และ 283 โหนด DT .dtbo ทำให้เกิดขนาดไฟล์เป็น 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 การซ้อนทับ.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 บิตที่สำคัญน้อยที่สุดในฟิลด์ Flag ใน 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() ไปยัง 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);
}