การเพิ่มประสิทธิภาพ DTO

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

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

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

/dts-v1/;

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

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

main.dts overlay.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 สองไฟล์จาก O(N 2 ) ถึง O(N) โดยที่ N คือจำนวนโหนดในแผนผัง

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

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

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

  • การดำเนินการซ้อนทับ 500 รายการ (ผนวกหรือแทนที่) มีความแตกต่างของเวลา 6x ถึง 8x
  • การดำเนินการซ้อนทับ 1,000 ครั้ง (ผนวกหรือแทนที่) มีความแตกต่างของเวลา 8x ถึง 10x

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

รูปที่ 1 การนับต่อท้ายคือ X

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

รูปที่ 2 จำนวนการเอาชนะคือ X

libufdt ได้รับการพัฒนาด้วย libfdt API และโครงสร้างข้อมูลบางตัว เมื่อใช้ 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 เมื่อใช้เวอร์ชัน 1 ของส่วนหัวตารางแผนผังอุปกรณ์ เมื่อใช้ส่วนหัว 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' will be 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);
}