מאגרי זיכרון

בדף הזה מתוארים מבני הנתונים והשיטות שמשמשים לתקשורת יעילה של חוצצי אופרנד בין הנהג ל-framework.

בזמן הידור של המודל, ה-framework מספק לנהג את הערכים של האופרנדים הקבועים. בהתאם לאורך החיים של האופרנד הקבוע, הערכים שלו נמצאים בווקטור HIDL או במאגר זיכרון משותף.

  • אם משך החיים הוא CONSTANT_COPY, הערכים נמצאים בשדה operandValues במבנה המודל. מכיוון שהערכים בווקטור HIDL מועתקים במהלך תקשורת בין תהליכים (IPC), לכן בדרך כלל משתמשים בו רק כדי להחזיק כמות קטנה של נתונים, כמו אופרנדים סקלריים (למשל, סקלרי ההפעלה ב-ADD) ופרמטרים קטנים של טנזור (לדוגמה, חיישן הצורה ב-RESHAPE).
  • אם משך החיים הוא CONSTANT_REFERENCE, הערכים נמצאים בשדה pools במבנה המודל. במהלך ה-IPC יש כפילות רק של הכינויים של מאגרי הזיכרון המשותפים במקום להעתיק את הערכים הגולמיים. לכן עדיף להחזיק כמות גדולה של נתונים (לדוגמה, הפרמטרים של המשקל בקיפולים) באמצעות מאגרי זיכרון משותפים מאשר וקטורים של HIDL.

בזמן הביצוע של המודל, ה-framework מספק לנהג את מאגרי הנתונים הזמניים של האופרנדים של הקלט והפלט. בניגוד לקבועים של זמן הידור שעשויים להישלח בווקטור 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. תוכלו לקרוא מידע נוסף בקטע AHardwareBuffer.

החל מ-NN HAL 1.3, ב-NNAPI יש תמיכה בדומיינים של זיכרון שמספקים ממשקי הקצאה למאגרי נתונים זמניים בניהול מנהלי התקנים. ניתן להשתמש במאגרי נתונים זמניים בניהול הנהג גם כקלט או כפלט של ביצוע. לפרטים נוספים, ראו דומיינים של זיכרון.

מנהלי התקנים של NNAPI חייבים לתמוך במיפוי של שמות זיכרון ashmem ו-mmap_fd. החל מ-NN HAL 1.3, מנהלי התקנים צריכים גם לתמוך במיפוי של hardware_buffer_blob. התמיכה במצב כללי ללא BLOB hardware_buffer ובדומיינים של זיכרון היא אופציונלית.

חוצץ AHardwareBuffer

AHardwareBuffer הוא סוג של זיכרון משותף שעוטף מאגר נתונים זמני של Gralloc. ב-Android 10, ממשק ה-API של רשתות נוירונים (NNAPI) תומך בשימוש ב-AHardwareBuffer, מה שמאפשר לנהג לבצע פעולות מבלי להעתיק נתונים, ובכך משפר את הביצועים ואת צריכת החשמל של אפליקציות. לדוגמה, מקבץ HAL של מצלמה יכול להעביר אובייקטים של AHardwareBuffer ל-NNAPI בשביל עומסי עבודה של למידת מכונה, באמצעות כינויי AHardwareBuffer שנוצרו על ידי ממשקי API של NDK ו-Media NDK למצלמה. למידע נוסף, ראו ANeuralNetworksMemory_createFromAHardwareBuffer.

אובייקטים של AHardwareBuffer שמשמשים ב-NNAPI מועברים לנהג דרך מבנה hidl_memory שנקרא hardware_buffer או hardware_buffer_blob. המבנה hidl_memory hardware_buffer_blob מייצג רק אובייקטים של AHardwareBuffer בפורמט AHARDWAREBUFFER_FORMAT_BLOB.

המידע שנדרש על ידי ה-framework מקודד בשדה hidl_handle שבמבנה hidl_memory. השדה 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 ואילך, NNAPI תומך בדומיינים של זיכרון שמספקים ממשקי הקצאה למאגרי נתונים מנוהלים של מנהלי התקנים. כך ניתן להעביר זיכרונות נייטיב של המכשיר בהפעלות שונות, וכך למנוע העתקה וטרנספורמציה מיותרת של נתונים בין הפעלות רצופות באותו מנהל התקן. תהליך זה מתואר באיור 1.

זרימת נתונים במאגר הנתונים הזמני עם או בלי דומיינים של זיכרון

איור 1. זרימת נתונים של מאגר נתונים זמני באמצעות דומיינים של זיכרון

