Systrace

Google 链接
Systrace是一个platform-provided工具,用于记录设备在短时间内的活动。 允许在系统级别上收集和检查设备上运行的所有进程的时间信息。将来自Android内核的数据(如CPU调度程序、磁盘活动和应用程序线程)结合起来生成一个HTML报告,帮助确定如何最好地提高应用程序或游戏的性能。该报告突出了它观察到的问题(如在显示动作或动画时的ui jank),并且提供了有关如何修复这些问题的建议。但是,Systrace不会在应用程序进程中收集有关代码执行的信息。有关应用正在执行的方法以及使用多少CPU资源的详细信息使用Android Studio CPU Profiler,你也可以生成trace logs后使用Profiler查看。
    三种使用方式:命令行调用,System Tracing APP,DDMS
    在Android5.0(API级别21)或更高版本的设备上,渲染一个frame的工作被UI Thread和Render Thread拆分。在以前的版本上,创建一个frame的所有工作都是在UI thread上完成的。
    在解决应用程序中与性能相关的错误(如启动缓慢、转换缓慢或UI jank)时,记录跟踪尤其有用。

  • 命令行调用
    Systrace command在android sdk tools包中提供,位于android-sdk/platform-tools/systrace/
    启动systrace,通过以下步骤:

    1. 下载安装Android Studio,然后下载SDK并更新。
      不一定要使用Android Studio,但是现在的SDK只能通过Android Studio更新。
    2. 安装python并将其包含在工作站的执行路径中。添加path D:\Python27,cmd 中输入python ,有信息
    3. python 2.7.9以后的自带pip,添加path D:\Python27\Scripts,cmd 中输入pip,有信息
    4. 通过USB调试连接到一个Android 4.3(API)或者 4.3以上的设备。
    5. 生成mynewtrace.html的文件; 当前目录: D:\adt\SDK\platform-tools\systrace
      python systrace.py -o mynewtrace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res
      
    6. 查看类别:其他命令查看链接
      python systrace.py --list-categories
      
      遇到缺少win32con, pip install -i https://pypi.douban.com/simple pypiwin32
      Systrace_第1张图片
      win32con

      Systrace_第2张图片
      需要启动模拟器或者连接设备
  • System Tracing APP
        在Android 9.0(API级别28)或更高版本的设备上,可以使用 System Tracing的 System App在设备上记录系统跟踪。系统跟踪将设备的活动保存到滚动缓冲区,该缓冲区可保存10-30秒的事件值。

    1. 开启开发者选项
    2. 打开开发者选项,选择System Tracing;开启Show Quick Setting tile的Switch Button。
    3. 或者,选择要跟踪的系统和传感器调用的类别,并选择缓冲区大小(以KB为单位)。选择与正在测试的用例相对应的类别,例如用于测试蓝牙操作的音频类别。
    4. 打开快速设置面板中的System Tracing 如下图System Tracing,或者打开开发者选项中的System Tracing并开启Record trace的Switch Button。
    5. 通知面板会出现一个System Tracing通知,点击通知面板或者快速设置面板中的System Tracing,停止tracing
    6. 系统将显示一个“saving trace”的新通知。保存完成后,系统将取消通知并显示第三个通知,System Tracing已保存,并且已准备好分享你的trace。
    7. 点击通知,显示分享对话框,点击share可以通过邮箱分享
    8. adb 命令下载,下载文件是.ctrace
      cd /path-to-traces-on-my-dev-machine
      adb pull /data/local/traces/ .
      
    9. 生成html文件;当前目录: D:\adt\SDK\platform-tools\systrace
      cd /path-to-traces-on-my-dev-machine
      python systrace.py --from-file trace-file-name.ctrace
      
    Systrace_第3张图片
    Developer Options

    Systrace_第4张图片
    Show Quick Setting tile

    Systrace_第5张图片
    System Tracing

    Systrace_第6张图片
    Trace saved

    Systrace_第7张图片
    Share Trace

    Systrace_第8张图片
    生成html文件
  • DDMS
    启动DDMS后,点击Capture system wide trace using Android systrace按钮后点击OK。
    Destination File: 生成文件存放哪里;
    Trace duration (seconds): 追踪周期时间
    Trace Buffer Size(kb): 追踪缓冲区大小
    Enable Application Traces from: 选择需要追踪的进程
    Commonly Used Tags: 常用标签     具体内容看图
    Advanced Options: 高级选项     具体内容看图

    Systrace_第9张图片
    Capture system wide trace using Android systrace

  • 报告分析

    1. 左边呈现是UI Frames的每个进程,选择你要观察的APP,右边是沿时间线指示呈现每个Frame。
      绿色圆表示: 16.6毫秒内渲染完成的Frames。
      黄色或红色圆表示: 渲染时间超过16.6毫秒的Frames。
    2. 单击一个frame 圆将高亮显示它,并提供系统渲染该frame所做的相关信息包括系统在呈现该帧时正在执行的方法(因此可以调查这些导致ui-jank的方法)和Alert。 Alert指出主要问题是在ListView回收和重新绑定中花费太多时间。Alert中有相关事件的链接,这些链接可以更详细地解释系统在这段时间内所做的工作。如图Android System Trace A Frame
    3. 若要查看每个Alert,以及触发每个Alert的次数,请单击窗口右侧的Alerts选项卡,如图Android System Trace Alert 所示。Alerts panel中查看跟踪出现的问题,以及它们对jank的影响频率。将Alerts panel视为要修复的错误列表。通常,一个领域的微小变化或改进可以消除应用中的整个Alerts。
    4. 如果UI Thread做了太多的工作,需要找出哪些方法占用了太多的CPU时间:
      为导致这些瓶颈的方法添加自定义事件,查看这些函数调用次数在Systrace中(具体操作下一段定义自定义事件)。
      如果不确定哪些方法会导致UI Thread出现瓶颈,请使用Android Studio Cpu Profiler,。
