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