systrace使用方式

前文有分析使用linux下的trace Linux trace使用入门 ,这里再次记录下android系统中比较实用的性能分析工具 systrace

撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/48373319本文来自 【jscese】的博客!


前提

systrace由kernel中的ftrace支持,kernel中的trace 配置开关编译,网上一搜很多,就不记录了


systrace使用方式

网上有 这篇文章里面有记录使用方法,但是实际上很多在windows下的人安装了python环境之后依然报错,有人说就是不支持~
我这里记录一下eclipse上的使用


eclipse环境下使用

相对前面在windows搭建python运行环境,google把sdk中的systrace模块功能集成到IDE里面,可以在安装好adt以及配置好sdk的eclipse中使用systrace功能,更加方便。


注意事项

sdk中的platfom tool version要在18以上,保持纯净的sdk 以及adt环境,如果修改替换了其中的某些tool,有可能导致最终抓取结果trace.xml 无法正常打开。

像前文python描述,systrace依赖kernel中的trace机制,还需额外对挂载的文件系统做权限修改,连接adb,如下:

<code class="hljs livecodeserver has-numbering">  adb <span class="hljs-built_in">shell</span> chmod <span class="hljs-number">777</span> /sys/kernel/debug
  adb <span class="hljs-built_in">shell</span> stop
  adb <span class="hljs-built_in">shell</span> start</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>

使用

切换到eclipse的DDMS:

这里写图片描述

adb连接小机,开机adb root,adb连接正常的情况如下图显示样机信息及进程

这里写图片描述

点击红色标注按钮,选取关注的项目,结果存放路径,抓取时间以及buffer大小,默认为5s

这里写图片描述

只关注显示情况的话 ,只选取Graphics就可以,点击OK,操作样机,时间结束,保存xml文件

结果分析查看

使用google chrome 浏览器打开xml文件,情形如下:
这里写图片描述
左边区域为对应的进程以及线程,右边为时序图,依次对应,可使用 鼠标+键盘 缩放定位想查看的区域


详细的操作点击右上的? 可查看:
这里写图片描述


如上trace数据为显示Graphics时抓取到的,为surfaceflinger 合成的时序操作
缩放查看其中的一段数据如下:
这里写图片描述
可以看到最上面的为VSYNC信号的变化时序,间隔16ms左右,按照60HZ的频率刷新,一次即为16+ms
从上图还可以看到一次surfaceflinger的合成操作 时间占用大概为3.5+ms 左右,相对整个一帧16+ms的时间来说,性能足够。


此图为视频播放时,播放器与surfaceflinger的buffer交互,图中每次合成前都有新的buffer数据丢到surfaceflinger这边,满足有新的buffer数据 + VSYNC信号的切换 才会去触发合成:
图中每次合之前的绿色小块就是queuebuffer, 所以从这里来看 影响整体合成帧率性能的 决定因素在queuebuffer的频率能否满足 VSYNC的需求,以达到60fps的效果

每一次surfaceflinger一帧 在一次VSYNC信号改变的时候,这里只抓取了核心的两个步骤:获取新的buffer 释放前一个buffer,组合buffer数据为一帧图像
可看到调用关系时间消耗组成图:
这里写图片描述
这里时序图中显示出来的函数名,是因为在其函数加了TRACE标记 去trace这个函数的生命周期
可依此来分析某个环节耗时多少,进行定位优化
比如在SurfaceFlinger.cpp 中:

<code class="hljs cs has-numbering"><span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG ATRACE_TAG_GRAPHICS</span></code><ul style="" class="pre-numbering"><li>1</li></ul>

可以看到TAG 为GRAPHICS 也就是为什么开始说eclipse里面只选个Graphics 就行了的原因,对应关系
函数中:

