Systrace简介

systrace 是分析 Android 设备性能的主要工具,在PC端使用。
Android设备端对应的应用层控制程序是atrace。
Kernel对应使用的模块是ftrace。
建议使用systrace之前,先简单学习ftrace的使用方法。
Systrace官网:
https://developer.android.google.cn/topic/performance/tracing/?hl=zh-cn

使用示例

SurfaceFlingerVsync分析为例,主机端执行

python2 systrace.py gfx

即可抓取SurfaceFlinger相关的trace。

没有特别指明时,抓取的结果在systrace安装目录下trace.html,将其拖入谷歌浏览器,即可得到图形化的分析结果。

android studio 执行onDestroy android studio systrace_android


详细的Systrace使用方法,请阅读官网文档,本文仅介绍两种最常关注的元素,事件与帧堆栈。

事件

这里的VSYNC-sf标签,就是一个事件。

本处以SYNC-sf这一标签为例,查询Android源码中的对应触发源,学习它是怎么触发的。

android studio 执行onDestroy android studio systrace_堆栈_02


使用箭头操作,点击标签,可以查看它的值,这里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为标签的。

android studio 执行onDestroy android studio systrace_android_03


堆栈的每个层级代表线程对 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,利用局部变量的自动析构,来实现整个函数的追踪效果。