תכונת דומיין הזיכרון מיועדת לטינוטורים שהם בעיקר פנימיים לנהג, והם לא צריכים גישה לעיתים קרובות בצד הלקוח. דוגמאות לקנזורים כאלה כוללות את הסנסטורים של המצבים במודלים של רצף. עדיף להשתמש במאגרי זיכרון משותפים אם רוצים להשתמש בטנסטורים שזקוקים לגישה למעבד (CPU) בתדירות גבוהה בצד הלקוח.

כדי לתמוך במאפיין דומיין הזיכרון, מטמיעים את IDevice::allocate כדי לאפשר ל-framework לבקש הקצאת מאגר נתונים זמני בניהול הנהג. במהלך ההקצאה, ה-framework מספק את המאפיינים ואת דפוסי השימוש הבאים למאגר הנתונים:

  • ב-BufferDesc מתוארים המאפיינים הנדרשים של מאגר הנתונים הזמני.
  • BufferRole מתאר את דפוס השימוש הפוטנציאלי של מאגר הנתונים הזמני כקלט או כפלט של מודל מוכן. אפשר לציין כמה תפקידים במהלך ההקצאה של מאגר הנתונים הזמני, ולהשתמש בו רק כתפקידים שצוינו.

מאגר הנתונים הזמני שהוקצה לנהג הוא פנימי. הנהגים יכולים לבחור כל מיקום של מאגר נתונים זמני או כל פריסת נתונים. אחרי ההקצאה של מאגר הנתונים הזמני, הלקוח של הנהג יכול להתייחס אליו או לבצע בו פעולות באמצעות האסימון שמוחזר או האובייקט IBuffer.

האסימון מ-IDevice::allocate מסופק כשפונים למאגר הנתונים הזמני כאחד מהאובייקטים MemoryPool במבנה Request של הפעלה. כדי למנוע ניסיון לגשת למאגר הנתונים הזמני שמוקצה לתהליך אחר, הנהג צריך לבצע אימות מתאים בכל שימוש במאגר הנתונים הזמני. הנהג צריך לוודא שהשימוש במאגר הנתונים הזמני הוא אחד מהתפקידים ב-BufferRole שסופקו במהלך ההקצאה, ומיד אם השימוש בו לא חוקי.

האובייקט IBuffer משמש להעתקה מפורשת של זיכרון. במצבים מסוימים, הלקוח של הנהג צריך לאתחל את מאגר הנתונים הזמני על ידי הנהג ממאגר זיכרון משותף, או להעתיק אותו למאגר זיכרון משותף. תרחישים לדוגמה:

  • אתחול המשתנה של המצב
  • תוצאות הביניים נשמרות במטמון
  • ביצוע חלופי במעבד (CPU)

כדי לתמוך בתרחישים לדוגמה האלה, הנהג צריך להטמיע את הקוד IBuffer::copyTo ואת IBuffer::copyFrom ב-ashmem, ב-mmap_fd וב-hardware_buffer_blob, אם הוא תומך בהקצאת דומיינים של זיכרון. לנהג/ת לא חובה תהיה תמיכה במצב non-BLOB. hardware_buffer.

במהלך הקצאת מאגר הנתונים הזמני, אפשר להסיק את המאפיינים של מאגר הנתונים הזמני מהאופרנדים של המודל התואם של כל התפקידים שצוינו ב-BufferRole ומהמאפיינים שסופקו ב-BufferDesc. כשמשלבים את כל המידע הממדי, יכול להיות שהמידות או הדירוג של מאגר הנתונים הזמני לא ידועים. במקרה כזה, מאגר הנתונים הזמני נמצא במצב גמיש שבו המידות קבועות כשמשתמשים בו כקלט של מודל, ובמצב דינמי כשמשתמשים בו כפלט של המודל. אפשר להשתמש באותו מאגר נתונים זמני עם צורות שונות של פלט בפעולות שונות, והמנהל של צריך לתקן את הגודל של מאגר הנתונים הזמני.

דומיין הזיכרון הוא תכונה אופציונלית. נהג יכול לקבוע שהוא לא יכול לתמוך בבקשת הקצאה מסוימת מכמה סיבות. לדוגמה:

  • מאגר הנתונים הזמני המבוקש הוא בגודל דינמי.
  • יש לנהג מגבלות זיכרון שמונעות ממנו לטפל במאגרי נתונים זמניים גדולים.

אפשר לקרוא בו-זמנית כמה שרשורים שונים מהמאגר בניהול הנהג. לא מוגדרת גישה למאגר הנתונים הזמני לצורך כתיבה או קריאה/כתיבה בו-זמנית, אבל היא לא יכולה לקרוס את שירות הנהג או לחסום את המתקשר ללא הגבלת זמן. הנהג יכול להחזיר שגיאה או להשאיר את התוכן של מאגר הנתונים הזמני.