<code class="hljs cs has-numbering"><span class="hljs-keyword">bool</span> SurfaceFlinger::handleMessageInvalidate() {
    ATRACE_CALL();
    <span class="hljs-keyword">return</span> handlePageFlip();
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

ATRACE_CALL()为开始标记,这就开始trace该函数了


调用实现逻辑

上面有说到 ATRACE_CALL() 开始打开trace,本着习性,必然得去追一下code,记录一下 不在意细节 ~
这个宏定义在 \system\core\include\utils\Trace.h 中:

<code class="hljs cs has-numbering"><span class="hljs-comment">// ATRACE_NAME traces the beginning and end of the current scope.  To trace</span>
<span class="hljs-comment">// the correct start and end times this macro should be declared first in the</span>
<span class="hljs-comment">// scope body.</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_NAME(name) android::ScopedTrace ___tracer(ATRACE_TAG, name)</span>
<span class="hljs-comment">// ATRACE_CALL is an ATRACE_NAME that uses the current function name.</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_CALL() ATRACE_NAME(__FUNCTION__)</span>

namespace android {

class ScopedTrace {
<span class=“hljs-keyword”>public</span>:
inline <span class=“hljs-title”>ScopedTrace</span>(uint64_t tag, <span class=“hljs-keyword”>const</span> <span class=“hljs-keyword”>char</span>* name)
: <span class=“hljs-title”>mTag</span>(tag) {
atrace_begin(mTag,name);
}

inline ~ScopedTrace() {
atrace_end(mTag);
}

<span class=“hljs-keyword”>private</span>:
uint64_t mTag;
};
</code><ul style="" class=“pre-numbering”><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li></ul>

继续查看定义在 \system\core\include\cutils\trace.h 中:
看下TAG类型:

<code class="hljs cs has-numbering"><span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_NEVER            0       // This tag is never enabled.</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_ALWAYS           (1<<0)  // This tag is always enabled.</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_GRAPHICS         (1<<1)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_INPUT            (1<<2)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_VIEW             (1<<3)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_WEBVIEW          (1<<4)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_WINDOW_MANAGER   (1<<5)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_ACTIVITY_MANAGER (1<<6)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_SYNC_MANAGER     (1<<7)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_AUDIO            (1<<8)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_VIDEO            (1<<9)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_CAMERA           (1<<10)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_HAL              (1<<11)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_APP              (1<<12)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_RESOURCES        (1<<13)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_DALVIK           (1<<14)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_RS               (1<<15)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_BIONIC           (1<<16)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_POWER            (1<<17)</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> ATRACE_TAG_LAST             ATRACE_TAG_POWER</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>

其中上面在SurfaceFlinger中定义成了 ATRACE_TAG_GRAPHICS

<code class="hljs java has-numbering"><span class="hljs-javadoc">/**
 * Trace the beginning of a context.  name is used to identify the context.
 * This is often used to time function execution.
 */</span>
#define ATRACE_BEGIN(name) atrace_begin(ATRACE_TAG, name)
<span class="hljs-keyword">static</span> inline <span class="hljs-keyword">void</span> atrace_begin(uint64_t tag, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>* name)
{
    <span class="hljs-keyword">if</span> (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
        <span class="hljs-keyword">char</span> buf[ATRACE_MESSAGE_LENGTH];
        size_t len;
    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, &lt;span class="hljs-string"&gt;"B|%d|%s"&lt;/span&gt;, getpid(), name);
    write(atrace_marker_fd, buf, len);
}

}</code><ul style="" class=“pre-numbering”><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li></ul>

首先会去check 当前来的tag 是否 enable,会进行判断去初始化:

<code class="hljs java has-numbering"><span class="hljs-javadoc">/**
 * atrace_init readies the process for tracing by opening the trace_marker file.
 * Calling any trace function causes this to be run, so calling it is optional.
 * This can be explicitly run to avoid setup delay on first trace function.
 */</span>
#define ATRACE_INIT() atrace_init()
<span class="hljs-keyword">static</span> inline <span class="hljs-keyword">void</span> atrace_init()
{
    <span class="hljs-keyword">if</span> (CC_UNLIKELY(!android_atomic_acquire_load(&atrace_is_ready))) {
        atrace_setup();
    }
}

<span class=“hljs-javadoc”>/**

  • Get the mask of all tags currently enabled.
  • It can be used as a guard condition around more expensive trace calculations.
  • Every trace function calls this, which ensures atrace_init is run.
    */</span>
    #define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags()
    <span class=“hljs-keyword”>static</span> inline uint64_t atrace_get_enabled_tags()
    {
    atrace_init();
    <span class=“hljs-keyword”>return</span> atrace_enabled_tags;
    }

<span class=“hljs-javadoc”>/**

  • Test if a given tag is currently enabled.
  • Returns nonzero if the tag is enabled, otherwise zero.
  • It can be used as a guard condition around more expensive trace calculations.
    */</span>
    #define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG)
    <span class=“hljs-keyword”>static</span> inline uint64_t atrace_is_tag_enabled(uint64_t tag)
    {
    <span class=“hljs-keyword”>return</span> atrace_get_enabled_tags() & tag;
    }</code><ul style="" class=“pre-numbering”><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li></ul>

调转到 \system\core\libcutils\trace.c 中,只进行一次的初始化:

<code class="hljs fsharp has-numbering"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> atrace_init_once()
{
    atrace_marker_fd = <span class="hljs-keyword">open</span>(<span class="hljs-string">"/sys/kernel/debug/tracing/trace_marker"</span>, O_WRONLY);
    <span class="hljs-keyword">if</span> (atrace_marker_fd == -<span class="hljs-number">1</span>) {
        ALOGE(<span class="hljs-string">"Error opening trace file: %s (%d)"</span>, strerror(errno), errno);
        atrace_enabled_tags = <span class="hljs-number">0</span>;
        goto <span class="hljs-keyword">done</span>;
    }
atrace_enabled_tags = atrace_get_property();

<span class=“hljs-keyword”>done</span>:
android_atomic_release_store(<span class=“hljs-number”>1</span>, &atrace_is_ready);
}

<span class=“hljs-keyword”>void</span> atrace_setup()
{
pthread_once(&atrace_once_control, atrace_init_once);
}
</code><ul style="" class=“pre-numbering”><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>

/sys/kernel/debug/tracing/trace_marker 是重点,为trace在kernel里面创建的文件节点
打开之后保存全局的文件描述符:atrace_marker_fd

现在回头看atrace_beginatrace_end 就是向这个节点write 对应要打开的trace的开关数据
kernel中的trace驱动自然会有file operation处理
浏览个大概,细节有必要时再做分析~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值