atrace & trace_printk

参考

https://www.cnblogs.com/pyjetson/p/14946007.html

https://juejin.cn/post/7140836853241872392

atrace时android基于trace_marker来实现trace user space 调用的方法。使用cat /sys/kernel/debug/tracing/trace可打印出在user space添加的atrace.

static void atrace_init_once()
{
    atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);

    if (atrace_marker_fd == -1) {
        ALOGE("Error opening trace file: %s (%d)", strerror(errno), errno);
        atrace_enabled_tags = 0;
    } else {
      atrace_enabled_tags = atrace_get_property();
    }
}
// atrace_get_property-获取debug.atrace.tags.enableflags的值,默认为ATRACE_TAG_ALWAYS

// Read the sysprop and return the value tags should be set to
static uint64_t atrace_get_property()
{
    char value[PROPERTY_VALUE_MAX];
    char *endptr;
    uint64_t tags;

    property_get("debug.atrace.tags.enableflags", value, "0");
    errno = 0;
    tags = strtoull(value, &endptr, 0);
    if (value[0] == '\0' || *endptr != '\0') {
        ALOGE("Error parsing trace property: Not a number: %s", value);
        return 0;
    } else if (errno == ERANGE || tags == ULLONG_MAX) {
        ALOGE("Error parsing trace property: Number too large: %s", value);
        return 0;
    }

    // Only set the "app" tag if this process was selected for app-level debug
    // tracing.
    if (atrace_is_app_tracing_enabled()) {
        tags |= ATRACE_TAG_APP;
    } else {
        tags &= ~ATRACE_TAG_APP;
    }
    return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
}
#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);
    }
}
#define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG)
static inline uint64_t atrace_is_tag_enabled(uint64_t tag)
{
    return atrace_get_enabled_tags() & tag;
}
uint64_t atrace_get_enabled_tags()
{
    atrace_init();
    return atrace_enabled_tags;
}
void atrace_begin_body(const char* name)
{
    WRITE_MSG("B|%d|", "%s", name, "");
}
#define WRITE_MSG(format_begin, format_end, name, value) { \
    char buf[ATRACE_MESSAGE_LENGTH] __attribute__((uninitialized));     \
    int pid = getpid(); \
    int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
        name, value); \
    if (len >= (int) sizeof(buf)) { \
        /* Given the sizeof(buf), and all of the current format buffers, \
         * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \
        int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
        /* Truncate the name to make the message fit. */ \
        ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
        len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \
            name_len, name, value); \
    } \
    write(atrace_marker_fd, buf, len); \
}

 atrace_begin可以用来trace某些操作的begin,如果想要trace更多信息, 可改写atrace_write:

static void atrace_write(const char*fmt, ...) {
    char buf[ATRACE_MESSAGE_LENGTH] __attribute__((uninitialized));
    int len;
    va_list ap;

    va_start(ap, fmt);
    len = vsnprintf(buf, ATRACE_MESSAGE_LENGTH, fmt, ap);
    va_end(ap);
    if (len < 0) {
       return ;
    }
    write(atrace_marker_fd, buf, len); 
}

 

如果要在kernel添加trace,可使用trace_printk

/**
 * trace_printk - printf formatting in the ftrace buffer
 * @fmt: the printf format for printing
 *
 * Note: __trace_printk is an internal function for trace_printk() and
 *       the @ip is passed in via the trace_printk() macro.
 *
 * This function allows a kernel developer to debug fast path sections
 * that printk is not appropriate for. By scattering in various
 * printk like tracing in the code, a developer can quickly see
 * where problems are occurring.
 *
 * This is intended as a debugging tool for the developer only.
 * Please refrain from leaving trace_printks scattered around in
 * your code. (Extra memory is used for special buffers that are
 * allocated when trace_printk() is used.)
 *
 * A little optimization trick is done here. If there's only one
 * argument, there's no need to scan the string for printf formats.
 * The trace_puts() will suffice. But how can we take advantage of
 * using trace_puts() when trace_printk() has only one argument?
 * By stringifying the args and checking the size we can tell
 * whether or not there are args. __stringify((__VA_ARGS__)) will
 * turn into "()\0" with a size of 3 when there are no args, anything
 * else will be bigger. All we need to do is define a string to this,
 * and then take its size and compare to 3. If it's bigger, use
 * do_trace_printk() otherwise, optimize it to trace_puts(). Then just
 * let gcc optimize the rest.
 */

#define trace_printk(fmt, ...)                \
do {                            \
    char _______STR[] = __stringify((__VA_ARGS__));    \
    if (sizeof(_______STR) > 3)            \
        do_trace_printk(fmt, ##__VA_ARGS__);    \
    else                        \
        trace_puts(fmt);            \
} while (0)

trace_printk例子:https://elixir.bootlin.com/linux/v5.4.240/source/drivers/media/platform/qcom/camss/camss-vfe-4-1.c#L939

trace_printk("VFE: status0 = 0x%08x, status1 = 0x%08x\n",
             value0, value1);

 

posted @ 2023-04-16 15:18  fellow_jing  阅读(243)  评论(0编辑  收藏  举报