Android 6.0(API 级别 23)及更高版本支持原生跟踪 API,trace.h
,用于将跟踪事件写入系统缓冲区,然后您可以使用 Perfetto 或 systrace 分析这些事件。此 API 的常见用例包括观察特定代码块执行所需的时间,并将代码块与不良系统行为相关联。
注意:在运行 API 级别 27 及以下版本的设备和模拟器上,如果没有足够的可用内存或内存碎片太多,您将收到以下消息:Atrace 无法分配足够的内存来记录跟踪
。如果发生这种情况并且您的捕获没有完整的数据集,则应关闭后台进程或重新启动设备或模拟器。
要定义在应用或游戏中发生的原生代码中的自定义事件,请完成以下步骤
为用于在应用或游戏中捕获自定义事件的 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);
在运行时加载 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 调用前面代码片段中所示代码周围的托管代码中的方法。
分别在自定义事件的开头和结尾调用
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()
宏使此类跟踪更容易设置。此外,此类宏允许您跳过为跟踪函数可能抛出异常或提前调用return
的情况创建try
和catch
块。
要创建用于跟踪整个函数的宏,请完成以下步骤
定义宏
#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(); } };
在您要跟踪的函数内调用宏
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"); }
为您推荐
- 注意:当 JavaScript 关闭时,链接文本会显示。
- SQLite 性能最佳实践
- 在没有 Macrobenchmark 的情况下创建和测量基线配置文件