מאגרי זיכרון

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

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

  • אם משך החיים הוא CONSTANT_COPY, הערכים נמצאים בשדה operandValues במבנה המודל. מכיוון שהערכים בווקטור HIDL מועתקים במהלך תקשורת בין תהליכים (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 שנוצרו על ידי ממשקי ה-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. כשכל פרטי המאפיינים משולבים, יכול להיות שבמאגר הזמני יהיו מאפיינים או דירוג לא ידועים. במקרה כזה, המאגר נמצא במצב גמיש שבו המאפיינים קבועים כשמשתמשים בו כקלט של מודל, ובמצב דינמי כשמשתמשים בו כפלט של מודל. אפשר להשתמש באותו מאגר נתונים זמני עם צורות שונות של פלט בהפעלות שונות, והדרייבר צריך לטפל בגודל המאגר הזמני בצורה תקינה.

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

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

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