שימוש באופטימיזציה מודרכת הפרופיל

מערכת ה-build של Android ל-Android 13 ומטה תומכת בשימוש בהנחיות הפרופיל של Clang אופטימיזציה (PGO) במודולים מותאמים של Android שיש להם תוכנית build כללים. בדף הזה מוסבר על Clang PGO, איך ליצור ולעדכן באופן שוטף פרופילים שמשמשים ל-PGO ואיך לשלב את PGO עם מערכת ה-build (עם ).

NB: במסמך הזה מתואר השימוש ב-PGO בפלטפורמת Android. כדי ללמוד על השימוש PGO מאפליקציה ל-Android, צריך להיכנס לכתובת הדף הזה.

מידע על Clang PGO

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

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

צריך ליצור את כל הפרופילים מעומס עבודה מייצג מפעיל את ההתנהגות האופיינית של האפליקציה. אמנם Clang תומך בשני מבוסס AST (-fprofile-instr-generate) ו-LLVM IR (-fprofile-generate), מערכת Android תומכת רק במבוסס-LLVM IR עבור PGO שמבוסס על אינסטרומנטציה.

הדגלים הבאים נדרשים כדי ליצור את איסוף הפרופילים:

  • -fprofile-generate לאומנטציה מבוססת IR. עכשיו אפשר הקצה העורפי משתמש בגישה משוקללת של עצים פורשים להפחית את מספר נקודות האינסטרומנטציה ולבצע אופטימיזציה של המיקום שלהן קצוות בעלי משקל נמוך (יש להשתמש באפשרות הזו גם בשלב הקישור). קלאנג הנהג עובר באופן אוטומטי את זמן הריצה של הפרופיילינג (libclang_rt.profile-arch-android.a) לקישור. הספרייה הזו מכילה תרחישים לכתיבת הפרופילים לדיסק לאחר התכנות יציאה.
  • -gline-tables-only לאיסוף פרופילים שמבוססים על דגימה כדי ליצור מידע מינימלי על תוצאות ניפוי הבאגים.

אפשר להשתמש בפרופיל ל-PGO באמצעות -fprofile-use=pathname או -fprofile-sample-use=pathname למודלים שמבוססים על אינסטרומנטציה ופרופילים מבוססי דגימה, בהתאמה.

הערה: כשמתבצעים שינויים בקוד, אם Clang לא יכול היא משתמשת בנתוני הפרופיל שהיא יוצרת אזהרה -Wprofile-instr-out-of-date.

שימוש ב-PGO

השימוש ב-PGO כולל את השלבים הבאים:

  1. יצירת הספרייה/הפעלה באמצעות אינסטרומנטציה על ידי העברת -fprofile-generate למהדר ולמקשר.
  2. לאסוף פרופילים על ידי הרצת עומס עבודה מייצג בינארית עם אינסטרומנטציה.
  3. מבצעים עיבוד לאחר עיבוד הפרופילים באמצעות הכלי llvm-profdata (לפרטים נוספים, ראו טיפול ב-LLVM) קובצי פרופיל).
  4. השתמשו בפרופילים כדי להחיל PGO על ידי העברה -fprofile-use=<>.profdata למהדר מקשר.

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

איסוף פרופילים

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

  1. תזהו נקודת השוואה ואת קבוצת הספריות שמפעילות יחד המקובל בשוק.
  2. הוספת מאפייני pgo לנקודת ההשוואה ולספריות (פרטים) למטה).
  3. הפקת build של Android עם עותק מוגדר של ספריות אלה באמצעות:
    make ANDROID_PGO_INSTRUMENT=benchmark

