พูลหน่วยความจำ

หน้านี้อธิบายโครงสร้างข้อมูลและเมธอดที่ใช้เพื่อสื่อสารบัฟเฟอร์ออปเรอเรนต์ระหว่างไดรเวอร์กับเฟรมเวิร์กอย่างมีประสิทธิภาพ

เฟรมเวิร์กจะระบุค่าของการดำเนินการแบบคงที่ให้กับไดรเวอร์ ณ เวลาคอมไพล์โมเดล ค่าของ 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 โปรดดูรายละเอียดเพิ่มเติมที่ AHardwareBuffer
  • hardware_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 เมื่อรวมข้อมูลมิติข้อมูลทั้งหมดแล้ว บัฟเฟอร์อาจมีมิติข้อมูลหรือลําดับที่ไม่รู้จัก ในกรณีเช่นนี้ บัฟเฟอร์จะอยู่ในสถานะที่ยืดหยุ่นซึ่งมิติข้อมูลจะคงที่เมื่อใช้เป็นอินพุตของโมเดล และอยู่ในสถานะแบบไดนามิกเมื่อใช้เป็นเอาต์พุตของโมเดล คุณสามารถใช้บัฟเฟอร์เดียวกันกับเอาต์พุตที่มีรูปร่างต่างกันในการเรียกใช้ที่แตกต่างกัน และไดรเวอร์ต้องจัดการการปรับขนาดบัฟเฟอร์อย่างเหมาะสม

โดเมนหน่วยความจําเป็นฟีเจอร์เสริม โปรแกรมควบคุมอาจพิจารณาว่าไม่สามารถรองรับคำขอการจัดสรรหนึ่งๆ ได้เนื่องด้วยเหตุผลหลายประการ เช่น

  • บัฟเฟอร์ที่ขอมีขนาดแบบไดนามิก
  • โปรแกรมควบคุมมีข้อจำกัดด้านหน่วยความจำที่ทำให้จัดการบัฟเฟอร์ขนาดใหญ่ไม่ได้

อาจมีหลายชุดข้อความที่อ่านจากบัฟเฟอร์ที่จัดการโดยไดรเวอร์พร้อมกัน ไม่มีการกำหนดการเข้าถึงบัฟเฟอร์พร้อมกันสำหรับการเขียนหรืออ่าน/เขียน แต่ต้องไม่ทำให้บริการไดรเวอร์ขัดข้องหรือบล็อกผู้โทรโดยไม่มีกำหนดสิ้นสุด ไดรเวอร์อาจแสดงข้อผิดพลาดหรือปล่อยเนื้อหาของบัฟเฟอร์ไว้ในสถานะที่กําหนดไม่ได้