- 调度任务:标识在该 CPU 核心上正在运行的任务,点击任务可查看其 ID、优先级等信息。
这些信息 App 可以直接读取 /sys/devices/system/cpu
节点下相关信息获得,而另外一部分标识线程状态信息则只能通过系统或者 adb 才能获取,且这些信息不是统一节点控制,需要激活各自对应的事件节点,让 ftrace 记录下不同事件的 tracepoint。内核在运行时,根据节点的使能状态,会往 ftrace 缓冲中记录事件。
例如,激活线程调度状态信息记录,需要激活类似如下相关节点。
events/sched/sched_switch/enable
events/sched/sched_wakeup/enable
激活后,则可以获取到线程调度状态相关的信息,比如:
-
Running: 线程在正常执行代码逻辑。
-
Runnable: 可执行状态,等待调度,如果长时间调度不到,说明 CPU 繁忙。
-
Sleeping: 休眠,一般是在等待事件驱动。
-
Uninterruptible Sleep: 不可中断的休眠,需要看 Args 描述来确定当时状态。
-
Uninterruptible Sleep - Block I/O: IO 阻塞。
最终,上述两大类事件记录都汇集到内核态同一缓冲中, Systrace 工具是通过指定抓取 trace 类别等参数,然后触发手机端 /system/bin/atrace
开启对应文件节点信息,接着 atrace 会读取 ftrace 缓存,生成只包含 ftrace 信息的 atrace_raw 信息,最终通过脚本转换成可视化 HTML 文件,大致流程如下。
RheaTrace 揭秘
本章节将从 RheaTrace 重点优势一一介绍。
Systrace 源码分析
Systrace 提供 Trace#beginSection(String)
和 Trace.endSection()
采集 atrace 数据,首先,我们大致了解下 atrace 工作原理,以 android.os.Trace#beginSection
作为分析入口。
public static void beginSection(@NonNull String sectionName) {
if (isTagEnabled(TRACE_TAG_APP)) {
if (sectionName.length() > MAX_SECTION_NAME_LEN) {
throw new IllegalArgumentException(“sectionName is too long”);
}
nativeTraceBegin(TRACE_TAG_APP, sectionName);
}
}
android.os.Trace#beginSection
会调用 nativeTraceBegin
方法,该方法实现参考 frameworks/base/core/jni/android_os_Trace.cpp。
static void android_os_Trace_nativeTraceBegin(JNIEnv* env, jclass,
jlong tag, jstring nameStr) {
withString(env, nameStr, tag {
atrace_begin(tag, str);
});
}
atrace_begin
方法实现参考 system/core/libcutils/include/cutils/trace.h。
#define ATRACE_BEGIN(name) atrace_begin(ATRACE_TAG, name)
static inline void atrace_begin(uint64_t tag, const char* name)
{
if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
void atrace_begin_body(const char*);
atrace_begin_body(name);
}
}
atrace_begin_body
方法实现参考 system/core/libcutils/trace-dev.cpp。
void atrace_begin_body(const char* name)
{
WRITE_MSG(“B|%d|”, “%s”, name, “”);
}
atrace_begin_body 最终实现在宏 WRITE_MSG 实现,代码如下:
#define WRITE_MSG(format_begin, format_end, name, value) { \
…
write(atrace_marker_fd, buf, len); \
}
通过 WRITE_MSG 实现,可知,atrace 数据是实时写入 fd 为 atrace_marker_fd
的文件中,如果多线程同时写入,则会出现锁问题,导致性能损耗加大。
RheaTrace 核心优势
效率提升
RheaTrace 会在 App 编译期间自动插入 Trace 跟踪函数,大大提高效率。针对不同 Android Gradle Plugin 版本,我们支持 Proguard 之后插桩,这样可以减少 App 方法插桩量,同时也过滤 Empty、Set/Get 等简单方法。
思路基于 matrix-gradle-plugin 大量改造实现。
rheaTrace {
compilation {
//为每个方法生成唯一 ID,若为 true,Trace#beginSection(String) 传入的是方法 ID。
traceWithMethodID = true
//决