رویدادهای ردیابی سفارشی در کد بومی

Android 6.0 (سطح API 23) و بالاتر از API ردیابی بومی، trace.h پشتیبانی می کند تا رویدادهای ردیابی را در بافر سیستم بنویسد که سپس می توانید با استفاده از Perfetto یا systrace آن را تجزیه و تحلیل کنید. موارد استفاده رایج برای این API شامل مشاهده زمانی است که یک بلوک کد خاص برای اجرا طول می کشد و ارتباط یک بلوک کد با رفتار نامطلوب سیستم.

توجه: در دستگاه‌ها و شبیه‌سازهایی که API سطح 27 و پایین‌تر دارند، اگر حافظه کافی در دسترس نباشد یا حافظه بیش از حد تکه‌تکه باشد، پیام زیر را دریافت خواهید کرد: Atrace could not allocate enough memory to record a trace . اگر این اتفاق افتاد و ضبط شما مجموعه کاملی از داده ها را نداشت، باید فرآیندهای پس زمینه را ببندید یا دستگاه یا شبیه ساز را مجددا راه اندازی کنید.

برای تعریف رویدادهای سفارشی که در کد بومی در برنامه یا بازی شما رخ می دهد، مراحل زیر را کامل کنید:

  1. همانطور که در قطعه کد زیر نشان داده شده است، نشانگرهای تابع را برای توابع ATrace تعریف کنید که برای ثبت رویدادهای سفارشی در برنامه یا بازی خود استفاده می کنید:

    #include <android/trace.h>
    #include <dlfcn.h>
    
    void *(*ATrace_beginSection) (const char* sectionName);
    void *(*ATrace_endSection) (void);
    
    typedef void *(*fp_ATrace_beginSection) (const char* sectionName);
    typedef void *(*fp_ATrace_endSection) (void);
    
  2. همانطور که در قطعه کد زیر نشان داده شده است، نمادهای ATrace را در زمان اجرا بارگذاری کنید. معمولاً این فرآیند را در یک سازنده شی انجام می دهید.

    // Retrieve a handle to libandroid.
    void *lib = dlopen("libandroid.so", RTLD_NOW | RTLD_LOCAL);
    
    // Access the native tracing functions.
    if (lib != NULL) {
        // Use dlsym() to prevent crashes on devices running Android 5.1
        // (API level 22) or lower.
        ATrace_beginSection = reinterpret_cast<fp_ATrace_beginSection>(
            dlsym(lib, "ATrace_beginSection"));
        ATrace_endSection = reinterpret_cast<fp_ATrace_endSection>(
            dlsym(lib, "ATrace_endSection"));
    }
    

    احتیاط: به دلایل امنیتی، تماس‌های dlopen() را فقط در نسخه اشکال‌زدایی برنامه یا بازی خود وارد کنید.

    توجه: برای ارائه پشتیبانی ردیابی بیشتر به Android 4.3 (سطح API 18)، می‌توانید از JNI برای فراخوانی متدهای موجود در کد مدیریت شده در اطراف کد نشان داده شده در قطعه قبلی استفاده کنید.

  3. ATrace_beginSection() و ATrace_endSection() را به ترتیب در ابتدا و انتهای رویداد سفارشی خود فراخوانی کنید:

    #include <android/trace.h>
    
    char *customEventName = new char[32];
    sprintf(customEventName, "User tapped %s button", buttonName);
    
    ATrace_beginSection(customEventName);
    // Your app or game's response to the button being pressed.
    ATrace_endSection();
    

    توجه: هنگامی که ATrace_beginSection() چندین بار فراخوانی می کنید، فراخوانی ATrace_endSection() تنها به متد اخیر ATrace_beginSection() پایان می دهد. بنابراین، برای تماس‌های تودرتو، مطمئن شوید که هر تماس را با ATrace_beginSection() با فراخوانی به ATrace_endSection() مطابقت دهید.

    علاوه بر این، نمی‌توانید ATrace_beginSection() در یک رشته فراخوانی کنید و آن را از یک رشته دیگر پایان دهید. شما باید هر دو تابع را از یک رشته فراخوانی کنید.

نکات راحتی

نکات زیر اختیاری هستند، اما ممکن است تجزیه و تحلیل کد بومی شما را آسان‌تر کنند.

ردیابی کل یک تابع

هنگام تنظیم زمان بندی پشته تماس یا عملکرد، ممکن است ردیابی کل عملکردها مفید باشد. می‌توانید از ماکرو ATRACE_CALL() برای تنظیم آسان‌تر این نوع ردیابی استفاده کنید. علاوه بر این، چنین ماکرویی به شما امکان می‌دهد از ایجاد بلوک‌های try and catch برای مواردی که تابع ردیابی شده ممکن است استثنا ایجاد کند یا تماس زودهنگام return ، صرفنظر کنید.

برای ایجاد یک ماکرو برای ردیابی کل یک تابع، مراحل زیر را انجام دهید:

  1. ماکرو را تعریف کنید:

    #define ATRACE_NAME(name) ScopedTrace ___tracer(name)
    
    // ATRACE_CALL is an ATRACE_NAME that uses the current function name.
    #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
    
    class ScopedTrace {
      public:
        inline ScopedTrace(const char *name) {
          ATrace_beginSection(name);
        }
    
        inline ~ScopedTrace() {
          ATrace_endSection();
        }
    };
    
  2. ماکرو را در تابعی که می خواهید ردیابی کنید فراخوانی کنید:

    void myExpensiveFunction() {
      ATRACE_CALL();
      // Code that you want to trace.
    }
    

تاپیک های خود را نام ببرید

همانطور که در قطعه کد زیر نشان داده شده است، می توانید برای هر رشته ای که رویدادهای شما در آن اتفاق می افتد یک نام بدهید. این مرحله شناسایی رشته‌هایی را که به اقدامات خاصی در بازی شما تعلق دارند، آسان‌تر می‌کند.

#include <pthread.h>

static void *render_scene(void *parm) {
    // Code for preparing your app or game's visual components.
}

static void *load_main_menu(void *parm) {
    // Code that executes your app or game's main logic.
}

void init_threads() {
    pthread_t render_thread, main_thread;

    pthread_create(&render_thread, NULL, render_scene, NULL);
    pthread_create(&main_thread, NULL, load_main_menu, NULL);

    pthread_setname_np(render_thread, "MyRenderer");
    pthread_setname_np(main_thread, "MyMainMenu");
}
{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}