benchmark הוא placeholder שמזהה את של אוסף ספריות שנוצרו במהלך ה-build. הנציג בפועל מקורות קלט (וכנראה גם קובץ הפעלה אחר שמקשר אל ספרייה שהיא (בנצ'מרק) אינן ספציפיות ל-PGO והן חורגות מההיקף של מהמסמך.

  1. הבהוב או סנכרן את ה-build עם האינסטרומנטציה במכשיר.
  2. מריצים את נקודת ההשוואה כדי לאסוף פרופילים.
  3. אפשר להשתמש בכלי llvm-profdata (כפי שמפורט בהמשך) כדי לאחר העיבוד של הפרופילים והכנתם לבדיקה לתוך המקור עץ.

שימוש בפרופילים במהלך ה-build

בדיקת הפרופילים ב-toolchain/pgo-profiles ב-Android עץ. השם צריך להיות תואם למה שצוין נכס משנה profile_file של הנכס pgo עבור בספרייה. מערכת ה-build מעבירה את קובץ הפרופיל ל-Clang באופן אוטומטי במהלך יצירת הספרייה. ANDROID_PGO_DISABLE_PROFILE_USE אפשר להגדיר את משתנה הסביבה ל-true כך להשבית באופן זמני את PGO ולמדוד את היתרונות שלו על הביצועים.

כדי לציין ספריות פרופיל נוספות ספציפיות למוצר, יש לצרף אותן אל את המשתנה PGO_ADDITIONAL_PROFILE_DIRECTORIES BoardConfig.mk. אם יצוינו נתיבים נוספים, הפרופילים הנתיבים האלה מבטלים את אלה שבשדה toolchain/pgo-profiles.

כשיוצרים תמונת גרסה באמצעות היעד dist כדי make, מערכת ה-build תכתוב את השמות של קובצי הפרופיל החסרים אל $DIST_DIR/pgo_profile_file_missing.txt. אפשר לבדוק את זה כדי לראות אילו קובצי פרופיל הושמטו בטעות משבית את PGO).

הפעלת PGO בקובצי Android.bp

כדי להפעיל PGO בקובצי Android.bp למודולים מקוריים, צריך פשוט לציין את המאפיין pgo. המאפיין הזה כולל נכסי משנה:

נכס תיאור
instrumentation יש להגדיר את הערך true עבור PGO באמצעות האינסטרומנטציה. ברירת המחדל היא false
sampling צריך להגדיר את הערך true עבור PGO באמצעות דגימה. ברירת המחדל היא false
benchmarks רשימת מחרוזות. המודול הזה מיועד ליצירת פרופיילינג אם יש נקודת השוואה כלשהי ברשימה מצוין ב-build של ANDROID_PGO_INSTRUMENT כאפשרות.
profile_file קובץ הפרופיל (ביחס ל-toolchain/pgo-profile) לשימוש עם PGO. על ידי ההוספה הזו, ה-build מציג אזהרה שהקובץ לא קיים קובץ אל $DIST_DIR/pgo_profile_file_missing.txt אלא אם מוגדר המאפיין enable_profile_use false או משתנה ה-build ANDROID_PGO_NO_PROFILE_USE מוגדר true.
enable_profile_use יש להגדיר לערך false אם לא ניתן להשתמש בפרופילים במהלך build. אפשר להשתמש בה במהלך אתחול כדי להפעיל איסוף פרופילים או להשבית באופן זמני את PGO. ברירת המחדל היא true.
cflags רשימה של דגלים נוספים לשימוש במהלך build עם אינסטרומנטציה.

דוגמה למודול עם PGO:

cc_library {
    name: "libexample",
    srcs: [
        "src1.cpp",
        "src2.cpp",
    ],
    static: [
        "libstatic1",
        "libstatic2",
    ],
    shared: [
        "libshared1",
    ]
    pgo: {
        instrumentation: true,
        benchmarks: [
            "benchmark1",
            "benchmark2",
        ],
        profile_file: "example.profdata",
    }
}

אם נקודות ההשוואה benchmark1 ו-benchmark2 פעילות מייצגת של ספריות libstatic1, libstatic2, או libshared1, pgo של הספריות האלה יכול גם לכלול את נקודות ההשוואה. מודול defaults ב-Android.bp יכול לכלול מפרט pgo לקבוצת ספריות כדי להימנע מחזרה על אותם כללי build למספר מודולים.

כדי לבחור קובצי פרופיל שונים או להשבית את PGO באופן סלקטיבי מציינים את profile_file, enable_profile_use ו-cflags נכסים לכל של הארכיטקטורה, דוגמה (עם יעד ארכיטקטורה ב- bold):

cc_library {
    name: "libexample",
    srcs: [
          "src1.cpp",
          "src2.cpp",
    ],
    static: [
          "libstatic1",
          "libstatic2",
    ],
    shared: [
          "libshared1",
    ],
    pgo: {
         instrumentation: true,
         benchmarks: [
              "benchmark1",
              "benchmark2",
         ],
    }

    target: {
         android_arm: {
              pgo: {
                   profile_file: "example_arm.profdata",
              }
         },
         android_arm64: {
              pgo: {
                   profile_file: "example_arm64.profdata",
              }
         }
    }
}

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

טיפול בקובצי פרופיל ב-LLVM

הפעלת ספרייה עם אינסטרומנטציה או קובץ הפעלה יוצרת קובץ פרופיל בשם default_unique_id_0.profraw ב- /data/local/tmp (כאשר unique_id הוא שהוא ייחודי לספרייה הזו). אם הקובץ הזה כבר קיים, זמן הריצה של הפרופיילינג ממזג את הפרופיל החדש עם הפרופיל הישן בזמן הכתיבה את הפרופילים. חשוב לדעת שאין גישה אל /data/local/tmp דרך האפליקציה מפתחים; כדאי להשתמש בהם במקום כמו /storage/emulated/0/Android/data/packagename/files במקום זאת. כדי לשנות את המיקום של קובץ הפרופיל, צריך להגדיר את LLVM_PROFILE_FILE במשתנה הסביבה בזמן הריצה.

llvm-profdata משמש לאחר מכן להמרת הקובץ .profraw (וייתכן מיזוג מספר קבצים של .profraw) אל .profdata file:

  llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>

לאחר מכן אפשר להיכנס למקור של profile.profdata עץ לשימוש במהלך ה-build.

אם במהלך נקודת השוואה נטענים כמה קבצים בינאריים/ספריות עם אינסטרומנטציה, כל ספרייה יוצרת קובץ .profraw נפרד עם מזהה ייחודי. בדרך כלל ניתן למזג את כל הקבצים האלה לקובץ אחד קובץ אחד (.profdata) שמשמש ל-build של PGO. במקרים שבהם הספרייה נמצא בשימוש בנצ'מרק אחר, יש לבצע אופטימיזציה של הספרייה הזו באמצעות מפרופילים של שתי נקודות השוואה. במצב כזה, show האפשרות llvm-profdata שימושית:

  llvm-profdata merge -output=default_unique_id.profdata default_unique_id_0.profraw
llvm-profdata show -all-functions default_unique_id.profdata

כדי למפות פרמטרים Unique_id לספריות ספציפיות, צריך לחפש את פלט show לכל Unique_id של שם פונקציה הוא ייחודי לספרייה.

מקרה לדוגמה: PGO for ART

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

המהדרבורד dex2oat מראש ב-ART תלוי libart-compiler.so, שבתורו תלוי libart.so. זמן הריצה של ART מיושם בעיקר ב libart.so נקודות ההשוואה של המהדר ושל זמן הריצה יהיו שונה:

Benchmark ספריות עם פרופיל
dex2oat dex2oat (קובץ להפעלה), libart-compiler.so, libart.so
art_runtime libart.so
  1. צריך להוסיף את מאפיין pgo הבא ל-dex2oat, libart-compiler.so:
        pgo: {
            instrumentation: true,
            benchmarks: ["dex2oat",],
            profile_file: "dex2oat.profdata",
        }
  2. צריך להוסיף את מאפיין pgo הבא ל-libart.so:
        pgo: {
            instrumentation: true,
            benchmarks: ["art_runtime", "dex2oat",],
            profile_file: "libart.profdata",
        }
  3. ליצור גרסאות build עם אינסטרומנטציה עבור dex2oat וגם art_runtime נקודות השוואה באמצעות:
        make ANDROID_PGO_INSTRUMENT=dex2oat
        make ANDROID_PGO_INSTRUMENT=art_runtime
  4. לחלופין, אפשר ליצור build עם מכשיר אחד עם כל הספריות בוצעה אינסטרומנטציה באמצעות:

        make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime
        (or)
        make ANDROID_PGO_INSTRUMENT=ALL

    הפקודה השנייה יוצרת את כל המודולים שתומכים ב-PGO עבור פרופיילינג.

  5. מריצים את נקודות ההשוואה בעת ביצוע תרגיל dex2oat ו art_runtime כדי לקבל:
    • שלושה קובצי .profraw מ-dex2oat (dex2oat_exe.profdata, dex2oat_libart-compiler.profdata, וגם dexeoat_libart.profdata), זוהה באמצעות השיטה שמתואר בטיפול בפרופיל LLVM קבצים.
    • art_runtime_libart.profdata יחיד.
  6. הפקת קובץ profdata נפוץ לקובץ הפעלה של dex2oat ול- libart-compiler.so באמצעות:
    llvm-profdata merge -output=dex2oat.profdata \
        dex2oat_exe.profdata dex2oat_libart-compiler.profdata
  7. כדי לקבל את הפרופיל של libart.so, צריך למזג את הפרופילים משתי נקודות השוואה:
    llvm-profdata merge -output=libart.profdata \
        dex2oat_libart.profdata art_runtime_libart.profdata

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

    llvm-profdata merge -output=libart.profdata \
        -weighted-input=2,dex2oat_libart.profdata \
        -weighted-input=1,art_runtime_libart.profdata

    הפקודה שלמעלה מקצה לפרופיל פי 2 משקל מ- dex2oat המשקל בפועל צריך להיקבע לפי הדומיין ידע או ניסויים.

  8. יש לבדוק את קובצי הפרופיל dex2oat.profdata ו libart.profdata אל toolchain/pgo-profiles למשך במהלך ה-build.