Define custom events for Systrace

    The Android platform provides a tracing API which you can use to label aparticular section of code. If you capture a new system trace of the "debug"version of your app and include the option, as shown in the followingsnippet, these custom events appear in a Systrace report:

    Note: This approach is different from using the class, which helps you inspect detailedapp CPU usage by generating .trace files.

    This guide describes how to define custom events in both managed code and nativecode.

    In Android 4.3 (API level 18) and higher, you can use theTrace class in your code to define customevents that then appear in Systrace reports, as shown in the following codesnippet.

    Additionally, you cannot call beginSection() on one thread and end it from another thread; you must call both methods on the same thread.

    1. class MyAdapter : RecyclerView.Adapter<MyViewHolder>() {
    2. override fun onCreateViewHolder(parent: ViewGroup,
    3. viewType: Int): MyViewHolder {
    4. return try {
    5. Trace.beginSection("MyAdapter.onCreateViewHolder")
    6. MyViewHolder.newInstance(parent)
    7. } finally {
    8. // In try and catch statements, always call "endSection()" in a
    9. // "finally" block. That way, the method is invoked even when an
    10. // exception occurs.
    11. Trace.endSection()
    12. }
    13. }
    14.  
    15. override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
    16. Trace.beginSection("MyAdapter.onBindViewHolder")
    17. try {
    18. try {
    19. Trace.beginSection("MyAdapter.queryDatabase")
    20. val rowItem = queryDatabase(position)
    21. dataset.add(rowItem)
    22. } finally {
    23. Trace.endSection()
    24. }
    25. holder.bind(dataset[position])
    26. } finally {
    27. Trace.endSection()
    28. }
    29. }
    30. }
    1. public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    2. public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    3. Trace.beginSection("MyAdapter.onCreateViewHolder");
    4. MyViewHolder myViewHolder;
    5. try {
    6. myViewHolder = MyViewHolder.newInstance(parent);
    7. } finally {
    8. // In try and catch statements, always call "endSection()" in a
    9. // "finally" block. That way, the method is invoked even when an
    10. // exception occurs.
    11. Trace.endSection();
    12. }
    13. return myViewHolder;
    14. }
    15.  
    16. @Override
    17. public void onBindViewHolder(MyViewHolder holder, int position) {
    18. Trace.beginSection("MyAdapter.onBindViewHolder");
    19. try {
    20. try {
    21. Trace.beginSection("MyAdapter.queryDatabase");
    22. RowItem rowItem = queryDatabase(position);
    23. dataset.add(rowItem);
    24. } finally {
    25. Trace.endSection();
    26. }
    27. holder.bind(dataset.get(position));
    28. } finally {
    29. Trace.endSection();
    30. }
    31. }
    32. }

    Native code

    Android 6.0 (API level 23) and higher support a native tracing API, trace.h,to write trace events to the system buffer that you can then analyze usingSystrace. Common use cases for this API include observing the time that aparticular block of code takes to execute and associating a block of code withundesirable system behavior.

    To define custom events that occur in the native code within your app or game,complete the following steps:

    • Define function pointers for the ATrace functions that you use to capture custom events within your game, as shown in the following code snippet:
    • Load the ATrace symbols at runtime, as shown in the following code snippet. Usually, you perform this process in an object constructor.
    1. // Retrieve a handle to libandroid.
    2. void *lib = dlopen("libandroid.so", RTLD_NOW || RTLD_LOCAL);
    3.  
    4. // Access the native tracing functions.
    5. if (lib != NULL) {
    6. // (API level 22) or lower.
    7. ATrace_beginSection = reinterpret_cast<fp_ATrace_beginSection>(
    8. dlsym(lib, "ATrace_beginSection"));
    9. ATrace_endSEction = reinterpret_cast<fp_ATrace_endSection>(
    10. dlsym(lib, "ATrace_endSection"));
    11. }

    Caution: For security reasons, include calls to dlopen() only in the debug version of your app or game.

    • Call ATrace_beginSection() and ATrace_endSection() at the beginning and end, respectively, of your custom event:
    1. #include <android/trace.h>
    2.  
    3. char *customEventName = new char[32];
    4. sprintf(customEventName, "User tapped %s button", buttonName);
    5.  
    6. ATrace_beginSection(customEventName);
    7. // Your app or game's response to the button being pressed.
    8. ATrace_endSection();

    Note: When you call ATrace_beginSection() multiple times, calling ATrace_endSection() ends only the most recently called method. So, for nested calls, make sure that you properly match each call to ATrace_beginSection() with a call to ATrace_endSection().

    Additionally, you cannot call ATrace_beginSection() on one thread and end it from another. You must call both functions from the same thread.

    The following tips are optional but might make it easier to analyze your nativecode.

    Trace an entire function

    When instrumenting your call stack or function timing, you might find it usefulto trace entire functions. You can use the ATRACE_CALL() macro to make thistype of tracing easier to set up. Furthermore, such a macro allows you to skipcreating try and catch blocks for cases where the traced function mightthrow an exception or call return early.

    • Define the macro:
    • Call the macro within the function that you want to trace:
    1. void myExpensiveFunction() {
    2. ATRACE_CALL();
    3. // Code that you want to trace.
    4. }

    Name your threads

    You can give a name to each thread in which your events occur, as demonstratedin the following code snippet. This step makes it easier to identify the threadsthat belong to specific actions within your game.

    1. #include <pthread.h>
    2.  
    3. static void *render_scene(void *parm) {
    4. // Code for preparing your app or game's visual components.
    5. }
    6.  
    7. static void *load_main_menu(void *parm) {
    8. // Code that executes your app or game's main logic.
    9. }
    10.  
    11. void init_threads() {
    12. pthread_t render_thread, main_thread;
    13.  
    14. pthread_create(&render_thread, NULL, render_scene, NULL);
    15. pthread_create(&main_thread, NULL, load_main_menu, NULL);
    16.  
    17. pthread_setname_np(render_thread, "MyRenderer");
    18. }