Systrace_第10张图片
Capture system wide trace using Android systrace

Systrace_第11张图片
Android System Trace

Systrace_第12张图片
Android System Trace Zoom

Systrace_第13张图片
Android System Trace A Frame

Systrace_第14张图片
Android System Trace Alert
  • 定义自定义事件
    1. 在Android 4.3(API级别18)及更高版本中,使用代码中的Trace类在HTML报告中标记执行事件。需要使用-a或--app命令行选项运行Systrace,并指定应用程序的包名称。

      python systrace.py -a com.lqr.wechat -b 16384 -o my_systrace_report.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res 
      

          下面的代码示例演示如何使用Trace类来标记方法的执行,包括该方法中的两个嵌套代码块;多次调用BeginAtomon(String)时,调用EndSection()只结束最近调用的BeginAtomon(String)方法。因此,对于嵌套调用(如下面示例中的调用),需要确保每个对BeginAtomion()的调用都与对EndSection()的调用正确匹配。此外,不能在一个线程上调用BeginAtomon()并从另一个线程结束它,必须从同一个线程调用EndSection()。

      public  class  MyAdapter  extends  RecyclerView.Adapter  {  
          ...
          @Override  
          public  MyViewHolder onCreateViewHolder(ViewGroup parent,  int viewType)  {  
              Trace.beginSection("MyAdapter.onCreateViewHolder");  
              MyViewHolder myViewHolder;  
              try  { 
                 myViewHolder =  MyViewHolder.newInstance(parent); 
              }  finally  {  
                  // In 'try...catch' statements, always call `[endSection()](https://developer.android.google.cn/reference/android/os/Trace.html#endSection())`  
                  // in a 'finally' block to ensure it is invoked even when an exception  // is thrown.  
                  Trace.endSection(); 
              }  
              return myViewHolder;  
          } 
      
          @Override  
          public  void onBindViewHolder(MyViewHolder holder,  int position)  { 
              Trace.beginSection("MyAdapter.onBindViewHolder");  
              try  {  
                  try  {  
                      Trace.beginSection("MyAdapter.queryDatabase");  
                      RowItem rowItem = queryDatabase(position); 
                      dataset.add(rowItem);  
                  }  finally  {  
                      Trace.endSection(); 
                  } 
                  holder.bind(dataset.get(position));
              }  finally  {  
                  Trace.endSection();  
              } 
          } 
          ... 
       }
      
    2. Android 6.0(API级别23)及更高版本支持调用native层tracing
      API 通过引入trace.h,将trace事件写入系统缓冲区,然后使用Systrace进行分析。Android 6.0到4.3可以尝试通过JNI调用。

      • 为ATrace functions定义方法指针
      #include 
      #include 
      
      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符号,通常在对象构造函数中执行这个过程,出于安全原因,仅在应用程序或游戏的调试版本中包含对dlopen()的调用。
      // 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(dlsym(lib, "ATrace_beginSection"));
          ATrace_endSEction = reinterpret_cast(dlsym(lib, "ATrace_endSection"));
      } 
      
      • 在自定义事件的开始和结束调用atrace_begindomon() 和atrace_endsection()
      #include 
      
      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_CALL()宏使这种类型的跟踪更容易设置。此外,通过创建try-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 
        
        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");
        }
        
Systrace_第15张图片
定义自定义事件
  • 源码性能调试
    待定

你可能感兴趣的:(Systrace)