אחזור והעלאה של פרופילים

לא משנה אם אתם יוצרים פרופיל מבוסס-אפליקציה או פרופיל מבוסס-טריגר, ProfilingManager שומר את הקובץ המלא במכשיר ושולח ProfilingResult לקריאה החוזרת (callback) הרשומה שלכם. מפעילים את ProfilingResult.getResultFilePath כדי לקבל את הנתיב של הפרופיל השמור:

אחזור פרופילים ממכשיר

בקטע הזה מוסבר איפה ProfilingManager שומר פרופילים במכשיר, איך פועל ניקוי הקבצים האוטומטי ואיך לשלוף קבצים באופן מקומי באמצעות adb.

מיקומי קבצים ופורמטים של שמות

‫ProfilingManager שומר פרופילים מצונזרים בספריית האחסון הספציפית לאפליקציה ב-/data/user/0/<app>/files/profiling/. הפורמט של שם הקובץ תלוי באופן שבו הפרופיל נלכד:

  • פרופילים מבוססי-אפליקציה:

    profile_<tag>_<datetime>_uid-<uid>.<profile-type-ext>
    

    אם לא צוין תג בבקשה לפרופיל, <tag>_ מושמט: profile_<datetime>_uid-<uid>.<profile-type-ext>.

  • פרופילים שמבוססים על טריגרים:

    profile_trigger-type-<trigger_type>_<datetime>_uid-<uid>.<profile-type-ext>
    

כאשר:

  • ‫<app> הוא שם החבילה של האפליקציה.
  • ‫<tag> הוא עד 20 התווים האלפאנומריים הראשונים (ומקפים) של התג שסופק על ידי המתקשר, שהוגדר באמצעות setTag או הועבר אל requestProfiling, הומר לאותיות קטנות, וכל התווים מחוץ ל-a-z, ל-0-9 ול-- הוסרו.
  • ‫<trigger_type> הוא קוד קבוע של מספר שלם לטריגר מ-ProfilingTrigger. תמיד צריך להפעיל את ProfilingResult.getTriggerType בקוד במקום לנתח את שם הקובץ.
  • ‫<datetime> הוא התאריך והשעה שבהם הפרופיל תועד (yyyy-MM-dd-HH-mm-ss-SSS).
  • ‫<uid> הוא מזהה המשתמש של האפליקציה ב-Linux (כלול בגרסאות האחרונות של המודול Profiling).
  • ‫<profile-type-ext> היא סיומת הקובץ של סוג הפרופיל שנוצר:
    • .perfetto-trace לעקבות המערכת
    • ‫.perfetto-java-heap-dump לתמונות מצב של הזיכרון מ-Java
    • ‫.perfetto-heap-profile לתמונות מצב של ערימה
    • ‫.perfetto-stack-sample לפרופילים של דגימת מחסנית

אחסון וניקוי במכשיר

כדי לפנות נפח האחסון במכשיר באופן מיידי, מחקו כל קובץ פרופיל ב-worker של ההעלאה מיד אחרי שההעלאה מסתיימת (כי הניקוי האוטומטי פועל רק כש-ProfilingManager מעביר תוצאות לאפליקציה, וקבצים שלא הועלו יכולים להישאר בדיסק אם האפליקציה מפסיקה לרשום קריאות חוזרות אחרי סיום הקמפיין). כגיבוי בגרסאות האחרונות של מודול Profiling, ‏ProfilingManager גם מוחק באופן אוטומטי קבצים שנמסרו בספריית האחסון הספציפית לאפליקציה, אם הם ישנים יותר מ-5 ימים, כשנמסרות תוצאות חדשות.

העלאת פרופילים בסביבת הייצור באמצעות WorkManager

מכיוון שגודל הקבצים של הפרופילים יכול להיות כמה מגה-בייט, כדאי לתזמן את ההעלאות של גרסת הייצור ברקע כשהמכשיר מחובר לרשת ללא הגבלת נפח (Wi-Fi), נטען ולא בשימוש.

לפני ההעלאה, דוחסים את קובץ הפרופיל (לדוגמה, באמצעות GZIPOutputStream או ZipOutputStream). פרופילי Perfetto protobuf ותמונות מצב של הזיכרון ב-Java נדחסים באופן משמעותי, וכך מפחיתים את רוחב הפס של הרשת ואת עלויות האחסון בקצה העורפי.

הוספת יחסי תלות של WorkManager

