หน้านี้จะอธิบายถึงการเพิ่มประสิทธิภาพที่คุณสามารถทำได้กับการติดตั้งใช้งานการวางซ้อนแผนผังอุปกรณ์ (DTO) อธิบายข้อจำกัดเกี่ยวกับการซ้อนทับโหนดราก และรายละเอียดวิธีกำหนดค่าการวางซ้อนที่บีบอัดในอิมเมจ DTBO รวมทั้งมีตัวอย่างวิธีการติดตั้งและโค้ด
บรรทัดคำสั่งของเคอร์เนล
บรรทัดคำสั่งเคอร์เนลเดิมใน Device Tree (DT) อยู่ในโหนด chosen/bootargs
บูตโหลดเดอร์ต้องต่อเชื่อมตำแหน่งนี้กับแหล่งที่มาอื่นๆ ของบรรทัดคำสั่งเคอร์เนล
/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
ล่าสุดจะรองรับ DTO แต่เราขอแนะนำให้ใช้ libufdt
เพื่อนำ DTO ไปใช้งาน (แหล่งที่มา AOSP ที่ platform/system/libufdt
) libufdt
สร้างโครงสร้างแบบต้นไม้จริง (แผนผังอุปกรณ์ที่ไม่แยกเป็นหลายรายการ หรือ ufdt) จาก DTO ที่มีลำดับชั้น (FDT) เพื่อให้ปรับปรุงการผสานไฟล์ .dtb
2 ไฟล์จาก O(N2) ในโหนด N เป็น O(N) ได้
การทดสอบประสิทธิภาพ
ในการทดสอบภายในของ Google การใช้ libufdt
ใน 2405 .dtb
และโหนด DT .dtbo
283 โหนดทำให้ไฟล์มีขนาด 70,618 และ 8,566 ไบต์หลังจากการคอมไพล์ เมื่อเทียบกับการใช้งาน DTO ที่ย้ายมาจาก FreeBSD (รันไทม์ 124 มิลลิวินาที) รันไทม์ DTO ของ libufdt
เท่ากับ 10 มิลลิวินาที
การทดสอบประสิทธิภาพสำหรับอุปกรณ์ Pixel เทียบกับ libufdt
และ libfdt
จำนวนโหนดฐานจะมีผลคล้ายกัน แต่มีข้อแตกต่างต่อไปนี้
- การดำเนินการซ้อนทับ 500 รายการ (ต่อท้ายหรือลบล้าง) มีเวลาต่างกัน 6 ถึง 8 เท่า
- การดำเนินการวางซ้อน (เพิ่มต่อท้ายหรือลบล้าง) 1,000 ครั้งใช้เวลานานขึ้น 8-10 เท่า
ตัวอย่างการตั้งค่าจำนวนต่อท้ายเป็น 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
ไปยังบูตโหลดเดอร์
ดูการใช้งานอ้างอิงได้ที่ 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 บิตที่สำคัญที่สุดของช่องแฟล็กใน 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
- รวมไลบรารี หากต้องการใช้
libufdt
ให้ใส่libfdt
สำหรับโครงสร้างข้อมูลและ API ดังนี้#include <libfdt.h> #include <ufdt_overlay.h>
- โหลด 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);
- วางซ้อน DT โดยทำดังนี้
- ใช้
ufdt_install_blob()
เพื่อรับส่วนหัว FDT สำหรับ DT หลัก ดังนี้main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- โทรติดต่อ
ufdt_apply_overlay()
ไปยัง DTO เพื่อขอ DT ที่ผสานในรูปแบบ FDT:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- ใช้
merged_fdt
เพื่อดูขนาดของdtc_totalsize()
ดังนี้merged_fdt_size = dtc_totalsize(merged_fdt);
- ส่ง 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); }