Systrace

作者: ArcherZang | 来源:发表于2019-05-14 16:01 被阅读0次

    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
        win32con
        需要启动模拟器或者连接设备
    • 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
        
      Developer Options
      Show Quick Setting tile
      System Tracing
      Trace saved
      Share Trace
      生成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: 高级选项     具体内容看图

      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,。
    Capture system wide trace using Android systrace
    Android System Trace
    Android System Trace Zoom
    Android System Trace A Frame
    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<MyViewHolder>  {  
            ...
            @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 <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符号,通常在对象构造函数中执行这个过程,出于安全原因,仅在应用程序或游戏的调试版本中包含对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<fp_ATrace_beginSection>(dlsym(lib, "ATrace_beginSection"));
            ATrace_endSEction = reinterpret_cast<fp_ATrace_endSection>(dlsym(lib, "ATrace_endSection"));
        } 
        
        • 在自定义事件的开始和结束调用atrace_begindomon() 和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_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 <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");
          }
          
    定义自定义事件

    相关文章

      网友评论

          本文标题:Systrace

          本文链接:https://www.haomeiwen.com/subject/sjtcaqtx.html