‫ProfilingManager לא תלוי בענן, כך שאפשר לתזמן את העלאת הפרופילים לכל בקאנד באמצעות WorkManager. מוסיפים את הספרייה WorkManager לקובץ build.gradle.kts:

Kotlin

   dependencies {
       implementation("androidx.work:work-runtime:2.12.0")
   }
   

מגניב

   dependencies {
       implementation 'androidx.work:work-runtime:2.12.0'
   }
   

תזמון של משימת העלאה

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

Kotlin

class TraceUploadWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {
        // Perform your uploading work here
        Log.d("ProfileTest", "Uploading trace: " + inputData.getString("PROFILE_PATH"))

        return Result.success()
    }
}

fun setupProfileUploadWorker(profileFilepath: String?) {
    val workMgr = WorkManager.getInstance(applicationContext)
    val workRequestBuilder = OneTimeWorkRequest.Builder(TraceUploadWorker::class)

    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.UNMETERED)
        .setRequiresDeviceIdle(true)
        .setRequiresCharging(true)
        .build()
    workRequestBuilder.setConstraints(constraints)

    val inputDataBuilder = Data.Builder()
    inputDataBuilder.putString("PROFILE_PATH", profileFilepath)
    workRequestBuilder.setInputData(inputDataBuilder.build())

    workMgr.enqueue(workRequestBuilder.build())
}

Java

public static class TraceUploadWorker extends Worker {

  public TraceUploadWorker(
      @androidx.annotation.NonNull Context context,
      @androidx.annotation.NonNull WorkerParameters workerParams) {
    super(context, workerParams);
  }

  @androidx.annotation.NonNull
  @Override
  public Result doWork() {
    // Perform your uploading work here
    Log.d("ProfileTest", "Uploading trace: " + getInputData().getString("PROFILE_PATH"));

    return Result.success();
  }
}

public void setupProfileUploadWorker(String profileFilepath) {
  WorkManager workMgr = WorkManager.getInstance(getApplicationContext());
  OneTimeWorkRequest.Builder workRequestBuilder = new OneTimeWorkRequest.Builder(
      TraceUploadWorker.class);

  Constraints constraints = new Constraints.Builder()
      .setRequiredNetworkType(NetworkType.UNMETERED)
      .setRequiresDeviceIdle(true)
      .setRequiresCharging(true)
      .build();
  workRequestBuilder.setConstraints(constraints);

  Data.Builder inputDataBuilder = new Data.Builder();
  inputDataBuilder.putString("PROFILE_PATH", profileFilepath);
  workRequestBuilder.setInputData(inputDataBuilder.build());

  workMgr.enqueue(workRequestBuilder.build());
}

הדרכה מפורטת על הקוד

בדוגמה שלמעלה מתבצעים השלבים הבאים:

  • הגדרת ה-worker: יוצרים מחלקה של TraceUploadWorker שמרחיבה את Worker. מטמיעים את doWork כדי לוודא שקובץ הפרופיל עדיין קיים, דוחסים ומעלים אותו באמצעות ה-SDK לקצה העורפי או צד הלקוח ב-HTTP, ומוחקים את הקובץ המקומי אחרי שההעלאה מסתיימת.
  • תזמון העבודה:
    • יוצרים OneTimeWorkRequest לעובד.
    • הגדרת אילוצים: משתמשים ב-setRequiredNetworkType(NetworkType.UNMETERED), ב-setRequiresDeviceIdle(true) וב-setRequiresCharging(true) כדי שההעלאה תפעל רק כשהמכשיר מחובר ל-Wi-Fi, נטען ולא בשימוש.
    • העברת נתונים: משתמשים ב-setInputData כדי להעביר את נתיב הפרופיל מ-getResultFilePath ל-worker.
    • ‫Enqueue: שליחת הבקשה אל WorkManager באמצעות קריאה ל-WorkManager.enqueue.

השלבים הבאים

אחרי שאחזרתם או העליתם פרופילים, אתם יכולים להציג אותם בממשק המשתמש של Perfetto, להריץ שאילתות על פרופילים ספציפיים באמצעות PerfettoSQL, לנתח עקבות בכמות גדולה או לנתח פרופילים באמצעות AI. במאמר פריסת Bigtrace ב-Kubernetes מוסבר איך להגדיר צינור עיבוד נתונים לניתוח בצד השרת, שניתן להתאים לעומס.