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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章