【systrace学习】atrace打开各系统层tag开关的原理

atrace命令可以开启trace,让系统中埋下的trace标记开始记录,这是怎么实现的呢,

我们以系统层的trace为例来查看,

atrace的代码

frameworks/native/cmds/atrace/​​​​​​atrace.cpp

93/* Tracing categories */
94static const TracingCategory k_categories[] = {
95    { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, {
96        { OPT,      "events/mdss/enable" },
97        { OPT,      "events/sde/enable" },
98    } },
99    { "input",      "Input",            ATRACE_TAG_INPUT, { } },
100    { "view",       "View System",      ATRACE_TAG_VIEW, { } },
101    { "webview",    "WebView",          ATRACE_TAG_WEBVIEW, { } },
102    { "wm",         "Window Manager",   ATRACE_TAG_WINDOW_MANAGER, { } },

里面通过设置属性的值,来传递信息,即哪些tag需要进行记录

606// Set the trace tags that userland tracing uses, and poke the running
607// processes to pick up the new value.
608static bool setTagsProperty(uint64_t tags)
609{
610    std::string value = android::base::StringPrintf("%#" PRIx64, tags);
611    if (!android::base::SetProperty(k_traceTagsProperty, value)) {
612        fprintf(stderr, "error setting trace tags system property\n");
613        return false;
614    }
615    return true;
616}
60const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";

执行函数由于执行的次数很多,所以没有必要每次都读取属性 debug.atrace.tags.enableflags的值来判断当前tag是否需要打印,只需要读一次,保存下来即可。

但是进程怎么知道属性值变化了呢,这里调用每个系统服务的SYSPROPS_TRANSACTION方法,来推送,

531// Poke all the binder-enabled processes in the system to get them to re-read
532// their system properties.
533static bool pokeBinderServices()
534{
535    sp<IServiceManager> sm = defaultServiceManager();
536    Vector<String16> services = sm->listServices();
537    for (size_t i = 0; i < services.size(); i++) {
538        sp<IBinder> obj = sm->checkService(services[i]);
539        if (obj != NULL) {
540            Parcel data;
541            if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
542                    NULL, 0) != OK) {
543                if (false) {
544                    // XXX: For some reason this fails on tablets trying to
545                    // poke the "phone" service.  It's not clear whether some
546                    // are expected to fail.
547                    String8 svc(services[i]);
548                    fprintf(stderr, "error poking binder service %s\n",
549                        svc.string());
550                    return false;
551                }
552            }
553        }
554    }
555    return true;
556}

SYSPROPS_TRANSACTION 方法执行起来做什么?

status_t BBinder::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
    switch (code) {
        ...
        case SYSPROPS_TRANSACTION: {
            report_sysprop_change();
            return NO_ERROR;
        }
        ...
    }
}
 

report_sysprop_change()方法会调用属性变化的回调函数,

void report_sysprop_change() {
   do_report_sysprop_change();

#if defined(__ANDROID__)
    // libutils.so is double loaded; from the default namespace and from the
    // 'sphal' namespace. Redirect the sysprop change event to the other instance
    // of libutils.so loaded in the 'sphal' namespace so that listeners attached
    // to that instance is also notified with this event.
    static auto func = get_report_sysprop_change_func();
    if (func != nullptr) {
        (*func)();
    }
#endif
}

所以,服务进程中写了回调函数后,就可以更新属性的值了。

这里使用了binder来进行通知。

InputDispatcher里的trace调用

3868void InputDispatcher::traceInboundQueueLengthLocked() {
3869    if (ATRACE_ENABLED()) {
3870        ATRACE_INT("iq", mInboundQueue.count());
3871    }
3872}

ATRACE_ENABLED

/system/core/include/cutils/
H A Dtrace.h168 #define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG)
156#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags()
157static inline uint64_t atrace_get_enabled_tags()
158{
159    atrace_init();
160    return atrace_enabled_tags;
161}
162
163/**
164 * Test if a given tag is currently enabled.
165 * Returns nonzero if the tag is enabled, otherwise zero.
166 * It can be used as a guard condition around more expensive trace calculations.
167 */
168#define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG)
169static inline uint64_t atrace_is_tag_enabled(uint64_t tag)
170{
171    return atrace_get_enabled_tags() & tag;
172}

调用traceInit()可以设置属性变化的回调,会调用

22static void traceInit() {
23    ::android::add_sysprop_change_callback(atrace_update_tags, 0);
24}

这里有个很有意思的知识点,在代码中搜不到traceInit的调用,只看到定义,

20static void traceInit() __attribute__((constructor));
21
22static void traceInit() {
23    ::android::add_sysprop_change_callback(atrace_update_tags, 0);
24}

那到底是怎样设置的回调函数呢?

其实设置了  __attribute__((constructor))  这个高端写法,在main函数开始的地方,就会调用traceInit方法,我们可以搜一下  __attribute__((constructor))这个用法。也可以写个例子来验证这种调用,情况确实如此。

查看atrace_update_tags的定义,在里面读取属性"debug.atrace.tags.enableflags"的值,更新了atrace_enabled_tags的值,

98/**
99 * If tracing is ready, set atrace_enabled_tags to the system property
100 * debug.atrace.tags.enableflags. Can be used as a sysprop change callback.
101 */
102void atrace_update_tags();

在 system/core/libcutils/trace-dev.inc

里有其实现,获取了要监控的属性值

