मेमोरी पूल

इस पेज में ऐसे डेटा स्ट्रक्चर और तरीकों के बारे में बताया गया है जिनका इस्तेमाल ड्राइवर और फ़्रेमवर्क के बीच बेहतर ढंग से ऑपरेंड बफ़र को कम्यूनिकेट करने के लिए किया जाता है.

मॉडल कंपाइलेशन के समय, फ़्रेमवर्क ड्राइवर को कॉन्स्टेंट ऑपरेटिंग की वैल्यू देता है. कॉन्स्टेंट ऑपरेंड के समय के आधार पर, इसकी वैल्यू, 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 में दिए गए डाइमेंशन से बफ़र के डाइमेंशन का पता लगाया जाता है. डाइमेंशन वाली सारी जानकारी एक साथ होने पर, बफ़र में ऐसे डाइमेंशन या रैंक हो सकते हैं जिनके बारे में जानकारी नहीं है. ऐसे मामले में, बफ़र सुविधाजनक स्थिति में होता है. इसमें, मॉडल इनपुट के तौर पर इस्तेमाल किए जाने पर डाइमेंशन तय होते हैं. साथ ही, मॉडल आउटपुट के तौर पर इस्तेमाल किए जाने पर, डाइमेंशन डाइनैमिक स्थिति में होते हैं. एक ही बफ़र का इस्तेमाल, अलग-अलग फ़ॉर्मैट में आउटपुट के अलग-अलग आकारों के साथ किया जा सकता है. साथ ही, ड्राइवर को बफ़र का साइज़ बदलने को सही तरीके से मैनेज करना चाहिए.

मेमोरी डोमेन एक वैकल्पिक सुविधा है. ड्राइवर यह तय कर सकता है कि वह कई वजहों से किसी दिए गए आवंटन अनुरोध को स्वीकार नहीं कर सकता. उदाहरण के लिए:

  • अनुरोध किए गए बफ़र का साइज़ डाइनैमिक है.
  • ड्राइवर की मेमोरी में पाबंदियां है, जो उसे बड़े बफ़र को हैंडल करने से रोकती है.

ड्राइवर से मैनेज किए गए बफ़र को एक साथ कई अलग-अलग थ्रेड के लिए पढ़ा जा सकता है. लिखने या पढ़ने/लिखने के लिए एक साथ बफ़र को ऐक्सेस करने की जानकारी नहीं है, लेकिन इससे ड्राइवर सेवा क्रैश नहीं होनी चाहिए या कॉलर को हमेशा के लिए ब्लॉक नहीं करना चाहिए. ड्राइवर गड़बड़ी का मैसेज दिखा सकता है या बफ़र के कॉन्टेंट को तय नहीं कर सकता.