מאגרי זיכרון

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

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

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

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

סוג הנתונים hidl_memory ב-HIDL משמש גם בתהליך ה-compilation וגם בתהליך הביצוע כדי לייצג מאגר זיכרון משותף לא ממופה. הנהג צריך למפות את הזיכרון בהתאם כדי שניתן יהיה להשתמש בו על סמך שם סוג הנתונים 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 ודומיינים של זיכרון שאינם BLOB היא אופציונלית.

AHardwareBuffer

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

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

המידע שנדרש למסגרת מקודד בשדה hidl_handle של המבנה hidl_memory. השדה hidl_handle עוטף את השדה native_handle, שמקודד את כל המטא-נתונים הנדרשים לגבי מאגר AHardwareBuffer או Gralloc.

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

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

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

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

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

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

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

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

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

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