इस पेज में ऐसे डेटा स्ट्रक्चर और तरीकों के बारे में बताया गया है जिनका इस्तेमाल ड्राइवर और फ़्रेमवर्क के बीच बेहतर ढंग से ऑपरेंड बफ़र को कम्यूनिकेट करने के लिए किया जाता है.
मॉडल कंपाइलेशन के समय, फ़्रेमवर्क ड्राइवर को कॉन्स्टेंट ऑपरेटिंग की वैल्यू देता है. कॉन्स्टेंट ऑपरेंड के समय के आधार पर, इसकी वैल्यू, HIDL वेक्टर या शेयर किए गए मेमोरी पूल में मौजूद होती हैं.
- अगर लाइफ़टाइम वैल्यू
CONSTANT_COPY
है, तो वैल्यू, मॉडल स्ट्रक्चर केoperandValues
फ़ील्ड में मौजूद होती हैं. HIDL वेक्टर में वैल्यू, इंटरप्रोसेस कम्यूनिकेशन (IPC) के दौरान कॉपी की जाती हैं. इसलिए, आम तौर पर इसका इस्तेमाल सिर्फ़ छोटा डेटा होल्ड करने के लिए किया जाता है, जैसे कि स्केलर ऑपरेंड. (उदाहरण के लिए,ADD
में ऐक्टिवेशन स्केलर) और छोटे टेंसर पैरामीटर (उदाहरण के लिए,RESHAPE
में शेप टेंसर). - अगर लाइफ़टाइम वैल्यू
CONSTANT_REFERENCE
है, तो वैल्यू, मॉडल स्ट्रक्चर केpools
फ़ील्ड में मौजूद होती हैं. आईपीसी के दौरान, रॉ वैल्यू को कॉपी करने के बजाय, सिर्फ़ शेयर की गई मेमोरी पूल के हैंडल का डुप्लीकेट बनाया जाता है. इसलिए, HIDL वेक्टर की तुलना में, शेयर किए गए मेमोरी पूल का इस्तेमाल करके ज़्यादा डेटा (उदाहरण के लिए, कॉन्वलूशन में वेट पैरामीटर) रखना बेहतर होता है.
मॉडल एक्ज़ीक्यूशन के समय, फ़्रेमवर्क ड्राइवर को इनपुट और आउटपुट ऑपरेंड के बफ़र देता है. एचआईडीएल वेक्टर में भेजे गए कंपाइल-टाइम कॉन्सटेंट के उलट, किसी एक्ज़ीक्यूशन के इनपुट और आउटपुट डेटा को हमेशा मेमोरी पूल के कलेक्शन की मदद से बताया जाता है.
एचआईडीएल डेटा टाइप hidl_memory
का इस्तेमाल, कंपाइलेशन और एक्ज़ीक्यूशन, दोनों में किया जाता है. इससे, मैप नहीं किए गए, शेयर किए गए स्टोरेज पूल को दिखाया जाता है. ड्राइवर को मेमोरी को उसके हिसाब से मैप करना चाहिए, ताकि उसे hidl_memory
डेटा टाइप के नाम के आधार पर इस्तेमाल किया जा सके.
इस्तेमाल की जा सकने वाली मेमोरी के नाम:
ashmem
: Android ने आपके साथ मेमोरी शेयर की है. ज़्यादा जानकारी के लिए, मेमोरी देखें.mmap_fd
: शेयर की गई मेमोरी का बैक अप,mmap
के ज़रिए फ़ाइल डिस्क्रिप्टर से लिया गया है.hardware_buffer_blob
: शेयर की गई मेमोरी को AHardwareBuffer नेAHARDWARE_BUFFER_FORMAT_BLOB
फ़ॉर्मैट में इस्तेमाल किया है. न्यूरल नेटवर्क (एनएन) एचएएल 1.2 की ओर से उपलब्ध. ज़्यादा जानकारी के लिए, AHardwareBuffer पर जाएं.hardware_buffer
: शेयर की गई मेमोरी एक ऐसे सामान्य AHardwareBuffer से मिली है जोAHARDWARE_BUFFER_FORMAT_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 में, Neural Networks API (NNAPI) की मदद से AHardwareBuffer
का इस्तेमाल किया जा सकता है. इससे ड्राइवर, डेटा को कॉपी किए बिना डेटा को कॉपी कर सकता है. इससे ऐप्लिकेशन की परफ़ॉर्मेंस बेहतर होती है और ज़्यादा बैटरी खर्च होती है. उदाहरण के लिए, कैमरा एचएएल स्टैक, मशीन लर्निंग के वर्कलोड के लिए AHardwareBuffer ऑब्जेक्ट को एनएनएपीआई को भेज सकता है. इसके लिए, कैमरा एनडीके और मीडिया एनडीके एपीआई से जनरेट किए गए AHardwareBuffer हैंडल का इस्तेमाल किया जाता है. ज़्यादा जानकारी के लिए, ANeuralNetworksMemory_createFromAHardwareBuffer
देखें.
NNAPI में इस्तेमाल किए जाने वाले AHardwareBuffer ऑब्जेक्ट को hardware_buffer
या hardware_buffer_blob
नाम के hidl_memory
स्ट्रक्चर के ज़रिए ड्राइवर को पास किया जाता है.
hidl_memory
स्ट्रक्ट hardware_buffer_blob
सिर्फ़ AHARDWAREBUFFER_FORMAT_BLOB
फ़ॉर्मैट वाले AHardwareBuffer ऑब्जेक्ट के बारे में बताता है.
फ़्रेमवर्क के लिए ज़रूरी जानकारी को hidl_memory
स्ट्रक्चर के hidl_handle
फ़ील्ड में एन्कोड किया गया है. 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 या उसके बाद के वर्शन वाले डिवाइसों पर, एनएनएपीआई ऐसे मेमोरी डोमेन के साथ काम करता है जो ड्राइवर से मैनेज किए जाने वाले बफ़र के लिए ऐलोकेटर इंटरफ़ेस उपलब्ध कराते हैं. इससे, एक ही ड्राइवर पर लगातार काम करने के बीच, डेटा कॉपी करने और ट्रांसफ़ॉर्मेशन को रोकने के लिए, डिवाइस की नेटिव मेमोरी को पास किया जा सकता है. यह फ़्लो पहली इमेज में दिखाया गया है.
पहला डायग्राम. मेमोरी डोमेन का इस्तेमाल करके बफ़र डेटा फ़्लो
मेमोरी डोमेन की सुविधा उन टेंसर के लिए है जो ज़्यादातर ड्राइवर के लिए इंटरनल होते हैं. साथ ही, जिन्हें क्लाइंट साइड पर बार-बार ऐक्सेस करने की ज़रूरत नहीं होती. ऐसे टेंसर के उदाहरणों में, सीक्वेंस मॉडल में स्टेट टेंसर शामिल हैं. जिन टेंसर को क्लाइंट साइड पर बार-बार सीपीयू ऐक्सेस की ज़रूरत होती है उनके लिए शेयर किए गए मेमोरी पूल इस्तेमाल करना बेहतर होगा.
मेमोरी डोमेन की सुविधा ठीक से काम कर सके, इसके लिए IDevice::allocate
लागू करें, ताकि फ़्रेमवर्क को ड्राइवर से मैनेज किए जाने वाले बफ़र ऐलोकेशन के लिए अनुरोध करने की अनुमति मिल सके. असाइन किए जाने के दौरान, फ़्रेमवर्क बफ़र के लिए ये प्रॉपर्टी और इस्तेमाल के पैटर्न उपलब्ध कराता है:
BufferDesc
, बफ़र की ज़रूरी प्रॉपर्टी के बारे में बताता है.BufferRole
यह बताता है कि बफ़र का इस्तेमाल कैसे किया जा सकता है. यह जानकारी, तैयार किए गए मॉडल के इनपुट या आउटपुट के तौर पर मिलती है. बफ़र ऐलोकेशन के दौरान एक से ज़्यादा भूमिकाएं दी जा सकती हैं और तय किए गए बफ़र का इस्तेमाल, सिर्फ़ उन भूमिकाओं के तौर पर किया जा सकता है.
तय किया गया बफ़र, ड्राइवर के लिए इंटरनल होता है. ड्राइवर कोई भी बफ़र लोकेशन या डेटा लेआउट चुन सकता है. बफ़र के असाइन हो जाने के बाद, ड्राइवर का क्लाइंट, दिखाए गए टोकन या IBuffer
ऑब्जेक्ट का इस्तेमाल करके, बफ़र का रेफ़रंस ले सकता है या उसके साथ इंटरैक्ट कर सकता है.
IDevice::allocate
का टोकन तब दिया जाता है, जब बफ़र को एक्ज़ीक्यूट करने के Request
स्ट्रक्चर में MemoryPool
ऑब्जेक्ट में से एक के तौर पर रेफ़रंस दिया जाता है. किसी प्रोसेस को दूसरी प्रोसेस में असाइन किए गए बफ़र को ऐक्सेस करने से रोकने के लिए, ड्राइवर को बफ़र के हर इस्तेमाल पर सही तरीके से पुष्टि करनी होगी. ड्राइवर को इस बात की पुष्टि करनी होगी कि बफ़र का इस्तेमाल, ऐलोकेशन के दौरान दिए गए BufferRole
रोल में से एक है. साथ ही, अगर इस्तेमाल के गैर-कानूनी होने पर, यह प्रोसेस तुरंत पूरी नहीं हो पाती है.
IBuffer
ऑब्जेक्ट का इस्तेमाल, मेमोरी को साफ़ तौर पर कॉपी करने के लिए किया जाता है. कुछ मामलों में, ड्राइवर के क्लाइंट को शेयर की गई मेमोरी पूल से ड्राइवर की ओर से मैनेज किया गया बफ़र शुरू करना होगा या शेयर किए गए मेमोरी पूल में बफ़र को कॉपी करना होगा. इस्तेमाल के उदाहरणों में ये शामिल हैं:
- स्टेट टेंसर को शुरू करना
- बीच के नतीजों को कैश मेमोरी में सेव करना
- सीपीयू पर फ़ॉलबैक एक्ज़ीक्यूशन
इस्तेमाल के इन उदाहरणों के काम करने के लिए, ड्राइवर को ashmem
, mmap_fd
, और hardware_buffer_blob
के साथ IBuffer::copyTo
और IBuffer::copyFrom
को लागू करना होगा. ऐसा तब करना होगा, जब यह मेमोरी डोमेन असाइन करने की सुविधा के साथ काम करता हो. ड्राइवर के लिए, नॉन-बीएलओबी मोड hardware_buffer
का इस्तेमाल करना ज़रूरी नहीं है.
बफ़र ऐलोकेशन के दौरान, BufferRole
में तय की गई सभी भूमिकाओं के मॉडल ऑपरेंड के डेटा और BufferDesc
में दिए गए डाइमेंशन से बफ़र के डाइमेंशन का पता लगाया जाता है. डाइमेंशन वाली सारी जानकारी एक साथ होने पर, बफ़र में ऐसे डाइमेंशन या रैंक हो सकते हैं जिनके बारे में जानकारी नहीं है. ऐसे मामले में, बफ़र सुविधाजनक स्थिति में होता है. इसमें, मॉडल इनपुट के तौर पर इस्तेमाल किए जाने पर डाइमेंशन तय होते हैं. साथ ही, मॉडल आउटपुट के तौर पर इस्तेमाल किए जाने पर, डाइमेंशन डाइनैमिक स्थिति में होते हैं. एक ही बफ़र का इस्तेमाल, अलग-अलग फ़ॉर्मैट में आउटपुट के अलग-अलग आकारों के साथ किया जा सकता है. साथ ही, ड्राइवर को बफ़र का साइज़ बदलने को सही तरीके से मैनेज करना चाहिए.
मेमोरी डोमेन एक वैकल्पिक सुविधा है. ड्राइवर यह तय कर सकता है कि वह कई वजहों से किसी दिए गए आवंटन अनुरोध को स्वीकार नहीं कर सकता. उदाहरण के लिए:
- अनुरोध किए गए बफ़र का साइज़ डाइनैमिक है.
- ड्राइवर की मेमोरी में पाबंदियां है, जो उसे बड़े बफ़र को हैंडल करने से रोकती है.
ड्राइवर से मैनेज किए गए बफ़र को एक साथ कई अलग-अलग थ्रेड के लिए पढ़ा जा सकता है. लिखने या पढ़ने/लिखने के लिए एक साथ बफ़र को ऐक्सेस करने की जानकारी नहीं है, लेकिन इससे ड्राइवर सेवा क्रैश नहीं होनी चाहिए या कॉलर को हमेशा के लिए ब्लॉक नहीं करना चाहिए. ड्राइवर गड़बड़ी का मैसेज दिखा सकता है या बफ़र के कॉन्टेंट को तय नहीं कर सकता.