2015-01-17 155 views
3

Android systrace日誌記錄系統非常棒,但它僅適用於代碼的Java部分,通過Trace.beginSection()Trace.endSection()。在代碼的C/C++ NDK(native)部分中,它只能通過JNI使用,而JNI在沒有Java環境的線程中很慢或不可用...是否可以直接從本地代碼記錄Android systrace事件,而不使用JNI?

是否有任何方法將事件添加到主體系統跟蹤緩衝區,甚至是從本機C代碼生成一個單獨的日誌?

This老問題提到atrace/ftrace是Android的systrace使用的內部系統。這可以輕鬆(輕鬆)?

BONUS TWIST:由於跟蹤呼叫通常位於性能關鍵部分,因此最好在之後的實際事件時間內運行呼叫。即對於一個人我寧願能夠指定記錄的時間,而不是對它自己進行輪詢。但那隻會是錦上添花。

回答

7

我不認爲它是從NDK公開的。

如果你看看來源,你可以看到android.os.Trace class調用native code來做實際的工作。該代碼調用atrace_begin()atrace_end(),它們在header in the cutils庫中聲明。

如果從完整的源代碼樹中提取標題並鏈接到內部庫,則可以直接使用atrace函數。但是,您可以從標題看到atrace_begin()很簡單:

static inline void atrace_begin(uint64_t tag, const char* name) 
{ 
    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { 
     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); 
    } 
} 

事件被直接寫入跟蹤文件的描述符。 (請注意,時間戳不是事件的一部分;它會自動添加。)您可以在代碼中執行類似的操作;請參閱atrace_init_once()in the .c file以查看文件是如何打開的。請注意,除非將atrace作爲NDK的一部分發布,否則使用它的任何代碼都將是不可移植的,並且可能會在過去或未來版本的Android中失敗。然而,由於systrace是一個調試工具,而不是你實際想要在應用中啓用的東西,所以兼容性可能不是問題。

+0

非常感謝你的偉大的指針!它還解決了我關於人們如何在systrace輸出中獲取跟蹤計數器的另一個問題......我已經在一個單獨的答案中添加了一些解決方案的實現代碼。留下你的接受答案。 –

8

根據fadden的指針,用一些代碼發佈後續答案。請首先閱讀他/她的回答以獲得概述。

只需將正確格式化的字符串寫入/sys/kernel/debug/tracing/trace_marker即可正常打開,而且不會出現問題。以下是基於cutils headerC file的一些非常簡單的代碼。我更願意重新實現它,而不是牽扯任何依賴關係,所以如果你關心正確性,請檢查那裏的嚴格實現,和/或添加自己的額外檢查和錯誤處理。

這已經過測試,可在Android 4.4.2上運行。

跟蹤文件必須先打開,保存文件描述在atrace_marker_fd全球:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

#define ATRACE_MESSAGE_LEN 256 
int  atrace_marker_fd = -1; 

void trace_init() 
{ 
    atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY); 
    if (atrace_marker_fd == -1) { /* do error handling */ } 
} 

正常 '嵌套' 的痕跡類似於Java Trace.beginSectionTrace.endSection用得到:

inline void trace_begin(const char *name) 
{ 
    char buf[ATRACE_MESSAGE_LEN]; 
    int len = snprintf(buf, ATRACE_MESSAGE_LEN, "B|%d|%s", getpid(), name); 
    write(atrace_marker_fd, buf, len); 
} 

inline void trace_end() 
{ 
    char c = 'E'; 
    write(atrace_marker_fd, &c, 1); 
} 

還有兩種跟蹤類型可用,據我所知,Java無法訪問這些跟蹤類型:跟蹤計數器和異步跟蹤。

計數器跟蹤一個整數的值並在systrace HTML輸出中繪製一個小圖。非常有用的東西:

inline void trace_counter(const char *name, const int value) 
{ 
    char buf[ATRACE_MESSAGE_LEN]; 
    int len = snprintf(buf, ATRACE_MESSAGE_LEN, "C|%d|%s|%i", getpid(), name, value); 
    write(atrace_marker_fd, buf, len); 
} 

異步跡線產生非嵌套(即簡單地重疊)的時間間隔。它們在systrace HTML輸出中的細線程狀態欄上方顯示爲灰色段。他們採取額外的32位整數參數「區分同時發生的事件」。相同的名稱和整數必須結束痕跡時,可使用:

inline void trace_async_begin(const char *name, const int32_t cookie) 
{ 
    char buf[ATRACE_MESSAGE_LEN]; 
    int len = snprintf(buf, ATRACE_MESSAGE_LEN, "S|%d|%s|%i", getpid(), name, cookie); 
    write(atrace_marker_fd, buf, len); 
} 

inline void trace_async_end(const char *name, const int32_t cookie) 
{ 
    char buf[ATRACE_MESSAGE_LEN]; 
    int len = snprintf(buf, ATRACE_MESSAGE_LEN, "F|%d|%s|%i", getpid(), name, cookie); 
    write(atrace_marker_fd, buf, len); 
} 

最後,確實似乎沒有指定時間的記錄,短重新編譯的Android的方式,所以這不會對「獎金做什麼捻」。

相關問題