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);