בדף הזה מוסבר על מבני הנתונים והשיטות שמשמשים לתקשורת יעילה של מאגרי אופרנדים בין מנהל ההתקן לבין המסגרת.
בזמן הידור המודל, המסגרת מספקת את הערכים של האופרנדים הקבועים לדרייבר. בהתאם לזמן החיים של האופרנד הקבוע, הערכים שלו נמצאים בווקטור HIDL או במאגר זיכרון משותף.
- אם משך החיים הוא
CONSTANT_COPY
, הערכים נמצאים בשדהoperandValues
של מבנה המודל. מכיוון שהערכים בווקטור HIDL מועתקים במהלך תקשורת בין תהליכים (IPC), בדרך כלל משתמשים בו רק כדי להחזיק כמות קטנה של נתונים, כמו אופרנדים סקלריים (לדוגמה, הסקלר של ההפעלה ב-ADD
) ופרמטרים של טנסורים קטנים (לדוגמה, טנסור הצורה ב-RESHAPE
). - אם משך החיים הוא
CONSTANT_REFERENCE
, הערכים נמצאים בשדהpools
של מבנה המודל. במהלך תקשורת בין תהליכים (IPC) משוכפלים רק ה-handles של מאגרי הזיכרון המשותף, ולא מועתקים הערכים הגולמיים. לכן, יעיל יותר להחזיק כמות גדולה של נתונים (לדוגמה, פרמטרים של משקל בהמרות) באמצעות מאגרי זיכרון משותפים מאשר וקטורים של HIDL.
בזמן ההפעלה של המודל, המסגרת מספקת לדרייבר את המאגרים של אופרנדים הקלט והפלט. בניגוד לקבועים בזמן הקומפילציה שאולי נשלחים בווקטור 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
HardwareBuffer הוא סוג של זיכרון משותף שעוטף מאגר Gralloc. ב-Android 10, Neural Networks API (NNAPI) תומך בשימוש ב-AHardwareBuffer, ומאפשר לדרייבר לבצע פעולות בלי להעתיק נתונים. כך משתפרים הביצועים וצריכת החשמל באפליקציות. לדוגמה, מחסנית HAL של מצלמה יכולה להעביר אובייקטים של AHardwareBuffer ל-NNAPI עבור עומסי עבודה של למידת מכונה באמצעות נקודות אחיזה של AHardwareBuffer שנוצרו על ידי ממשקי API של NDK של מצלמה ו-NDK של מדיה. מידע נוסף זמין במאמר ANeuralNetworksMemory_createFromAHardwareBuffer
.
אובייקטים של HardwareBuffer שמשמשים ב-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 buffer.
מנהל ההתקן צריך לפענח בצורה נכונה את השדה 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. שימוש בדומיינים של זיכרון כדי ליצור מאגר זמני לזרימת נתונים
התכונה 'דומיין זיכרון' מיועדת לטנסורים שהם בעיקר פנימיים למנהל ההתקן ולא נדרשת גישה תכופה אליהם בצד הלקוח. דוגמאות לטנסורים כאלה כוללות את טנסורי המצב במודלים של רצפים. בטנסורים שצריכים גישה תכופה למעבד בצד הלקוח, עדיף להשתמש במאגרי זיכרון משותפים.
כדי לתמוך בתכונה של דומיין הזיכרון, צריך להטמיע את IDevice::allocate
כדי לאפשר למסגרת לבקש הקצאת מאגר בניהול מנהל ההתקן. במהלך ההקצאה, המסגרת מספקת את המאפיינים הבאים ודפוסי השימוש הבאים עבור המאגר:
-
BufferDesc
מתאר את המאפיינים הנדרשים של המאגר. BufferRole
מתאר את דפוס השימוש הפוטנציאלי של המאגר כקלט או כפלט של מודל מוכן. אפשר לציין כמה תפקידים במהלך הקצאת המאגר, ואפשר להשתמש במאגר שהוקצה רק בתפקידים שצוינו.
המאגר שהוקצה הוא פנימי לדרייבר. מנהל התקן יכול לבחור כל מיקום של מאגר או פריסת נתונים. אחרי שהוקצה מאגר בהצלחה, הלקוח של מנהל ההתקן יכול להפנות למאגר או ליצור איתו אינטראקציה באמצעות האסימון שמוחזר או האובייקט IBuffer
.
האסימון מ-IDevice::allocate
מסופק כשמפנים אל המאגר כאחד מאובייקטי MemoryPool
במבנה Request
של ביצוע. כדי למנוע מתהליך מסוים לנסות לגשת למאגר שהוקצה בתהליך אחר, מנהל ההתקן צריך להחיל אימות מתאים בכל שימוש במאגר. הדרייבר צריך לוודא שהשימוש בבאפר הוא אחד מBufferRole
התפקידים שסופקו במהלך ההקצאה, ואם השימוש לא חוקי, הוא צריך להפסיק את ההרצה באופן מיידי.
האובייקט IBuffer
משמש להעתקה מפורשת של הזיכרון. במקרים מסוימים, הלקוח של מנהל ההתקן צריך לאתחל את המאגר שמנוהל על ידי מנהל ההתקן ממאגר זיכרון משותף, או להעתיק את המאגר למאגר זיכרון משותף. תרחישים לדוגמה:
- אתחול של טנסור המצב
- שמירת תוצאות ביניים במטמון
- ביצוע חזרה למצב ראשוני במעבד
כדי לתמוך בתרחישי השימוש האלה, מנהל ההתקן צריך להטמיע את IBuffer::copyTo
ואת IBuffer::copyFrom
עם ashmem
, mmap_fd
ו-hardware_buffer_blob
אם הוא תומך בהקצאת זיכרון לדומיין. התמיכה במצב שאינו BLOB היא אופציונלית עבור מנהל ההתקן
hardware_buffer
.
במהלך הקצאה של מאגר נתונים זמני, אפשר להסיק את המימדים של מאגר הנתונים הזמני מהאופרנדים התואמים של המודל של כל התפקידים שצוינו על ידי BufferRole
, ומהמימדים שצוינו ב-BufferDesc
. אחרי שמשלבים את כל המידע על המאפיינים, יכול להיות שיהיו מאפיינים או דירוג לא ידועים במאגר. במקרה כזה, המאגר נמצא במצב גמיש שבו המאפיינים קבועים כשמשתמשים בו כקלט למודל, ובמצב דינמי כשמשתמשים בו כפלט למודל. אפשר להשתמש באותו מאגר נתונים זמני עם צורות שונות של פלטים בהרצות שונות, והדרייבר צריך לטפל בשינוי הגודל של מאגר הנתונים הזמני בצורה נכונה.
דומיין זיכרון הוא תכונה אופציונלית. יכולות להיות כמה סיבות לכך שנהג יקבע שהוא לא יכול לתמוך בבקשת הקצאה מסוימת. לדוגמה:
- גודל מאגר הנתונים הזמני המבוקש הוא דינמי.
- לדרייבר יש מגבלות זיכרון שמונעות ממנו לטפל במאגרי נתונים גדולים.
יכול להיות שכמה תהליכים שונים יקראו מהמאגר שמנוהל על ידי מנהל ההתקן בו-זמנית. הגישה למאגר בו-זמנית לצורך כתיבה או קריאה/כתיבה לא מוגדרת, אבל היא לא יכולה לגרום לקריסת שירות מנהל ההתקן או לחסימת המתקשר ללא הגבלת זמן. יכול להיות שהדרייבר יחזיר שגיאה או ישאיר את התוכן של המאגר במצב לא מוגדר.