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

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

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

  • หากชีวิตคือ CONSTANT_COPY ค่าที่จะอยู่ใน operandValues ด้านของรูปแบบโครงสร้าง เพราะค่าในเวกเตอร์ HIDL ที่มีการคัดลอกในช่วงการสื่อสาร (IPC) นี้โดยปกติจะใช้เพียง แต่จะถือเป็นจำนวนเงินที่เล็ก ๆ ของข้อมูลดังกล่าวเป็นตัวถูกดำเนินการเกลา (ตัวอย่างเช่นเกลาเปิดใช้งานใน ADD ) และพารามิเตอร์เมตริกซ์ขนาดเล็ก (ตัวอย่างเช่น เมตริกซ์รูปร่างใน RESHAPE )
  • หากชีวิตคือ CONSTANT_REFERENCE ค่าที่อยู่ใน pools ด้านของรูปแบบโครงสร้าง เฉพาะหมายเลขอ้างอิงของพูลหน่วยความจำแบบแบ่งใช้เท่านั้นที่ทำซ้ำระหว่าง IPC แทนที่จะคัดลอกค่าดิบ ดังนั้นจึงมีประสิทธิภาพมากกว่าที่จะเก็บข้อมูลจำนวนมาก (เช่น พารามิเตอร์น้ำหนักในการบิด) โดยใช้พูลหน่วยความจำแบบแบ่งใช้มากกว่าเวกเตอร์ HIDL

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

ชนิดข้อมูล HIDL hidl_memory ถูกนำมาใช้ทั้งในการรวบรวมและการดำเนินการเพื่อเป็นตัวแทนของสระว่ายน้ำของหน่วยความจำที่ใช้ร่วมกันแม็ป ผู้ขับขี่ควร map หน่วยความจำตามเพื่อให้ใช้งานตามชื่อของ 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 สำหรับรายละเอียดเพิ่มเติมโปรดดูที่ AHardwareBuffer

จาก NN HAL 1.3 NNAPI สนับสนุนโดเมนหน่วยความจำที่มีอินเทอร์เฟซตัวจัดสรรสำหรับบัฟเฟอร์ที่จัดการโดยไดรเวอร์ บัฟเฟอร์ที่จัดการโดยไดรเวอร์ยังสามารถใช้เป็นอินพุตหรือเอาต์พุตการดำเนินการ สำหรับรายละเอียดเพิ่มเติมโปรดดูที่ โดเมนหน่วยความจำ

ไดรเวอร์ NNAPI ต้องสนับสนุนการทำแผนที่ของ ashmem และ mmap_fd ชื่อหน่วยความจำ จาก NN HAL 1.3 ไดรเวอร์ยังต้องสนับสนุนการทำแผนที่ของ hardware_buffer_blob การสนับสนุนสำหรับโหมดที่ไม่ใช่หยดทั่วไป hardware_buffer และหน่วยความจำโดเมนเป็นตัวเลือก

AHardwareBuffer

AHardwareBuffer เป็นประเภทของหน่วยความจำที่ใช้ร่วมกันที่ล้อมเป็น บัฟเฟอร์ Gralloc ใน Android 10 โครงข่ายประสาท API (NNAPI) สนับสนุนการใช้ AHardwareBuffer ช่วยให้คนขับรถที่จะดำเนินการประหารชีวิตโดยไม่มีการคัดลอกข้อมูลที่ช่วยเพิ่มประสิทธิภาพการทำงานและการใช้พลังงานสำหรับปพลิเคชัน ตัวอย่างเช่น สแต็ก HAL ของกล้องสามารถส่งผ่านอ็อบเจ็กต์ AHardwareBuffer ไปยัง NNAPI สำหรับเวิร์กโหลดแมชชีนเลิร์นนิงได้โดยใช้แฮนเดิล AHardwareBuffer ที่สร้างโดย NDK ของกล้องและสื่อ NDK API สำหรับข้อมูลเพิ่มเติมโปรดดูที่ ANeuralNetworksMemory_createFromAHardwareBuffer

AHardwareBuffer วัตถุที่ใช้ใน NNAPI จะถูกส่งผ่านให้คนขับรถผ่าน hidl_memory struct ชื่อทั้ง hardware_buffer หรือ hardware_buffer_blob hidl_memory struct hardware_buffer_blob เป็นเพียงวัตถุ AHardwareBuffer กับ AHARDWAREBUFFER_FORMAT_BLOB รูปแบบ

ข้อมูลที่จำเป็นตามกรอบที่มีการเข้ารหัสใน hidl_handle เขตของ hidl_memory struct hidl_handle ฟิลด์ wraps 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 อธิบายถึงรูปแบบการใช้ศักยภาพของบัฟเฟอร์เป็น input หรือ output ของรูปแบบที่เตรียมไว้ สามารถระบุได้หลายบทบาทระหว่างการจัดสรรบัฟเฟอร์ และสามารถใช้บัฟเฟอร์ที่จัดสรรเป็นบทบาทที่ระบุเท่านั้น

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

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

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

  • การเริ่มต้นของเทนเซอร์สถานะ
  • แคชผลลัพธ์ระดับกลาง
  • การดำเนินการทางเลือกบน CPU

เพื่อรองรับการใช้งานในกรณีเหล่านี้ผู้ขับขี่ต้องใช้ IBuffer::copyTo และ IBuffer::copyFrom กับ ashmem , mmap_fd และ hardware_buffer_blob ถ้าสนับสนุนการจัดสรรหน่วยความจำประสิทธิภาพสูง มันเป็นทางเลือกสำหรับคนขับรถให้การสนับสนุนโหมดที่ไม่ใช่หยด hardware_buffer

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

โดเมนหน่วยความจำเป็นคุณสมบัติเสริม ผู้ขับขี่สามารถระบุได้ว่าไม่สามารถสนับสนุนคำขอการจัดสรรที่กำหนดได้ด้วยเหตุผลหลายประการ ตัวอย่างเช่น:

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

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