הזמנת קבצים

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

ניתן להוסיף לאפליקציה את התכונות של קובצי ההזמנות לפי השלבים הבאים שלבים:

  1. יצירת פרופילים וקובץ מיפוי
  2. יצירת קובץ הזמנה מהפרופילים ומקובץ המיפוי
  3. שימוש בקובץ ההזמנה במהלך גרסת ה-build של הגרסה כדי לפרוס את הסמלים

יצירת קובץ הזמנה

כדי ליצור קובץ הזמנה יש לבצע שלושה שלבים:

  1. יצירת גרסה של האפליקציה שכותבת את קובץ ההזמנה
  2. צריך להפעיל את האפליקציה כדי ליצור את הפרופילים
  3. עיבוד לאחר עיבוד של הפרופילים וקובץ המיפוי

יצירת build עם אינסטרומנטציה

הפרופילים נוצרים על ידי הרצת build של האפליקציה עם אינסטרומנטציה. בשביל build עם אינסטרומנטציה צריך להוסיף את -forder-file-instrumentation גם דגלים של מהדר ומקשר עם -mllvm -orderfile-write-mapping=<filename>-mapping.txt נוסף רק לדגלי המהדר. דגל האינסטרומנטציה מאפשר הגדרה של קובץ הזמנה לצורך פרופיילינג טוען את הספרייה הספציפית שנדרשת ליצירת פרופיל. מצד שני, דגל המיפוי פשוט מפיק את קובץ המיפוי שמציג את גיבוב MD5 לכל פונקציה בקובץ הבינארי או בספרייה.

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

ndk-build

צריך להקפיד לבנות באמצעות APP_OPTIM=release, לכן צריך לבצע אופטימיזציה ב-ndk-build מצב שאינו -O0. כשמפתחים באמצעות AGP, הפעולה הזו מתבצעת באופן אוטומטי לבנות.

LOCAL_CFLAGS += \
    -forder-file-instrumentation \
    -mllvm -orderfile-write-mapping=mapping.txt \

LOCAL_LDFLAGS += -forder-file-instrumentation

CMake

יש להקפיד להשתמש ב-CMAKE_BUILD_TYPE שאינו Debug, כדי ש-CMake ישתמש במצב אופטימיזציה שהוא לא -O0. כשיוצרים באמצעות AGP, הפעולה הזו מתבצעת באופן אוטומטי לגרסאות build של גרסאות.

target_compile_options(orderfiledemo PRIVATE
    -forder-file-instrumentation
    -mllvm -orderfile-write-mapping=mapping.txt
)
target_link_options(orderfiledemo PRIVATE -forder-file-instrumentation)

מערכות פיתוח אחרות

הידור הקוד באמצעות -forder-file-instrumentation -O1 -mllvm -orderfile-write-mapping=mapping.txt.

באופן ספציפי, לא חובה להשתמש ב--O1, אבל לא להשתמש ב--O0.

יש להשמיט -mllvm -orderfile-write-mapping=mapping.txt בזמן הקישור.

כל הדגלים האלה אינם נחוצים ל-build של גרסה, ולכן צריך לשלוט בו באמצעות משתנה build. כדי לשמור על פשטות, ניתן להגדיר את כל הפעולות האלו ב-CMakeLists.txt כמו דוגמה.

יצירה של ספריית קבצים להזמנה

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

  • התקשרות אל __llvm_profile_set_filename(PROFILE_DIR "/<filename>-%m.profraw") למשך הגדרה של נתיב הפרופיל. למרות שהארגומנט שהועבר הוא <filename>-%m.profraw, קובץ הפרופיל נשמר בשם <filename>-%m.profraw.order. צריך לוודא שהאפליקציה PROFILE_DIR יכולה לכתיבה ויש לכם גישה לספרייה.
    • מתבצע יצירת פרופיל של ספריות משותפות רבות, לכן %m מועיל מפני שהוא מתרחב לחתימת מודול ייחודית עבור הספרייה, וכתוצאה מכך פרופיל נפרד לכל ספרייה. לקבלת מידע נוסף על מצייןי תבניות, בקישור הזה.
  • מתקשרים אל __llvm_profile_initialize_file() כדי להגדיר את קובץ הפרופיל
  • אפשר להפעיל קריאה אל __llvm_orderfile_dump() כדי לכתוב במפורש בקובץ הפרופיל

