หน้านี้อธิบายโครงสร้างข้อมูลและวิธีการที่ใช้ในการสื่อสารบัฟเฟอร์ตัวถูกดำเนินการระหว่างไดรเวอร์และเฟรมเวิร์กอย่างมีประสิทธิภาพ
ณ เวลาการคอมไพล์โมเดล กรอบงานจะจัดเตรียมค่าของตัวถูกดำเนินการคงที่ให้กับไดรเวอร์ ขึ้นอยู่กับอายุการใช้งานของตัวถูกดำเนินการคงที่ ค่าของมันจะอยู่ในเวกเตอร์ HIDL หรือพูลหน่วยความจำแบบแบ่งใช้
- หากอายุการใช้งานคือ
CONSTANT_COPY
ค่าจะอยู่ในฟิลด์operandValues
ของโครงสร้างโมเดล เนื่องจากค่าในเวกเตอร์ HIDL ถูกคัดลอกระหว่างการสื่อสารระหว่างกระบวนการ (IPC) โดยทั่วไปจะใช้เพื่อเก็บข้อมูลจำนวนเล็กน้อยเท่านั้น เช่น ตัวถูกดำเนินการสเกลาร์ (เช่น สเกลาร์การเปิดใช้งานในADD
) และพารามิเตอร์เทนเซอร์ขนาดเล็ก (เช่น เทนเซอร์รูปร่างในRESHAPE
) - หากอายุการใช้งานคือ
CONSTANT_REFERENCE
ค่าจะอยู่ในฟิลด์pools
ของโครงสร้างโมเดล เฉพาะหมายเลขอ้างอิงของพูลหน่วยความจำที่ใช้ร่วมกันเท่านั้นที่จะถูกทำซ้ำระหว่าง IPC แทนที่จะคัดลอกค่าดิบ ดังนั้นจึงมีประสิทธิภาพมากกว่าในการเก็บข้อมูลจำนวนมาก (เช่น พารามิเตอร์น้ำหนักในรูปแบบ Convolution) โดยใช้พูลหน่วยความจำแบบแบ่งใช้มากกว่าเวกเตอร์ HIDL
ณ เวลาดำเนินการโมเดล กรอบงานจะจัดเตรียมบัฟเฟอร์ของตัวถูกดำเนินการอินพุตและเอาต์พุตให้กับไดรเวอร์ ไม่เหมือนกับค่าคงที่เวลาคอมไพล์ที่อาจส่งไปในเวกเตอร์ HIDL ข้อมูลอินพุตและเอาต์พุตของการดำเนินการจะถูกสื่อสารผ่านคอลเลกชันของพูลหน่วยความจำเสมอ
ชนิดข้อมูล HIDL hidl_memory
ใช้ทั้งในการคอมไพล์และการดำเนินการเพื่อแสดงพูลหน่วยความจำแบบแบ่งใช้ที่ไม่ได้แมป ไดรเวอร์ควรแมปหน่วยความจำตามนั้นเพื่อให้สามารถใช้งานได้ตามชื่อของประเภทข้อมูล hidl_memory
ชื่อหน่วยความจำที่รองรับคือ:
-
ashmem
: หน่วยความจำที่แชร์ของ Android สำหรับรายละเอียดเพิ่มเติม โปรดดูที่ หน่วยความจำ -
mmap_fd
: หน่วยความจำที่ใช้ร่วมกันได้รับการสนับสนุนโดยตัวอธิบายไฟล์ผ่านmmap
-
hardware_buffer_blob
: หน่วยความจำที่ใช้ร่วมกันซึ่งได้รับการสนับสนุนโดย AHardwareBuffer ด้วยรูปแบบAHARDWARE_BUFFER_FORMAT_BLOB
พร้อมใช้งานจากโครงข่ายประสาทเทียม (NN) HAL 1.2 สำหรับรายละเอียดเพิ่มเติม โปรดดู AHardwareBuffer -
hardware_buffer
: หน่วยความจำที่ใช้ร่วมกันได้รับการสนับสนุนโดย AHardwareBuffer ทั่วไปที่ไม่ได้ใช้รูปแบบAHARDWARE_BUFFER_FORMAT_BLOB
บัฟเฟอร์ฮาร์ดแวร์โหมดที่ไม่ใช่ BLOB ได้รับการสนับสนุนในการดำเนินการแบบจำลองเท่านั้น มีให้ตั้งแต่ NN HAL 1.2 สำหรับรายละเอียดเพิ่มเติม โปรดดู AHardwareBuffer
จาก NN HAL 1.3 NNAPI รองรับโดเมนหน่วยความจำที่มีอินเทอร์เฟซตัวจัดสรรสำหรับบัฟเฟอร์ที่จัดการโดยไดรเวอร์ บัฟเฟอร์ที่จัดการโดยไดรเวอร์ยังสามารถใช้เป็นอินพุตหรือเอาต์พุตการดำเนินการได้อีกด้วย สำหรับรายละเอียดเพิ่มเติม โปรดดู โดเมนหน่วยความจำ
ไดรเวอร์ NNAPI ต้องรองรับการแมปชื่อหน่วยความจำ ashmem
และ mmap_fd
จาก NN HAL 1.3 ไดรเวอร์จะต้องรองรับการแมปของ hardware_buffer_blob
ด้วย การสนับสนุนสำหรับ hardware_buffer
และโดเมนหน่วยความจำโหมดที่ไม่ใช่ BLOB ทั่วไปเป็นทางเลือก
Aฮาร์ดแวร์บัฟเฟอร์
AHardwareBuffer เป็นหน่วยความจำที่ใช้ร่วมกันประเภทหนึ่งที่ล้อม รอบบัฟเฟอร์ Gralloc ใน Android 10 นั้น Neural Networks API (NNAPI) รองรับการใช้ AHardwareBuffer ทำให้ไดรเวอร์ดำเนินการได้โดยไม่ต้องคัดลอกข้อมูล ซึ่งปรับปรุงประสิทธิภาพและการใช้พลังงานสำหรับแอป ตัวอย่างเช่น สแต็ก HAL ของกล้องสามารถส่งผ่านออบเจ็กต์ AHardwareBuffer ไปยัง NNAPI สำหรับปริมาณงานการเรียนรู้ของเครื่องโดยใช้ตัวจัดการ AHardwareBuffer ที่สร้างโดยกล้อง NDK และ NDK API ของสื่อ สำหรับข้อมูลเพิ่มเติม โปรดดูที่ ANeuralNetworksMemory_createFromAHardwareBuffer
อ็อบเจ็กต์ AHardwareBuffer ที่ใช้ใน NNAPI จะถูกส่งผ่านไปยังไดรเวอร์ผ่านโครงสร้าง hidl_memory
ที่ชื่อ hardware_buffer
หรือ hardware_buffer_blob
hidl_memory
struct hardware_buffer_blob
แสดงถึงเฉพาะอ็อบเจ็กต์ AHardwareBuffer ที่มีรูปแบบ AHARDWAREBUFFER_FORMAT_BLOB
ข้อมูลที่เฟรมเวิร์กต้องการได้รับการเข้ารหัสในฟิลด์ hidl_handle
ของโครงสร้าง hidl_memory
ช่อง hidl_handle
จะล้อม native_handle
ซึ่งเข้ารหัสข้อมูลเมตาที่จำเป็นทั้งหมดเกี่ยวกับบัฟเฟอร์ AHardwareBuffer หรือ Gralloc
ไดรเวอร์จะต้องถอดรหัสฟิลด์ hidl_handle
ที่ให้มาอย่างถูกต้อง และเข้าถึงหน่วยความจำที่อธิบายโดย hidl_handle
เมื่อเรียกใช้เมธอด getSupportedOperations_1_2
, getSupportedOperations_1_1
หรือ getSupportedOperations
ไดรเวอร์ควรตรวจสอบว่าสามารถถอดรหัส hidl_handle
ที่ให้มาและเข้าถึงหน่วยความจำที่อธิบายโดย hidl_handle
ได้หรือไม่ การจัดเตรียมโมเดลต้องล้มเหลวหากไม่รองรับฟิลด์ hidl_handle
ที่ใช้สำหรับตัวถูกดำเนินการคงที่ การดำเนินการจะต้องล้มเหลวหากไม่รองรับฟิลด์ hidl_handle
ที่ใช้สำหรับตัวถูกดำเนินการอินพุตหรือเอาท์พุตของการดำเนินการ ขอแนะนำให้ไดรเวอร์ส่งคืนรหัสข้อผิดพลาด GENERAL_FAILURE
หากการเตรียมโมเดลหรือการดำเนินการล้มเหลว
โดเมนหน่วยความจำ
สำหรับอุปกรณ์ที่ใช้ Android 11 หรือสูงกว่า NNAPI รองรับโดเมนหน่วยความจำที่มีอินเทอร์เฟซตัวจัดสรรสำหรับบัฟเฟอร์ที่จัดการโดยไดรเวอร์ ซึ่งช่วยให้สามารถส่งผ่านหน่วยความจำดั้งเดิมของอุปกรณ์ข้ามการประมวลผล ระงับการคัดลอกข้อมูลที่ไม่จำเป็นและการแปลงระหว่างการประมวลผลต่อเนื่องกันบนไดรเวอร์เดียวกัน โฟลว์นี้แสดงไว้ในรูปที่ 1
รูปที่ 1 บัฟเฟอร์กระแสข้อมูลโดยใช้โดเมนหน่วยความจำ
คุณลักษณะโดเมนหน่วยความจำมีไว้สำหรับเทนเซอร์ที่อยู่ภายในไดรเวอร์เป็นส่วนใหญ่ และไม่จำเป็นต้องเข้าถึงฝั่งไคลเอ็นต์บ่อยครั้ง ตัวอย่างของเทนเซอร์ดังกล่าวรวมถึงเทนเซอร์สถานะในแบบจำลองลำดับ สำหรับเทนเซอร์ที่ต้องการการเข้าถึง CPU บ่อยครั้งในฝั่งไคลเอ็นต์ ขอแนะนำให้ใช้พูลหน่วยความจำแบบแบ่งใช้
เพื่อสนับสนุนคุณลักษณะโดเมนหน่วยความจำ ให้ใช้ IDevice::allocate
เพื่ออนุญาตให้กรอบงานร้องขอการจัดสรรบัฟเฟอร์ที่จัดการโดยไดรเวอร์ ในระหว่างการจัดสรร กรอบงานจะจัดเตรียมคุณสมบัติและรูปแบบการใช้งานต่อไปนี้สำหรับบัฟเฟอร์:
-
BufferDesc
อธิบายคุณสมบัติที่จำเป็นของบัฟเฟอร์ -
BufferRole
อธิบายรูปแบบการใช้งานที่เป็นไปได้ของบัฟเฟอร์เป็นอินพุตหรือเอาต์พุตของโมเดลที่เตรียมไว้ สามารถระบุได้หลายบทบาทในระหว่างการจัดสรรบัฟเฟอร์ และบัฟเฟอร์ที่จัดสรรสามารถใช้เป็นบทบาทที่ระบุเท่านั้น
บัฟเฟอร์ที่จัดสรรอยู่ภายในไดรเวอร์ ผู้ขับขี่สามารถเลือกตำแหน่งบัฟเฟอร์หรือเค้าโครงข้อมูลได้ เมื่อจัดสรรบัฟเฟอร์สำเร็จแล้ว ไคลเอนต์ของไดรเวอร์สามารถอ้างอิงหรือโต้ตอบกับบัฟเฟอร์โดยใช้โทเค็นที่ส่งคืนหรือวัตถุ IBuffer
โทเค็นจาก IDevice::allocate
มีให้เมื่ออ้างอิงบัฟเฟอร์เป็นหนึ่งในอ็อบเจ็กต์ MemoryPool
ในโครงสร้าง Request
ของการดำเนินการ เพื่อป้องกันไม่ให้กระบวนการพยายามเข้าถึงบัฟเฟอร์ที่จัดสรรไว้ในกระบวนการอื่น ไดรเวอร์ต้องใช้การตรวจสอบความถูกต้องที่เหมาะสมกับการใช้บัฟเฟอร์ทุกครั้ง โปรแกรมควบคุมต้องตรวจสอบว่าการใช้บัฟเฟอร์เป็นหนึ่งในบทบาท BufferRole
ที่ให้ไว้ในระหว่างการจัดสรร และต้องล้มเหลวในการดำเนินการทันทีหากการใช้งานผิดกฎหมาย
วัตถุ IBuffer
ใช้สำหรับการคัดลอกหน่วยความจำที่ชัดเจน ในบางสถานการณ์ ไคลเอ็นต์ของไดรเวอร์ต้องเริ่มต้นบัฟเฟอร์ที่จัดการโดยไดรเวอร์จากพูลหน่วยความจำที่ใช้ร่วมกัน หรือคัดลอกบัฟเฟอร์ออกไปยังพูลหน่วยความจำที่ใช้ร่วมกัน ตัวอย่างการใช้งานได้แก่:
- การเริ่มต้นของสเตตเทนเซอร์
- การแคชผลลัพธ์ระดับกลาง
- การดำเนินการสำรองบน CPU
เพื่อรองรับกรณีการใช้งานเหล่านี้ ไดรเวอร์ต้องใช้ IBuffer::copyTo
และ IBuffer::copyFrom
ด้วย ashmem
, mmap_fd
และ hardware_buffer_blob
หากรองรับการจัดสรรโดเมนหน่วยความจำ เป็นทางเลือกสำหรับไดรเวอร์ที่จะสนับสนุนโหมดที่ไม่ใช่ BLOB hardware_buffer
ในระหว่างการจัดสรรบัฟเฟอร์ ขนาดของบัฟเฟอร์สามารถอนุมานได้จากตัวถูกดำเนินการแบบจำลองที่สอดคล้องกันของบทบาททั้งหมดที่ระบุโดย BufferRole
และมิติที่ให้ไว้ใน BufferDesc
เมื่อรวมข้อมูลมิติทั้งหมดเข้าด้วยกัน บัฟเฟอร์อาจมีมิติหรืออันดับที่ไม่รู้จัก ในกรณีเช่นนี้ บัฟเฟอร์จะอยู่ในสถานะยืดหยุ่น โดยที่มิติได้รับการแก้ไขเมื่อใช้เป็นอินพุตโมเดล และอยู่ในสถานะไดนามิกเมื่อใช้เป็นเอาต์พุตโมเดล บัฟเฟอร์เดียวกันสามารถใช้กับรูปร่างเอาต์พุตที่แตกต่างกันในการดำเนินการที่แตกต่างกัน และไดรเวอร์จะต้องจัดการกับการปรับขนาดบัฟเฟอร์อย่างเหมาะสม
โดเมนหน่วยความจำเป็นคุณสมบัติเสริม ผู้ขับสามารถระบุได้ว่าไม่สามารถรองรับคำขอการจัดสรรที่กำหนดได้ด้วยเหตุผลหลายประการ ตัวอย่างเช่น:
- บัฟเฟอร์ที่ร้องขอมีขนาดไดนามิก
- ไดรเวอร์มีข้อจำกัดด้านหน่วยความจำซึ่งทำให้ไม่สามารถจัดการกับบัฟเฟอร์ขนาดใหญ่ได้
เป็นไปได้ที่เธรดต่างๆ หลายๆ เธรดจะอ่านจากบัฟเฟอร์ที่จัดการโดยไดรเวอร์พร้อมกัน การเข้าถึงบัฟเฟอร์พร้อมกันสำหรับการเขียนหรืออ่าน/เขียนไม่ได้ถูกกำหนดไว้ แต่จะต้องไม่ทำให้บริการไดรเวอร์เสียหายหรือบล็อกผู้เรียกอย่างไม่มีกำหนด ไดรเวอร์สามารถส่งคืนข้อผิดพลาดหรือปล่อยให้เนื้อหาของบัฟเฟอร์อยู่ในสถานะไม่แน่นอน