Systrace简介
systrace 是分析 Android 设备性能的主要工具,在PC端使用。
Android设备端对应的应用层控制程序是atrace。
Kernel对应使用的模块是ftrace。
建议使用systrace之前,先简单学习ftrace的使用方法。
Systrace官网:
https://developer.android.google.cn/topic/performance/tracing/?hl=zh-cn
使用示例
以SurfaceFlinger
的Vsync
分析为例,主机端执行
python2 systrace.py gfx
即可抓取SurfaceFlinger相关的trace。
没有特别指明时,抓取的结果在systrace安装目录下trace.html
,将其拖入谷歌浏览器,即可得到图形化的分析结果。
详细的Systrace使用方法,请阅读官网文档,本文仅介绍两种最常关注的元素,事件与帧堆栈。
事件
这里的VSYNC-sf
标签,就是一个事件。
本处以SYNC-sf
这一标签为例,查询Android源码中的对应触发源,学习它是怎么触发的。
使用箭头操作,点击标签,可以查看它的值,这里value = 1
。
TraceOrdinal 事件触发源
在源码中查看SYNC-sf
的触发源头,仅可以看到关于SYNC-sf
的一个注释,并没有执行什么代码来触发SYNC-sf
。
//frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.cpp
void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
// Trace VSYNC-sf
mVsync.value = (mVsync.value + 1) % 2;
}
追踪mVsync
//frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.h
class MessageQueue : public android::MessageQueue {
Vsync mVsync;
struct Vsync {
TracedOrdinal<int> value = {"VSYNC-sf", 0};
}
}
可以看到mVsync.value
是一个模板类TracedOrdinal<int>
//frameworks/native/services/surfaceflinger/TracedOrdinal.h
template <typename T>
class TracedOrdinal {
TracedOrdinal(std::string name, T initialValue)
: mName(std::move(name)),
mHasGoneNegative(std::signbit(initialValue)),
mData(initialValue) {
trace();
}
operator T() const { return mData; }
//核心操作,重载运算符=,赋值运算时,打印出当前标签的值
TracedOrdinal& operator=(T other) {
mData = other;
mHasGoneNegative = mHasGoneNegative || std::signbit(mData);
trace();
return *this;
}
private:
void trace() {
if (!std::signbit(mData)) {
ATRACE_INT64(mName.c_str(), int64_t(mData));
if (mHasGoneNegative) {
ATRACE_INT64(mNameNegative.c_str(), 0);
}
} else {
ATRACE_INT64(mNameNegative.c_str(), -int64_t(mData));
ATRACE_INT64(mName.c_str(), 0);
}
}
const std::string mName;
std::string mNameNegative;
bool mHasGoneNegative;
T mData;
};
这个TracedOrdinal
模板类,重载了赋值运算符,当进行赋值运算时,便会使用ATRACE_INT64
把事件标签的值,输出到systrace系统中。
//system/core/libcutils/include/cutils/trace.h
/**
* Traces a 64-bit integer counter value. name is used to identify the
* counter. This can be used to track how a value changes over time.
*/
#define ATRACE_INT64(name, value) atrace_int64(ATRACE_TAG, name, value)
这是一个atrace
的标准接口,ATRACE_TAG
用于控制输出开关,输出一个事件标签name
,以及它的值value
。
帧堆栈
帧堆栈是我们分析的第二项重要元素。
一个进程在Systrace的图形化界面中,通常首先罗列事件元素,然后紧接着就是帧堆栈元素。
帧堆栈元素是成堆的条形,属于一个线程,因此可以看到它在标签栏中是以线程名surfaceflinger
为标签的。
堆栈的每个层级代表线程对 atrace_begin() 与atrace_end()的一次调用,因为帧堆栈属于线程,因此这两个函数必须在同一个线程中先后被调用。
和事件元素一样,Android代码中通常也不会直接调用这两个函数,而是使用了一个类来封装使用。
ATRACE_CALL
在源码中查看surfaceflinger对onMessageInvalidate
的调用
void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) {
ATRACE_CALL();
}
那么这样一个类似函数调用的ATRACE_CALL
,是如何实现输出帧堆栈的效果的呢?
//system/core/libutils/include/utils/Trace.h
// ATRACE_NAME traces from its location until the end of its enclosing scope.
#define _PASTE(x, y) x ## y
#define PASTE(x, y) _PASTE(x,y)
#define ATRACE_NAME(name) ::android::ScopedTrace PASTE(___tracer, __LINE__)(ATRACE_TAG, name)
// ATRACE_CALL is an ATRACE_NAME that uses the current function name.
#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
namespace android {
class ScopedTrace {
public:
inline ScopedTrace(uint64_t tag, const char* name) : mTag(tag) {
atrace_begin(mTag, name);
}
inline ~ScopedTrace() {
atrace_end(mTag);
}
private:
uint64_t mTag;
};
在函数onMessageInvalidate
中,调用ATRACE_CALL
相当于以下代码
void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) {
::android::ScopedTrace __tracer2277(ATRACE_TAG, "onMessageInvalidate");
}
这是定义了一个局部变量,这个变量在函数入口,执行构造函数,在函数结束时,自动执行析构函数,来达到跟踪整个函数生命周期的效果。
//system/core/libcutils/include/cutils/trace.h
/**
* Trace the beginning of a context. name is used to identify the context.
* This is often used to time function execution.
*/
#define ATRACE_BEGIN(name) atrace_begin(ATRACE_TAG, name)
static inline void atrace_begin(uint64_t tag, const char* name);
/**
* Trace the end of a context.
* This should match up (and occur after) a corresponding ATRACE_BEGIN.
*/
#define ATRACE_END() atrace_end(ATRACE_TAG)
static inline void atrace_end(uint64_t tag);
atrace_begin()
与atrace_end()
,是atrace的标准接口函数,用于实现Systrace中的帧堆栈中的条形图案。
其中ATRACE_TAG
用于实现输出开关,name
则是帧堆栈中条形图案的名称,一般用__func__
指定为函数名。
结束
本文分析了Systrace中常用的两个元素,事件与帧堆栈。
在Android系统中,事件通过封装模板类TraceOrdinal
来实现赋值运算时的自动追踪效果;
帧堆栈则通过ATRACE_CALL
,利用局部变量的自动析构,来实现整个函数的追踪效果。