במסמך הזה מוצגות שיטות מומלצות שנועדו לאבחן בעיות ולוודא הפרופילים הבסיסיים פועלים כראוי כדי לספק את התועלת הרבה ביותר.
בעיות ב-build
אם העתקתם את הדוגמה 'פרופילי הבסיס' בקטע עכשיו ב-Android אפליקציה לדוגמה, יכול להיות שתיתקלו בכשלים בבדיקה במהלך המשימה של פרופיל הבסיס שקובעת שלא ניתן להריץ את הבדיקות באמולטור:
./gradlew assembleDemoRelease
Starting a Gradle Daemon (subsequent builds will be faster)
Calculating task graph as no configuration cache is available for tasks: assembleDemoRelease
Type-safe project accessors is an incubating feature.
> Task :benchmarks:pixel6Api33DemoNonMinifiedReleaseAndroidTest
Starting 14 tests on pixel6Api33
com.google.samples.apps.nowinandroid.foryou.ScrollForYouFeedBenchmark > scrollFeedCompilationNone[pixel6Api33] FAILED
java.lang.AssertionError: ERRORS (not suppressed): EMULATOR
WARNINGS (suppressed):
...
הכשלים מתרחשים מכיוון ש'עכשיו ב-Android' משתמש במכשיר שמנוהל על ידי Gradle יצירת פרופיל בסיס. הכשלים צפויים, כי בדרך כלל לא להריץ נקודות השוואה לביצועים באמולטור. אבל מאחר שלא בזמן היצירה של פרופילי Baseline, אפשר לאסוף מדדי ביצועים אוסף פרופילים בסיסיים של אמולטורים כדי שיהיה נוח יותר. כדי להשתמש בערך הבסיס פרופילים עם אמולטור, מבצעים את ה-build וההתקנה מתוך בשורת הפקודה, ומגדירים ארגומנט כדי להפעיל את הכללים של פרופילים בסיסיים:
installDemoRelease -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
לחלופין, אפשר ליצור הגדרות הרצה בהתאמה אישית ב-Android Studio כדי כדי להפעיל פרופילים בסיסיים באמולטורים, בוחרים הפעלה > עורכים את ההגדרות האישיות:
בעיות בהתקנה
צריך לבדוק שה-APK או ה-AAB שיוצרים הם מהווריאנט של build שכולל
פרופילים בסיסיים. הדרך הקלה ביותר לבדוק זאת היא לפתוח את ה-APK
ב-Android Studio, בוחרים באפשרות Build > (פיתוח >) ניתוח APK, פתיחה של
APK, ומחפשים את הפרופיל ב-/assets/dexopt/baseline.prof
file:
צריך לבצע הידור של פרופילים בסיסיים במכשיר שבו פועלת האפליקציה. לשני הסוגים
התקנות של אפליקציות מחנות האפליקציות ואפליקציות שהותקנו באמצעות
PackageInstaller
, האיסוף במכשיר מתרחש כחלק מהאפליקציה
תהליך ההתקנה. אבל כשהאפליקציה מותקנת מ-Android Studio, או
באמצעות כלי שורת הפקודה, ספריית Jetpack ProfileInstaller
תהיה אחראית על הזמנת הפרופילים לתור לסידור במהלך
תהליך אופטימיזציה של DEX ברקע. במקרים כאלה, אם רוצים לוודא
נעשה שימוש בפרופילים של קבוצת הבסיס, לכן יכול להיות שתצטרכו
איסוף מאולץ של פרופילים בסיסיים. ProfileVerifier
מאפשר
שאילתה לגבי סטטוס התקנת הפרופיל והידור, כפי שמוצג
לדוגמה:
Kotlin
private const val TAG = "MainActivity" class MainActivity : ComponentActivity() { ... override fun onResume() { super.onResume() lifecycleScope.launch { logCompilationStatus() } } private suspend fun logCompilationStatus() { withContext(Dispatchers.IO) { val status = ProfileVerifier.getCompilationStatusAsync().await() when (status.profileInstallResultCode) { RESULT_CODE_NO_PROFILE -> Log.d(TAG, "ProfileInstaller: Baseline Profile not found") RESULT_CODE_COMPILED_WITH_PROFILE -> Log.d(TAG, "ProfileInstaller: Compiled with profile") RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING -> Log.d(TAG, "ProfileInstaller: App was installed through Play store") RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST -> Log.d(TAG, "ProfileInstaller: PackageName not found") RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ -> Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read") RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE -> Log.d(TAG, "ProfileInstaller: Can't write cache file") RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") else -> Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued") } } }
Java
public class MainActivity extends ComponentActivity { private static final String TAG = "MainActivity"; @Override protected void onResume() { super.onResume(); logCompilationStatus(); } private void logCompilationStatus() { ListeningExecutorService service = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor()); ListenableFuture<ProfileVerifier.CompilationStatus> future = ProfileVerifier.getCompilationStatusAsync(); Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(CompilationStatus result) { int resultCode = result.getProfileInstallResultCode(); if (resultCode == RESULT_CODE_NO_PROFILE) { Log.d(TAG, "ProfileInstaller: Baseline Profile not found"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE) { Log.d(TAG, "ProfileInstaller: Compiled with profile"); } else if (resultCode == RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING) { Log.d(TAG, "ProfileInstaller: App was installed through Play store"); } else if (resultCode == RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST) { Log.d(TAG, "ProfileInstaller: PackageName not found"); } else if (resultCode == RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ) { Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read"); } else if (resultCode == RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE) { Log.d(TAG, "ProfileInstaller: Can't write cache file"); } else if (resultCode == RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else { Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued"); } } @Override public void onFailure(Throwable t) { Log.d(TAG, "ProfileInstaller: Error getting installation status: " + t.getMessage()); } }, service); } }
קודי התוצאות הבאים מספקים רמזים לגבי הגורם לבעיות מסוימות:
RESULT_CODE_COMPILED_WITH_PROFILE
- הפרופיל מותקן, עובר הידור ונעשה בו שימוש בכל פעם שהאפליקציה רצה. הזה היא התוצאה שרוצים לראות.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
- לא נמצא פרופיל ב-APK או ב-AAB שפועלים. חשוב לוודא שאתם משתמשים לבנות וריאנט שכולל פרופילים בסיסיים אם מופיעה שגיאה זו, ה-APK מכיל פרופיל.
RESULT_CODE_NO_PROFILE
- לא הותקן פרופיל לאפליקציה הזו בזמן התקנת האפליקציה דרך האפליקציה
או מנהל החבילות. הסיבה העיקרית לקוד השגיאה הזה היא הפרופיל
מנהל ההתקנה לא פעל מכיוון ש-
ProfileInstallerInitializer
הושבת. שים לב: כאשר מדווח על שגיאה זו, פרופיל מוטמע עדיין נמצא APK של האפליקציה. כאשר פרופיל מוטמע לא נמצא, מוחזר קוד השגיאהRESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
. RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
- פרופיל נמצא ב-APK או ב-AAB ומצורף לתור לאיסוף. כאשר
הפרופיל מותקן על ידי
ProfileInstaller
, הוא נמצא בתור להידור בפעם הבאה שהמערכת תפעיל אופטימיזציה של DEX ברקע. הפרופיל אינו פעיל עד לסיום הידור. אל תנסו ליצור נקודת השוואה של ערך הבסיס הפרופילים עד להשלמת ההידור. יכול להיות שתצטרכו איסוף מאולץ של פרופילים בסיסיים. השגיאה לא תופיע כאשר האפליקציה מותקנת מחנות האפליקציות או ממנהל החבילות במכשירים שפועלים Android 9 (API 28) ואילך, כי ההידור במהלך ההתקנה. RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING
- הותקן פרופיל לא תואם והאפליקציה נוצרה באמצעותו.
הסיבה לכך היא ההתקנה דרך חנות Google Play או מנהל החבילות.
לתשומת ליבך, התוצאה הזו שונה מ-
RESULT_CODE_COMPILED_WITH_PROFILE
כי הפרופיל הלא תואם יכלול רק שיטות שעדיין משותפות בין הפרופיל לאפליקציה. הפרופיל קטן בפועל מ- צפוי, ופחות שיטות יעברו הידור (methods) מאלה שנכללו בקבוצת הבסיס פרופיל. RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
ProfileVerifier
לא יכול לכתוב את הקובץ במטמון של תוצאת האימות. מי יכול יכול להיות שמשהו השתבש בהרשאות לתיקיית האפליקציות או אין מספיק מקום פנוי בכונן.RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION
- ProfileVerifier
is running on an unsupported API version of Android. ProfileVerifier
תומך רק ב-Android 9 (רמת API 28) ואילך. RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST
- השגיאה
PackageManager.NameNotFoundException
תקועה במהלך השאילתהPackageManager
לחבילת האפליקציה. זה קורה לעיתים רחוקות. אני רוצה לנסות מסירים את האפליקציה ומתקינים את הכול מחדש. RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
- קיים קובץ קודם במטמון של תוצאת אימות, אבל לא ניתן לקרוא אותו. הזה אמור לקרות לעתים רחוקות. מנסים להסיר את האפליקציה ולהתקין אותה מחדש.
שימוש ב-ProfileVerifier בסביבת הייצור
בסביבת הייצור, אפשר להשתמש ב-ProfileVerifier
בשילוב עם
ספריות של ניתוח נתונים, כמו Google Analytics for Firebase, כדי
ליצור אירועי ניתוח נתונים שמציין את סטטוס הפרופיל. לדוגמה,
מתריעה במהירות אם תפורסם גרסה חדשה של האפליקציה שלא כוללת
פרופילים בסיסיים.
אילוץ הידור של פרופילים בסיסיים
אם סטטוס ההידור של פרופילי הבסיס הוא
RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
, אפשר לאלץ
compilation באמצעות adb
:
adb shell cmd package compile -r bg-dexopt PACKAGE_NAME
בדיקת מצב ההידור ללא ProfileVerifier
אם לא משתמשים ב-ProfileVerifier
, אפשר לבדוק את מצב ההידור באמצעות
adb
, למרות שהוא לא מספק תובנות מעמיקות כמו ProfileVerifier
:
adb shell dumpsys package dexopt | grep -A 2 PACKAGE_NAME
השימוש ב-adb
מניב משהו שדומה לזה:
[com.google.samples.apps.nowinandroid.demo]
path: /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/base.apk
arm64: [status=speed-profile] [reason=bg-dexopt] [primary-abi]
[location is /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/oat/arm64/base.odex]
ערך הסטטוס מציין את הסטטוס של הידור הפרופיל. הערכים הבאים:
סטטוס ההידור | משמעות |
---|---|
speed‑profile |
יש פרופיל שעבר הידור שנמצא בשימוש. |
verify |
לא קיים פרופיל שעבר הידור. |
סטטוס verify
לא אומר שה-APK או ה-AAB לא מכילים פרופיל,
כי הוא יכול להיות בתור הידור על ידי האופטימיזציה הבאה של DEX ברקע
למשימה הזו.
ערך הסיבה מציין מה גורם להידור של הפרופיל, אחד מהערכים הבאים:
סיבה | משמעות |
---|---|
install‑dm
|
פרופיל הבסיס נוצר באופן ידני או על ידי Google מפעילים את הסרטון כשהאפליקציה מותקנת. |
bg‑dexopt
|
הפרופיל נוצר בזמן שהמכשיר שלך לא היה פעיל. זה יכול להיות פרופיל בסיס או הפרופיל שנאסף בזמן השימוש באפליקציה. |
cmdline
|
האוסף הופעל באמצעות adb. זה יכול להיות פרופיל בסיס או הפרופיל שנאסף בזמן השימוש באפליקציה. |
בעיות שקשורות לביצועים
בקטע הזה מוצגות כמה שיטות מומלצות להגדרה נכונה של השוואה והשוואה לשוק. הפרופילים הבסיסיים שלך כדי להפיק מהם את המרב.
נקודת השוואה נכונה של מדדי הפעלה
פרופילי הבסיס שלך יהיו אפקטיביים יותר אם מדדי ההפעלה מוגדר היטב. שני מדדי המפתח הם זמן להצגה ראשונית (TTID) ו זמן להצגה מלאה (TTFD).
TTID הוא מצב שבו האפליקציה משרטטת את הפריים הראשון. חשוב להקפיד על כך שהסרטון יהיה קצר ככל האפשר, כי הצגת משהו מראה למשתמש שהאפליקציה פועלת. אפשר אפילו להציג אינדיקטור התקדמות קבוע כדי להראות שהאפליקציה רספונסיבית.
'דברים שאפשר לעשות' (TTFD) הם המקרים שבהם אפשר לבצע אינטראקציה בפועל עם האפליקציה. חשוב לשמור היא קצרה ככל האפשר כדי למנוע תסכול בקרב המשתמשים. אם סימנת נכון אתם רוצים לומר למערכת שהקוד שרץ בדרך ל-TTDFD הוא חלק מתהליך ההפעלה של האפליקציה. יש סבירות גבוהה יותר שהמערכת מציבה את הקוד הזה בפרופיל כתוצאה מכך.
חשוב להקפיד על רמה נמוכה ככל האפשר של 'TTDID' ושל 'דברים שאפשר לעשות' (TTD) כדי שהאפליקציה תהיה רספונסיבית.
המערכת יכולה לזהות את האובייקט 'TTDID', להציג אותו ב-Logcat ולדווח על כך כחלק
של נקודות השוואה לחברות סטארט-אפ. עם זאת, המערכת לא יכולה לקבוע את 'דברים שאפשר לעשות' (TTDFD)
באחריות האפליקציה לדווח כשהיא מגיעה לקטע אינטראקטיבי מפורט
. אפשר לעשות זאת בטלפון reportFullyDrawn()
, או
ReportDrawn
אם משתמשים ב-Jetpack פיתוח נייטיב. אם יש לך כמה
משימות ברקע שצריך לבצע לפני שהאפליקציה תיחשב במלואה
ואז אפשר להשתמש ב-FullyDrawnReporter
, כמו שמתואר במאמר שיפור
ודיוק בתזמון ההפעלה.
פרופילים של הספרייה ופרופילים בהתאמה אישית
כאשר משווים את ההשפעה של פרופילים, לפעמים קשה להפריד היתרונות של הפרופילים של האפליקציה מפרופילים שנתרמו על ידי ספריות, כמו ספריות של Jetpack. כשיוצרים את ה-APK, הפלאגין של Android Gradle מוסיף יחסי תלות של ספריות כמו גם בפרופיל המותאם אישית שלך. זה טוב לאופטימיזציה של הביצועים הכוללים, ומומלץ להשתמש בו בגרסאות ה-build של הגרסאות. עם זאת, קשה למדוד את העלייה בנפח הביצועים מהפרופיל המותאם אישית.
דרך מהירה לראות באופן ידני את האופטימיזציה הנוספת שסופקה על ידי הוא להסיר אותו ולהפעיל את נקודות ההשוואה. לאחר מכן צריך להחליף אותו ולהריץ את להתייחסות אליהם שוב. ההשוואה בין שתי הפלטפורמות תציג את האופטימיזציה שסופקה על ידי רק את הפרופילים בספרייה, ואת הפרופילים בספרייה וגם את הפרופיל המותאם אישית.
דרך אוטומטית להשוואה בין פרופילים היא ליצור וריאנט חדש של build,
מכיל רק את הפרופילים של הספרייה ולא את הפרופיל המותאם אישית שלך. השוואה
נקודות השוואה מהווריאנט הזה לווריאציית הגרסה שמכילה גם את
והפרופילים המותאמים אישית שלכם. הדוגמה הבאה ממחישה איך
כדי להגדיר את הווריאנט שכולל רק פרופילים של ספרייה. הוספת וריאציה חדשה
שנקרא releaseWithoutCustomProfile
למודול הצרכן של הפרופיל,
בדרך כלל מודול האפליקציה:
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile(project(":baselineprofile")) } baselineProfile { variants { create("release") { from(project(":baselineprofile")) } } }
מגניב
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile ':baselineprofile"' } baselineProfile { variants { release { from(project(":baselineprofile")) } } }
הקוד שבדוגמה הקודמת מסיר את התלות baselineProfile
מכל
ומחילה אותו באופן סלקטיבי רק על הווריאנט release
. זה עשוי להיראות
בניגוד הגיוני לכך שפרופילי הספרייה עדיין מתווספים כאשר
התלות במודול מפיק הפרופיל תוסר. אבל המודול הזה
אחראי רק ליצירת הפרופיל המותאם אישית שלך. Android Gradle
הפלאגין עדיין פועל לכל הווריאציות, והוא אחראי לכלול
של הספריות.
צריך גם להוסיף את הווריאנט החדש למודול של מחולל הפרופילים. כאן
לדוגמה, שם המודול של היצרן הוא :baselineprofile
.
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") {} ... } ... }
מגניב
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile {} ... } ... }
כשמריצים את ההשוואה לשוק מ-Android Studio, צריך לבחור
וריאנט אחד (releaseWithoutCustomProfile
) למדידת ביצועים בעזרת ספרייה בלבד
פרופילים, או לבחור וריאנט release
כדי למדוד ביצועים באמצעות הספרייה
ופרופילים מותאמים אישית.
נמנעים מהפעלה של אפליקציה שמחייבת קלט/פלט (I/O)
אם האפליקציה מבצעת הרבה קריאות קלט/פלט (I/O) או קריאות לרשתות במהלך ההפעלה, יכולה להיות לכך השפעה שלילית גם על זמן ההפעלה של האפליקציה וגם על רמת הדיוק של ההפעלה השוואה לשוק. השיחות הכבדות האלה עשויות להימשך זמן בלתי מוגדר שיכולות להשתנות עם הזמן ואפילו בין איטרציות של אותה נקודת השוואה. קלט/פלט (I/O) בדרך כלל שיחות טובות יותר משיחות רשת, כי השנייה יכולה מושפעים מגורמים חיצוניים למכשיר ולמכשיר עצמו. בלי שיחות רשת במהלך ההפעלה. כאשר השימוש באחד או יותר מהשניים הוא בלתי נמנע, יש להשתמש בקלט/פלט (I/O).
מומלץ להגדיר את ארכיטקטורת האפליקציה כך שתתמוך בהפעלה של האפליקציה ללא רשת או שיחות קלט/פלט (I/O), גם אם הן ישמשו רק בזמן ביצוע השוואה לשוק. כך נוכל לוודא את השונות הנמוכה ביותר האפשרית בין איטרציות שונות של נקודות ההשוואה.
אם באפליקציה שלך נעשה שימוש ב-Hilt, ניתן לספק קידוד קלט/פלט (I/O) מזויף הטמעות בעת ביצוע השוואה לשוק ב-Microbenchmark ו-Hilt.
כיסוי כל התהליכים החשובים שעוברים המשתמשים
חשוב לכסות באופן מדויק את כל התהליכים החשובים שעוברים המשתמשים בתהליך יצירת פרופיל בסיס. התהליכים שעוברים המשתמשים שלא נכללים השתפרו על ידי הפרופילים של קבוצת הבסיס. הפרופילים הבסיסיים האפקטיביים ביותר כוללים את כל התהליכים הנפוצים שעוברים משתמשים בזמן ההפעלה, וגם משתמשים באפליקציה שרגישים לביצועים מסלולים, כמו רשימות גלילה.