android使用systrace框架sampling 手动搜集数据并分析

前话:计算机行业需要学习的知识太多,有时遇到一个不熟悉问题,只能依靠网络;网络上的答案有好有坏,也可能是环境与自己的环境不一样,导致给出的解决办法不适用。但是网络上有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)文件中去读取搜集到的信息
  • 实验
    • 但是原理终究是原理,实现过程中第一步就卡住了;原因在于使用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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章