หน้านี้อธิบายการเพิ่มประสิทธิภาพที่คุณทำได้ในการใช้งานการวางซ้อนต้นไม้อุปกรณ์ (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) จากต้นไม้อุปกรณ์แบบยุบ (FDT) จึงช่วยปรับปรุงการผสานไฟล์ .dtb
2 ไฟล์จาก O(N2) เป็น O(N) โดยที่ 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 | 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 บิตของช่อง 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
- รวมไลบรารี หากต้องการใช้
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()
เพื่อส่ง DT ที่ผสานแล้วในรูปแบบ FDT ไปยัง DTO โดยทำดังนี้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); }