מומלץ מאוד להשתמש בספריית Jetpack Macrobenchmark כדי ליצור כללים לפרופיל באופן אוטומטי, וכך לצמצם את המאמץ הידני ולשפר את יכולת ההתאמה לשינויים. עם זאת, אפשר ליצור כללים לפרופילים ולמדוד אותם באפליקציה באופן ידני.
הגדרת כללי פרופיל באופן ידני
אפשר להגדיר כללי פרופיל באופן ידני באפליקציה או במודול של ספרייה על ידי יצירת קובץ בשם baseline-prof.txt
שנמצא בספרייה src/main
. זו אותה תיקייה שמכילה את הקובץ AndroidManifest.xml
.
בכל שורה בקובץ מצוין כלל אחד. כל כלל מייצג תבנית להתאמת שיטות או מחלקות באפליקציה או בספרייה שצריך לבצע בהן אופטימיזציה.
התחביר של הכללים האלה הוא קבוצת-על של הפורמט של פרופיל ART שקריא לבני אדם (HRF) כשמשתמשים ב-adb shell profman --dump-classes-and-methods
. התחביר דומה לתחביר של תיאורים וחתימות, אבל מאפשר להשתמש בתווים כלליים כדי לפשט את תהליך כתיבת הכללים.
בדוגמה הבאה אפשר לראות כמה כללים של פרופיל בסיסי שכלולים בספריית Jetpack Compose:
HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
Landroidx/compose/runtime/ComposerImpl;
אפשר לנסות לשנות את כללי הפרופיל בפרויקט הדוגמה הזה ב-Compiler Explorer. שימו לב: הכלי Compiler Explorer תומך רק בפורמט הפרופיל של ART שניתן לקריאה על ידי בני אדם (HRF), ולכן הוא לא תומך בתווים כלליים.
תחביר הכלל
הכללים האלה יכולים להיות באחת משתי צורות, לטירגוט של שיטות או של מחלקות:
[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]
כלל של מחלקה משתמש בתבנית הבאה:
[CLASS_DESCRIPTOR]
תיאור מפורט מופיע בטבלה הבאה:
תחביר | תיאור |
---|---|
FLAGS |
מייצג אחד או יותר מהתווים H , S ו-P כדי לציין אם צריך לסמן את השיטה הזו כ-Hot , Startup או Post Startup בהקשר של סוג ההפעלה. שיטה עם הדגל H מציינת שהיא שיטה 'חמה', כלומר היא נקראת הרבה פעמים במהלך חיי האפליקציה. שיטה עם הדגל S מציינת שהיא שיטה שנקראת במהלך ההפעלה. שיטה עם הדגל P מציינת שהיא שיטה שנקראת אחרי ההפעלה. אם מופיע בקובץ הזה שם של מחלקה, המשמעות היא שהמחלקה הזו נמצאת בשימוש במהלך ההפעלה, ולכן צריך להקצות לה מראש מקום ב-heap כדי להימנע מעלות של טעינת המחלקה. הקומפיילר של ART משתמש באסטרטגיות אופטימיזציה שונות, כמו קומפילציה של AOT של השיטות האלה וביצוע אופטימיזציות של פריסות בקובץ ה-AOT שנוצר. |
CLASS_DESCRIPTOR |
תיאור של המחלקה של השיטה המטורגטת. לדוגמה, ל-androidx.compose.runtime.SlotTable יש תיאור של Landroidx/compose/runtime/SlotTable; . האות L מופיעה כאן בתחילת המספר בהתאם לפורמט Dalvik Executable (DEX). |
METHOD_SIGNATURE |
חתימה של ה-method, כולל השם, סוגי הפרמטרים וסוגי הערכים שמוחזרים של ה-method. לדוגמה:// LayoutNode.kt fun isPlaced():Boolean { // ... } ב- LayoutNode יש חתימה isPlaced()Z . |
הדפוסים האלה יכולים לכלול תווים כלליים כדי שכלל אחד יכלול כמה שיטות או מחלקות. לקבלת עזרה מודרכת בכתיבה באמצעות תחביר כללים ב-Android Studio, אפשר לעיין בפלאגין Android Baseline Profiles.
דוגמה לכלל עם תו כללי:
HSPLandroidx/compose/ui/layout/**->**(**)**
סוגים נתמכים בכללים של פרופיל Baseline
כללי פרופיל הבסיס תומכים בסוגים הבאים. פרטים על הסוגים האלה מופיעים במאמר בנושא פורמט Dalvik Executable (DEX).
תו | סוג | תיאור |
---|---|---|
B |
בייט | בייט חתום |
C |
char | מיקום תו (code point) של Unicode בקידוד UTF-16 |
D |
double | ערך נקודה צפה (floating-point) בדיוק כפול |
F |
float | ערך נקודה צפה (floating-point) בדיוק יחיד |
I |
INT | מספר שלם |
J |
ארוך | מספר שלם ארוך |
S |
סרטון קצר | סרטון Shorts חתום |
V |
void | ביטול |
Z |
בוליאני | נכון או לא נכון |
L (שם הכיתה) |
reference | מופע של שם כיתה |
בנוסף, ספריות יכולות להגדיר כללים שארוזים בארטיפקטים של AAR. כשיוצרים קובץ APK שכולל את פריטי המידע האלה, הכללים משולבים יחד – בדומה לאופן שבו מתבצע מיזוג של קובץ המניפסט – והם עוברים קומפילציה לפרופיל ART בינארי קומפקטי שספציפי לקובץ ה-APK.
ART משתמש בפרופיל הזה כשמשתמשים ב-APK במכשירים כדי לבצע קומפילציה של קבוצת משנה ספציפית של האפליקציה בזמן ההתקנה ב-Android 9 (רמת API 28) או ב-Android 7 (רמת API 24) כשמשתמשים ב-ProfileInstaller
.
איסוף ידני של פרופילי Baseline
אפשר ליצור פרופיל בסיסי באופן ידני בלי להגדיר את ספריית המקרו-בנצ'מרק וליצור אוטומציות של ממשק המשתמש של תהליכי המשתמש הקריטיים. מומלץ להשתמש בבדיקות מאקרו, אבל לפעמים זה לא אפשרי. לדוגמה, אם אתם משתמשים במערכת build שאינה Gradle, לא תוכלו להשתמש בפלאגין Baseline Profile Gradle. במקרים כאלה, אפשר לאסוף ידנית כללים של פרופיל בסיסי. התהליך הזה הרבה יותר פשוט אם משתמשים במכשיר או באמולטור עם API בגרסה 34 ומעלה. אפשר לעשות את זה גם עם רמות API נמוכות יותר, אבל צריך גישת root וצריך להשתמש באמולטור שמריץ תמונת AOSP. אפשר לאסוף כללים ישירות על ידי ביצוע הפעולות הבאות:
- מתקינים גרסת הפצה של האפליקציה במכשיר בדיקה. סוג בניית האפליקציה לא יכול להיות R8-optimized ולא יכול להיות ניתן לניפוי באגים כדי ללכוד פרופיל שאפשר להשתמש בו במערכת הבנייה.
- משביתים את התקנת הפרופיל ומסיימים את פעולת האפליקציה.
אם ל-APK יש תלות בספריית Profile Installer של Jetpack, הספרייה מבצעת אתחול של פרופיל בהפעלה הראשונה של ה-APK. ההגדרה הזו עלולה להפריע לתהליך יצירת הפרופיל, ולכן צריך להשבית אותה באמצעות הפקודה הבאה:
adb shell am broadcast -a androidx.profileinstaller.action.SKIP_FILE WRITE_SKIP_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
איפוס של קומפילציית האפליקציה ומחיקה של כל הפרופילים.
API מגרסה 34 ואילך
adb shell cmd package compile -f -m verify $PACKAGE_NAME adb shell pm art clear-app-profiles $PACKAGE_NAME
API 33 ומטה
adb root adb shell cmd package compile --reset $PACKAGE_NAME
מריצים את האפליקציה ומנווטים באופן ידני בתהליכים שהמשתמשים עוברים שרוצים לאסוף לגביהם פרופיל.
ממתינים לפחות חמש שניות כדי שהפרופילים יתייצבו.
מבצעים את פעולת השמירה וממתינים עד שהשמירה תושלם. אם חבילת ה-APK שלך תלויה בספריית Jetpack Profile Installer, צריך להשתמש בה כדי ליצור dump של הפרופילים:
אם אתם לא משתמשים ב-Profile Installer, אתם יכולים להעביר את הפרופילים באופן ידני לאמולטור באמצעות הפקודה הבאה:adb shell am broadcast -a androidx.profileinstaller.action.SAVE_PROFILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver sleep 1 # wait 1 second adb shell am force-stop $PACKAGE_NAME
adb root adb shell killall -s SIGUSR1 $PACKAGE_NAME sleep 1 # wait 1 second adb shell am force-stop $PACKAGE_NAME
להמיר את הפרופילים הבינאריים שנוצרו לטקסט:
API מגרסה 34 ואילך
adb shell pm dump-profiles --dump-classes-and-methods $PACKAGE_NAME
API 33 ומטה
בודקים אם נוצר פרופיל הפניה או פרופיל נוכחי. פרופיל ההפניה נמצא במיקום הבא:
/data/misc/profiles/ref/$$PACKAGE_NAME/primary.prof
הפרופיל הנוכחי נמצא במיקום הבא:
/data/misc/profiles/cur/0/$PACKAGE_NAME/primary.prof
קובעים את המיקום של קובץ ה-APK:
adb root adb shell pm path $PACKAGE_NAME
ביצוע ההמרה:
adb root adb shell profman --dump-classes-and-methods --profile-file=$PROFILE_PATH --apk=$APK_PATH > /data/misc/profman/$PACKAGE_NAME-primary.prof.txt
כדי לאחזר את הפרופיל שנוצר מהמכשיר, משתמשים ב-
adb
:adb pull /data/misc/profman/$PACKAGE_NAME-primary.prof.txt PATH_TO_APP_MODULE/src/main/
הפעולה הזו תמשוך את כללי הפרופיל שנוצרו ותתקין אותם במודול האפליקציה. בפעם הבאה שתבנו את האפליקציה, פרופיל הבסיס ייכלל בה. כדי לוודא זאת, פועלים לפי השלבים שמפורטים במאמר בעיות בהתקנה.
מדידה ידנית של שיפורים באפליקציה
מומלץ מאוד למדוד את השיפורים באפליקציה באמצעות השוואה לשוק. עם זאת, אם אתם רוצים למדוד את השיפורים באופן ידני, אתם יכולים להתחיל במדידת הפעלת האפליקציה לפני האופטימיזציה כנקודת השוואה.
PACKAGE_NAME=com.example.app
# Force Stop App adb shell am force-stop $PACKAGE_NAME # Reset compiled state adb shell cmd package compile --reset $PACKAGE_NAME
# Measure App startup # This corresponds to `Time to initial display` metric. adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \ | grep "TotalTime"
בשלב הבא, מעלים צדדית את פרופיל ה-Baseline.
# Unzip the Release APK first. unzip release.apk
# Create a ZIP archive. # The name should match the name of the APK. # Copy `baseline.prof{m}` and rename it `primary.prof{m}`. cp assets/dexopt/baseline.prof primary.prof cp assets/dexopt/baseline.profm primary.profm
# Create an archive. zip -r release.dm primary.prof primary.profm
# Confirm that release.dm only contains the two profile files: unzip -l release.dm # Archive: release.dm # Length Date Time Name # --------- ---------- ----- ---- # 3885 1980-12-31 17:01 primary.prof # 1024 1980-12-31 17:01 primary.profm # --------- ------- # 2 files
# Install APK + Profile together. adb install-multiple release.apk release.dm
כדי לוודא שהחבילה עברה אופטימיזציה במהלך ההתקנה, מריצים את הפקודה הבאה:
# Check dexopt state.
adb shell dumpsys package dexopt | grep -A 1 $PACKAGE_NAME
הפלט צריך לציין שהחבילה עברה קומפילציה:
[com.example.app]
path: /data/app/~~YvNxUxuP2e5xA6EGtM5i9A==/com.example.app-zQ0tkJN8tDrEZXTlrDUSBg==/base.apk
arm64: [status=speed-profile] [reason=install-dm]
עכשיו אפשר למדוד את ביצועי ההפעלה של האפליקציה כמו קודם, אבל בלי לאפס את המצב המהודר. חשוב לוודא שלא מאפסים את המצב המהודר של החבילה.
# Force stop app adb shell am force-stop $PACKAGE_NAME
# Measure app startup adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \ | grep "TotalTime"
פרופילים בסיסיים ו-profgen
בקטע הזה מתואר מה עושה הכלי profgen כשיוצרים גרסה בינארית קומפקטית של פרופיל בסיסי.
Profgen-cli עוזר בהידור, בבדיקה ובטרנספילציה של פרופילים של ART, כך שאפשר להתקין אותם במכשירים מבוססי Android בלי קשר לגרסת ה-SDK של היעד.
profgen-cli הוא CLI שמקמפל את ה-HRF של פרופיל בסיסי לפורמט המקומפל שלו. ה-CLI מופץ גם במאגר cmdline-tools
כחלק מ-Android SDK.
התכונות האלה זמינות בענף studio-main
:
➜ ../cmdline-tools/latest/bin
apkanalyzer
avdmanager
lint
profgen
retrace
screenshot2
sdkmanager
יצירת פרופילים בינאריים קומפקטיים באמצעות Profgen-cli
הפקודות שזמינות ב-Profgen-cli הן bin
, validate
ו-dumpProfile
. כדי לראות את הפקודות הזמינות, משתמשים ב-profgen --help
:
➜ profgen --help
Usage: profgen options_list
Subcommands:
bin - Generate Binary Profile
validate - Validate Profile
dumpProfile - Dump a binary profile to a HRF
Options:
--help, -h -> Usage info
משתמשים בפקודה bin
כדי ליצור את הפרופיל הבינארי הקומפקטי. הנה קריאה לדוגמה:
profgen bin ./baseline-prof.txt \
--apk ./release.apk \
--map ./obfuscation-map.txt \
--profile-format v0_1_0_p \
--output ./baseline.prof \
כדי לראות את האפשרויות הזמינות, אפשר להשתמש ב-profgen bin options_list
:
Usage: profgen bin options_list
Arguments:
profile -> File path to Human Readable profile { String }
Options:
--apk, -a -> File path to apk (always required) { String }
--output, -o -> File path to generated binary profile (always required)
--map, -m -> File path to name obfuscation map { String }
--output-meta, -om -> File path to generated metadata output { String }
--profile-format, -pf [V0_1_0_P] -> The ART profile format version
{ Value should be one of [
v0_1_5_s, v0_1_0_p, v0_0_9_omr1, v0_0_5_o, v0_0_1_n
]
}
--help, -h -> Usage info
הארגומנט הראשון מייצג את הנתיב אל baseline-prof.txt
HRF.
בנוסף, צריך לציין ב-Profgen-cli את הנתיב אל גרסת ה-APK של האפליקציה ואת מיפוי הטשטוש שמשמש לטשטוש ה-APK כשמשתמשים ב-R8 או ב-Proguard. כך, profgen
יכול לתרגם סמלי מקור ב-HRF לשמות המוסווים התואמים שלהם כשיוצרים את הפרופיל המהודר.
מכיוון שפורמטים של פרופילים ב-ART לא תואמים קדימה או אחורה, צריך לספק פורמט של פרופיל כדי ש-profgen
יארוז מטא-נתונים של פרופיל (profm
) שאפשר להשתמש בהם כדי לבצע טרנסקוד של פורמט פרופיל אחד ב-ART לפורמט אחר כשנדרש.
פורמטים של פרופילים וגרסאות של פלטפורמות
אלו האפשרויות שזמינות כשבוחרים פורמט פרופיל:
פורמט הפרופיל | גירסת פלטפורמה | רמת ממשק API: |
---|---|---|
v0_1_5_s | Android S+ | 31+ |
v0_1_0_p | Android P, Q ו-R | 28-30 |
v0_0_9_omr1 | Android O MR1 | 27 |
v0_0_5_o | Android O | 26 |
v0_0_1_n | Android N | 24-25 |
מעתיקים את קובצי הפלט baseline.prof
ו-baseline.profm
לתיקייה assets
או dexopt
בקובץ ה-APK.
מפות טשטוש
צריך לספק את מפת הטשטוש רק אם קובץ ה-HRF משתמש בסמלי מקור. אם קובץ ה-HRF נוצר מגרסת build של אפליקציה שכבר עברה טשטוש ולא נדרש מיפוי, אפשר להתעלם מהאפשרות הזו ולהעתיק את הפלט לתיקייה assets
או dexopt
.
התקנה מסורתית של פרופילי Baseline
באופן מסורתי, פרופילים בסיסיים מועברים למכשיר באחת משתי דרכים.
שימוש ב-install-multiple
עם DexMetadata
במכשירים שמופעלת בהם גרסה 28 של API ואילך, לקוח Play מוריד את מטען ה-APK ואת מטען ה-DexMetadata (DM) עבור גרסת APK שמותקנת. ה-DM מכיל את פרטי הפרופיל שמועברים אל Package Manager במכשיר.
קובצי ה-APK וה-DM מותקנים כחלק מסשן התקנה יחיד באמצעות פקודה כמו:
adb install-multiple base.apk base.dm
Jetpack ProfileInstaller
במכשירים עם רמת API 29 ואילך, ספריית Jetpack
ProfileInstaller מספקת מנגנון חלופי להתקנה של פרופיל שנארז ב-assets
או ב-dexopt
אחרי התקנת ה-APK במכשיר. ProfileInstaller
מופעל על ידי ProfileInstallReceiver
או ישירות על ידי האפליקציה.
הספרייה ProfileInstaller מבצעת טרנסקוד של הפרופיל על סמך גרסת ה-SDK של מכשיר היעד, ומעתיקה את הפרופיל לספרייה cur
במכשיר (ספריית הכנה ספציפית לחבילה עבור פרופילי ART במכשיר).
אחרי שהמכשיר לא פעיל, הפרופיל נאסף על ידי תהליך שנקרא bg-dexopt
במכשיר.
העברה צדדית של פרופיל Baseline
בקטע הזה מוסבר איך להתקין פרופיל בסיסי באמצעות קובץ APK.
שידור תוכן מאפליקציית androidx.profileinstaller
במכשירים עם API מגרסה 24 ואילך, אפשר לשדר פקודה להתקנת הפרופיל:
# Broadcast the install profile command - moves binary profile from assets
# to a location where ART uses it for the next compile.
# When successful, the following command prints "1":
adb shell am broadcast \
-a androidx.profileinstaller.action.INSTALL_PROFILE \
<pkg>/androidx.profileinstaller.ProfileInstallReceiver
# Kill the process
am force-stop <pkg>
# Compile the package based on profile
adb shell cmd package compile -f -m speed-profile <pkg>
ProfileInstaller לא מופיע ברוב קובצי ה-APK עם פרופילים בסיסיים – כלומר בכ-77,000 מתוך 450,000 אפליקציות ב-Play – אבל הוא מופיע כמעט בכל קובץ APK שמשתמש ב-Compose. הסיבה לכך היא שספריות יכולות לספק פרופילים בלי להצהיר על תלות ב-ProfileInstaller. הוספת תלות בכל ספרייה עם פרופיל חלה החל מ-Jetpack.
שימוש ב-install-multiple
עם profgen או DexMetaData
במכשירים עם API בגרסה 28 ומעלה, אפשר להעביר Baseline Profile (פרופיל בסיסי) לטעינה צדדית בלי להשתמש בספריית ProfileInstaller באפליקציה.
כדי לעשות זאת, משתמשים ב-Profgen-cli:
profgen extractProfile \
--apk app-release.apk \
--output-dex-metadata app-release.dm \
--profile-format V0_1_5_S # Select based on device and the preceding table.
# Install APK and the profile together
adb install-multiple appname-release.apk appname-release.dm
כדי לתמוך בפיצולים של קובצי APK, מריצים את השלבים הקודמים של חילוץ הפרופיל פעם אחת לכל קובץ APK. בזמן ההתקנה, מעבירים כל APK וקובץ .dm
משויך, ומוודאים שהשמות של ה-APK ושל .dm
זהים:
adb install-multiple appname-base.apk appname-base.dm \
appname-split1.apk appname-split1.dm
אימות
כדי לוודא שהפרופיל הותקן בצורה נכונה, אפשר להשתמש בשלבים שמפורטים במאמר בנושא מדידה ידנית של שיפורים באפליקציה.
העברה של תוכן מפרופיל בינארי
כדי לבדוק את התוכן של גרסה בינארית קומפקטית של פרופיל בסיסי, משתמשים באפשרות dumpProfile
של Profgen-cli:
Usage: profgen dumpProfile options_list
Options:
--profile, -p -> File path to the binary profile (always required)
--apk, -a -> File path to apk (always required) { String }
--map, -m -> File path to name obfuscation map { String }
--strict, -s [true] -> Strict mode
--output, -o -> File path for the HRF (always required) { String }
--help, -h -> Usage info
dumpProfile
צריך את קובץ ה-APK כי הייצוג הבינארי הקומפקטי מאחסן רק היסטים של DEX, ולכן הוא צריך אותם כדי לשחזר את שמות המחלקות והשיטות.
מצב קפדני מופעל כברירת מחדל, ובמצב הזה מתבצעת בדיקת תאימות של הפרופיל לקובצי ה-DEX ב-APK. אם אתם מנסים לנפות באגים בפרופילים שנוצרו על ידי כלי אחר, יכול להיות שתקבלו הודעות על כשלים בתאימות שימנעו מכם לבצע dump לצורך בדיקה. במקרים כאלה, אפשר להשבית את המצב הקפדני באמצעות --strict false
. עם זאת, ברוב המקרים מומלץ להשאיר את המצב הקפדני מופעל.
מפת טשטוש היא אופציונלית. אם מספקים אותה, היא עוזרת למפות מחדש סמלים שעברו טשטוש לגרסאות קריאות שלהם, כדי להקל על השימוש.
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- שיטות מומלצות לשיפור הביצועים של SQLite
- פרופילים של Baseline {:#baseline-profiles}
- חסימות חלקיות ממושכות של מצב שינה