הפרופילים נאספים בזיכרון ופונקציית ה-dump כותבת אותם חדש. עליך לוודא שפונקציית ה-Dump מופעלת בסוף ההפעלה כך שקובץ הפרופיל שלכם יכלול את כל הסמלים עד סיום ההפעלה.

extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_initialize_file(void);
extern int __llvm_orderfile_dump(void);
}

#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
  // ...
  // run workload
  // ...

  // set path and write profiles after workload execution
  __llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
  __llvm_profile_initialize_file();
  __llvm_orderfile_dump();
  return;
}

הרצת ה-Build for Profiles

מריצים את האפליקציה האינסטרומנטלית במכשיר פיזי או וירטואלי כדי ליצור פרופילים. אפשר לחלץ את קובצי הפרופיל באמצעות adb pull.

adb shell "run-as <package-name> sh -c 'cat /data/user/0/<package-name>/cache/default-%m.profraw.order' | cat > /data/local/tmp/default-%m.profraw.order"
adb pull /data/local/tmp/default-%m.profraw.order .

כפי שצוין קודם, עליכם לוודא שהתיקייה שמכילה את קובץ הפרופיל הכתוב ניתנים לגישה על-ידך. אם מדובר במכשיר וירטואלי, מומלץ להימנע מאמולטורים של חנות Play בגלל שאין גישה לתיקיות רבות.

עיבוד לאחר עיבוד של קובץ הפרופיל והמיפוי

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

Linux/Mac/ChromeOS

hexdump -C default-%m.profraw.order > default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt

Windows

certutil -f -encodeHex default-%m.profraw.order default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt

אם רוצים לקרוא עוד על הסקריפט, אפשר לעיין כאן README.

שימוש בקובץ ההזמנה ליצירת אפליקציה

אחרי יצירת קובץ הזמנה, צריך להסיר את הדגלים הקודמים ואת את הפונקציות של קובץ ההזמנה, כי הן מיועדות רק לשלבים של יצירה. צריך רק להעביר את -Wl,--symbol-ordering-file=<filename>.orderfile אל דגלים של הידור ומקשר. לפעמים סמלים לא נמצאים, או לא ניתן להעביר אותם, או עם אזהרות, יכול להעביר את -Wl,--no-warn-symbol-ordering כדי לעקוף את האזהרות האלה.

ndk-build

LOCAL_CFLAGS += \
    -Wl,--symbol-ordering-file=<filename>.orderfile \
    -Wl,--no-warn-symbol-ordering \

LOCAL_LDFLAGS += \
    -Wl,--symbol-ordering-file=<filename>.orderfile \
    -Wl,--no-warn-symbol-ordering \

CMake

target_compile_options(orderfiledemo PRIVATE
    -Wl,--symbol-ordering-file=<filename>.orderfile
    -Wl,--no-warn-symbol-ordering
)
target_link_options(orderfiledemo PRIVATE
    -Wl,--symbol-ordering-file=<filename>.orderfile
    -Wl,--no-warn-symbol-ordering
)

מערכות פיתוח אחרות

הידור הקוד באמצעות -Wl,--symbol-ordering-file=<filename>.orderfile -Wl,--no-warn-symbol-ordering.

למידע נוסף, ניתן לעיין בדוגמה לקובץ ההזמנה.

פרטי ההטמעה של קובץ ההזמנה

יש דרכים רבות ליצור קובצי הזמנות ולהשתמש בהם לצורכי בנייה. ה-NDK משתמש בשיטת LLVM כך שהיא השימושית ביותר עבור ה-C או C++ המשותף. באפליקציה עצמו של Java או Kotlin. Clang לוקח כל שם פונקציה (סמל) ויוצר גיבוב MD5 שלו מפיק את היחס הזה לקובץ מיפוי. גיבוב MD5 של פונקציה נכתב בקובץ הפרופיל (פורמט תקין) כאשר מופעלת בפעם הראשונה. הפעלות נוספות של הפונקציה לא כותבות את גיבוב ה-MD5 שלה כי הוא רוצה למנוע כפילויות. כתוצאה מכך, רק ההרצה הראשונה של הפונקציה מתועדת לפי הסדר. באמצעות מעבר על קובץ הפרופיל וקובץ המיפוי, אפשר לבצע כל גיבוב MD5 ומחליפים אותו בפונקציה המתאימה ומקבלים קובץ הזמנה.

דוגמאות לקובץ פרופיל בפורמט הקסדצימלי וגם לקובץ מיפוי יכולות להיות נמצא כ-example.prof ו-example-mapping.txt בהתאמה.