หน้านี้อธิบายโครงสร้างข้อมูลและเมธอดที่ใช้เพื่อสื่อสารบัฟเฟอร์ออปเรอเรนต์ระหว่างไดรเวอร์กับเฟรมเวิร์กอย่างมีประสิทธิภาพ
เฟรมเวิร์กจะระบุค่าของการดำเนินการแบบคงที่ให้กับไดรเวอร์ ณ เวลาคอมไพล์โมเดล ค่าของ Operand แบบคงที่จะอยู่ในรูปแบบเวกเตอร์ HIDL หรือพูลหน่วยความจำที่ใช้ร่วมกัน ทั้งนี้ขึ้นอยู่กับอายุการใช้งานของ Operand
- หากอายุการใช้งานคือ
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
มีให้บริการจาก Neural Networks (NN) HAL 1.2 โปรดดูรายละเอียดเพิ่มเติมที่ AHardwareBufferhardware_buffer
: หน่วยความจำที่ใช้ร่วมกันซึ่งรองรับโดย AHardwareBuffer ทั่วไปที่ไม่ใช้รูปแบบAHARDWARE_BUFFER_FORMAT_BLOB
ระบบรองรับบัฟเฟอร์ฮาร์ดแวร์ในโหมดที่ไม่ใช่ BLOB เฉพาะในการใช้งานโมเดลเท่านั้น ใช้ได้กับ NN HAL 1.2 ดูรายละเอียดเพิ่มเติมได้ที่ A hardwareBuffer
ตั้งแต่ NN HAL 1.3 เป็นต้นไป NNAPI รองรับโดเมนหน่วยความจำที่มีอินเทอร์เฟซตัวจัดสรรสำหรับบัฟเฟอร์ที่จัดการโดยไดรเวอร์ นอกจากนี้ คุณยังใช้บัฟเฟอร์ที่จัดการโดยไดรเวอร์เป็นอินพุตหรือเอาต์พุตการดําเนินการได้ด้วย โปรดดูรายละเอียดเพิ่มเติมที่หัวข้อโดเมนหน่วยความจำ
ไดรเวอร์ NNAPI ต้องรองรับการแมปชื่อหน่วยความจำ ashmem
และ mmap_fd
ตั้งแต่ NN HAL 1.3 เป็นต้นไป โปรแกรมควบคุมต้องรองรับการแมป hardware_buffer_blob
ด้วย รองรับhardware_buffer
โหมดทั่วไปที่ไม่ใช่ BLOB และโดเมนหน่วยความจำ (ไม่บังคับ)
AHardwareBuffer
AHardwareBuffer คือหน่วยความจําที่ใช้ร่วมกันประเภทหนึ่งที่รวมบัฟเฟอร์ Gralloc ใน Android 10 Neural Networks API (NNAPI) รองรับการใช้ AHardwareBuffer ซึ่งช่วยให้โปรแกรมควบคุมสามารถดำเนินการได้โดยไม่ต้องคัดลอกข้อมูล ซึ่งจะช่วยปรับปรุงประสิทธิภาพและการสิ้นเปลืองพลังงานของแอป ตัวอย่างเช่น สแต็ก HAL ของกล้องสามารถส่งออบเจ็กต์ AHardwareBuffer ไปยัง NNAPI สำหรับเวิร์กโหลดแมชชีนเลิร์นนิงได้โดยใช้แฮนเดิล AHardwareBuffer ที่ NDK ของกล้องและ NDK ของสื่อสร้างขึ้น ดูข้อมูลเพิ่มเติมได้ที่ 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
ซึ่งเข้ารหัสข้อมูลเมตาทั้งหมดที่จำเป็นเกี่ยวกับ 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 ที่ส่วนใหญ่เป็นระบบภายในกับไดรเวอร์และไม่จําเป็นต้องเข้าถึงบ่อยครั้งในฝั่งไคลเอ็นต์ ตัวอย่างเทนเซอร์ดังกล่าว ได้แก่ เทนเซอร์สถานะในโมเดลลำดับ สำหรับเทนเซอร์ที่ต้องเข้าถึง 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
เมื่อรวมข้อมูลมิติข้อมูลทั้งหมดแล้ว บัฟเฟอร์อาจมีมิติข้อมูลหรือลําดับที่ไม่รู้จัก ในกรณีเช่นนี้ บัฟเฟอร์จะอยู่ในสถานะที่ยืดหยุ่นซึ่งมิติข้อมูลจะคงที่เมื่อใช้เป็นอินพุตของโมเดล และอยู่ในสถานะแบบไดนามิกเมื่อใช้เป็นเอาต์พุตของโมเดล คุณสามารถใช้บัฟเฟอร์เดียวกันกับเอาต์พุตที่มีรูปร่างต่างกันในการเรียกใช้ที่แตกต่างกัน และไดรเวอร์ต้องจัดการการปรับขนาดบัฟเฟอร์อย่างเหมาะสม
โดเมนหน่วยความจําเป็นฟีเจอร์เสริม โปรแกรมควบคุมอาจพิจารณาว่าไม่สามารถรองรับคำขอการจัดสรรหนึ่งๆ ได้เนื่องด้วยเหตุผลหลายประการ เช่น
- บัฟเฟอร์ที่ขอมีขนาดแบบไดนามิก
- โปรแกรมควบคุมมีข้อจำกัดด้านหน่วยความจำที่ทำให้จัดการบัฟเฟอร์ขนาดใหญ่ไม่ได้
อาจมีหลายชุดข้อความที่อ่านจากบัฟเฟอร์ที่จัดการโดยไดรเวอร์พร้อมกัน ไม่มีการกำหนดการเข้าถึงบัฟเฟอร์พร้อมกันสำหรับการเขียนหรืออ่าน/เขียน แต่ต้องไม่ทำให้บริการไดรเวอร์ขัดข้องหรือบล็อกผู้โทรโดยไม่มีกำหนดสิ้นสุด ไดรเวอร์อาจแสดงข้อผิดพลาดหรือปล่อยเนื้อหาของบัฟเฟอร์ไว้ในสถานะที่กําหนดไม่ได้