136// Update tags if tracing is ready. Useful as a sysprop change callback.
137void atrace_update_tags()
138{
139    uint64_t tags;
140    if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
141        if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
142            tags = atrace_get_property();
143            pthread_mutex_lock(&atrace_tags_mutex);
144            atrace_enabled_tags = tags;
145            pthread_mutex_unlock(&atrace_tags_mutex);
146        } else {
147            // Tracing is disabled for this process, so we simply don't
148            // initialize the tags.
149            pthread_mutex_lock(&atrace_tags_mutex);
150            atrace_enabled_tags = ATRACE_TAG_NOT_READY;
151            pthread_mutex_unlock(&atrace_tags_mutex);
152        }
153    }
154}

总结:

细节很多,这里回顾一下大体过程,atrace里设置tag,标识哪些tag可以进行写trace,然后写到属性值debug.atrace.tags.enableflags里,atrace又进行了binder调用所有系统服务的SYSPROPS_TRANSACTION对应的方法,告诉它们,属性值变化了,可以调用属性变化回调函数了。

系统服务进程就调用预定的回调函数,读取debug.atrace.tags.enableflags的值,保存起来,以后就可以用这个值来和tag进行比较,判断当前的tag是否需要写trace,避免每次都属性值,那个读取代价太大。

普通应用中的trace原理类似,也是设置了属性值。

相关知识点:属性值的变化可以设置回调函数。

binder中竟然有个冷门方法SYSPROPS_TRANSACTION,通知属性值的变化。

参考资料:

[Android systrace系列] systrace的信息从哪里来 - zzc1024 - 博客园

监听SystemProperties变化_m0_52481422的博客-CSDN博客_android 监听property变化

<think>好的,用户想了解如何使用systrace进行性能追踪。我需要根据提供的引用内容整理步骤,确保符合系统级指令的要求,比如正确使用LaTeX格式,生成相关问题等。 首先,我应该先检查用户提供的引用内容,看看里面有哪些关键步骤和信息。引用[1]提到systrace是ftrace的封装,使用systrace.py脚本生成结果网页。引用[2]和[3]提到了在应用层、Java层和native代码中添加跟踪代码的方法,以及运行命令的参数。引用[4]则提到检查设备是否有atrace工具。 接下来,我需要将这些信息组织成清晰的步骤,可能包括准备工作、添加跟踪点、运行命令、分析结果等部分。每个步骤需要简明扼要,并且正确引用对应的引用来源。例如,在添加应用层跟踪点时,引用[2]提供了具体的代码示例,应该正确标注。 同时,要注意用户可能的环境差异,比如不同设备是否需要root权限,或者不同版本的Android系统可能存在的差异。但根据引用内容,没有特别提到这些,所以暂时不需要深入,但可以在注意事项中简单提及。 生成相关问题部分需要围绕systrace的使用展开,可能涉及优化、结果分析、对比其他工具等。根据已有信息,可以提出如何添加跟踪点、分析结果的方法、优化性能的步骤等问题。 最后,确保所有数学表达式或代码块使用正确的格式。虽然这个问题主要涉及命令行和代码示例,但如果有数学表达式,比如性能公式,需要用LaTeX,但这里可能不需要。代码块需要正确使用反引号包裹,并注明语言类型,如python或shell。 现在,把这些整理成结构化的回答,确保每个步骤有对应的引用标注,语言口语化,避免使用Markdown格式,同时生成相关问题。</think>### 如何使用 Systrace 进行性能追踪? #### **1. 准备工作** - **确认环境**:确保设备已开启开发者选项和USB调试模式,并通过`adb devices`连接成功[^4]。 - **检查工具**:输入`adb shell atrace`,若显示`capturing trace...`,则设备支持atraceSystrace底层依赖工具)[^4]。 #### **2. 添加跟踪点** - **应用层代码(Java)**: 在关键代码段前后插入以下语句: ```java Trace.beginSection("SECTION_NAME"); // 开始跟踪 // 需监控的代码逻辑 Trace.endSection(); // 结束跟踪 ``` 适用于Activity、Fragment等性能热点分析[^2]。 - **Framework层(Java/Native)**: - Java层使用`Trace.traceBegin(Trace.TRACE_TAG_VIEW, "RENDER_UI")`和`Trace.traceEnd()`。 - Native层使用`ATRACE_CALL()`或`ATRACE_BEGIN()`/`ATRACE_END()`[^2]。 #### **3. 运行Systrace命令** - **基础命令**: 进入SDK的`tools/systrace`目录,执行: ```shell python systrace.py -t 5 -o output.html sched gfx view # 追踪5秒,记录CPU调度、图形渲染等 ``` 参数说明: - `-t`:追踪时长(秒) - `-o`:输出文件名 - 末尾标签(如`sched`、`gfx`)定义追踪的模块[^1][^3]。 - **高级选项**: 使用`-l`查看支持的所有标签,例如: ```shell ./systrace.py -l # 显示可用标签(如cpu、disk、mem) ``` #### **4. 分析结果** - 打开生成的`output.html`,通过浏览器查看时间轴。 - **关键指标**: - **FPS(帧率)**:UI线程是否丢帧(绿色竖线表示帧渲染耗时)。 - **CPU利用率**:各核心负载是否均衡。 - **锁竞争**:检查线程阻塞情况(如红色标记的`SurfaceFlinger`卡顿)。 #### **注意事项** - **Root权限**:部分系统级标签(如`input`)需要root权限才能捕获。 - **版本兼容性**:不同Android版本可能支持不同的标签,建议使用最新SDK工具[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值