前话:计算机行业需要学习的知识太多,有时遇到一个不熟悉问题,只能依靠网络;网络上的答案有好有坏,也可能是环境与自己的环境不一样,导致给出的解决办法不适用。但是网络上有80%的答案都是拷贝粘贴,而且都不适用,不知道给出这些答案的人,最后到底解决答案了没有,针对这种情况,不知道有多少人和我一样会感到无奈甚至是气愤。改变不了环境,只能坚持自己好了。
- 问题背景(读者若对文中涉及到的知识不了解,找其他贴看吧):
- 项目要求,需要手动获取android使用systrace采样到的原始数据,后期对这些原始数据进行分析,进而实现一套自己的性能分析工具;
- 获取原始数据思路原理
- 首先得知道android中systrace框架是怎样进行数据搜集的,原理很简单,如下:
- 系统中存在一个线程(atrace,用户态),用来接收数据,并提供部分API,应用程序只需要使用这些API,就可以和该线程进行简单的通信;
- atrace接收到应用传来的信息,将数据写入kernel中ftrace框架中的ring-buffer,接口即为/sys/kernel/debugs/tracing/trace_marker(关于ftrace的文章-中国 Linux 内核开发者大会上的演讲稿:http://tinylab.org/ftrace-principle-and-practice/)
- 通过上面两步,数据已写入ring-buffer,如果对ftrace很熟悉的人,自然知道应该去/sys/kernel/debugs/tracing/trace(或trace_pipe)文件中去读取搜集到的信息
- 首先得知道android中systrace框架是怎样进行数据搜集的,原理很简单,如下:
- 实验
- 但是原理终究是原理,实现过程中第一步就卡住了;原因在于使用API的时候步骤有误,完全按照google官网给出的步骤仍旧有错
- 直接上代码–实验使用的是c语言:
//在执行程序之前,首先要打开kernel中trace的开关:
echo 1 > /sys/kernel/debugs/tracing/tracing_on
#define ATRACE_TAG ATRACE_TAG_ALWAYS//该定义,不管是位置还是值都很重要,网上很多答案均未给出此行代码,甚至是google官网步骤;此处TAG有很多,如果不使用ATRACE_TAG_ALWAYS,需要将ATRACE_TAG 和 debug.atrace.tags.enableflags联合使用;
//设置trace的enable选项:
setprop debug.atrace.tags.enableflags 0x400
getprop
#include <cutils/trace.h>
static int parseCommandLine(int argc, char** argv)
{
ATRACE_BEGIN("parseCommandLine");
...
ATRACE_END();
} - 结果截图:
cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 8/8 #P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
sh-5321 [003] ...1 1285940.919439: tracing_mark_write: hello
start_gpu-22648 [003] ...1 1285958.112761: tracing_mark_write: B|22648|main
start_gpu-22648 [003] ...1 1285958.112799: tracing_mark_write: B|22648|parseCommandLine
start_gpu-22648 [003] ...1 1285958.112860: tracing_mark_write: E
start_gpu-22648 [003] ...1 1285958.112898: tracing_mark_write: B|22648|parseCommandLine
start_gpu-22648 [003] ...1 1285958.114089: tracing_mark_write: E
start_gpu-22648 [003] ...1 1285958.114249: tracing_mark_write: B|22648|set_events
start_gpu-22648 [002] ...1 1285958.118014: tracing_mark_write: E
- 接下来给出关于systrace以及atrace的关键代码
static void atrace_init_once()
{
atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY);
if (atrace_marker_fd == -1) {
ALOGE("Error opening trace file: %s (%d)", strerror(errno), errno);
atrace_enabled_tags = 0;
goto done;
}
atrace_enabled_tags = atrace_get_property();
done:
atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
}
void atrace_setup()
{
pthread_once(&atrace_once_control, atrace_init_once);
}
void atrace_begin_body(const char* name)
{
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name);
write(atrace_marker_fd, buf, len);
}
void atrace_async_begin_body(const char* name, int32_t cookie)
{
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%" PRId32,
getpid(), name, cookie);
write(atrace_marker_fd, buf, len);
}
void atrace_async_end_body(const char* name, int32_t cookie)
{
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%" PRId32,
getpid(), name, cookie);
write(atrace_marker_fd, buf, len);
}
void atrace_int_body(const char* name, int32_t value)
{
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId32,
getpid(), name, value);
write(atrace_marker_fd, buf, len);
}
void atrace_int64_body(const char* name, int64_t value)
{
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId64,
getpid(), name, value);
write(atrace_marker_fd, buf, len);
}
//用户态API
#define ATRACE_INIT() atrace_init()
static inline void atrace_init()
{
if (CC_UNLIKELY(!atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
atrace_setup();
}
}
#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))) {//此处会将ATRACE_TAG和 debug.atrace.tags.enableflags进行求交集;
void atrace_begin_body(const char*);
atrace_begin_body(name);
}
}
#define ATRACE_END() atrace_end(ATRACE_TAG)
static inline void atrace_end(uint64_t tag)
{
if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
char c = 'E';
write(atrace_marker_fd, &c, 1);
}
}
#define ATRACE_ASYNC_END(name, cookie) atrace_async_end(ATRACE_TAG, name, cookie)
static inline void atrace_async_end(uint64_t tag, const char* name, int32_t cookie)
{
if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
void atrace_async_end_body(const char*, int32_t);
atrace_async_end_body(name, cookie);
}
}
/**
* Traces an integer counter value. name is used to identify the counter.
* This can be used to track how a value changes over time.
*/
#define ATRACE_INT(name, value) atrace_int(ATRACE_TAG, name, value)
static inline void atrace_int(uint64_t tag, const char* name, int32_t value)
{
if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
void atrace_int_body(const char*, int32_t);
atrace_int_body(name, value);
}
}
/**
* 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)
static inline void atrace_int64(uint64_t tag, const char* name, int64_t value)
{
if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
void atrace_int64_body(const char*, int64_t);
atrace_int64_body(name, value);
}
}
-附加:c++使用systrace的实例,稍作记录
#include <utils/Trace.h>
...
#define ATRACE_TAG ATRACE_TAG_ALWAYS
...
ATRACE_CALL()