您的位置:首页 > 其它

ftrace macro

2016-03-19 13:43 369 查看
* Usage

Two elements are required for tracepoints :

- A tracepoint definition, placed in a header file.

- The tracepoint statement, in C code.

数据结构和宏定义在文件

include/linux/tacepoint.h

struct tracepoint_func {

void *func;

void *data;

};

struct tracepoint {

const char *name;
/* Tracepoint name */

struct static_key key;

void (*regfunc)(void);

void (*unregfunc)(void);

struct tracepoint_func __rcu *funcs;

};

extern int

tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);

extern int

tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data);

在头文件中包含tracepoint.h, 并调用DECLARE_TRACE定义一组函数

#define TP_PROTO(args...) args

#define TP_ARGS(args...) args

#define TP_CONDITION(args...) args

#define DECLARE_TRACE(name, proto, args) \

__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), 1,
\

PARAMS(void *__data, proto),
\

PARAMS(__data, args))

#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \

extern struct tracepoint __tracepoint_##name;
\

static inline void trace_##name(proto)
\

{ \

if (static_key_false(&__tracepoint_##name.key))
\

__DO_TRACE(&__tracepoint_##name,
\

TP_PROTO(data_proto),
\

TP_ARGS(data_args),
\

TP_CONDITION(cond),,);
\

if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) {
\

rcu_read_lock_sched_notrace();
\

rcu_dereference_sched(__tracepoint_##name.funcs);\

rcu_read_unlock_sched_notrace();
\

} \

} \

__DECLARE_TRACE_RCU(name, PARAMS(proto), PARAMS(args),
\

PARAMS(cond), PARAMS(data_proto), PARAMS(data_args))
\

static inline int
\

register_trace_##name(void (*probe)(data_proto), void *data)
\

{ \

return tracepoint_probe_register(&__tracepoint_##name,
\

(void *)probe, data);
\

} \

static inline int
\

unregister_trace_##name(void (*probe)(data_proto), void *data)
\

{ \

return tracepoint_probe_unregister(&__tracepoint_##name,\

(void *)probe, data);
\

} \

static inline void
\

check_trace_callback_type_##name(void (*cb)(data_proto))
\

{ \

} \

static inline bool
\

trace_##name##_enabled(void)
\

{ \

return static_key_false(&__tracepoint_##name.key);
\

}

DEFINE_TRACE:

#define DEFINE_TRACE_FN(name, reg, unreg) \

static const char __tpstrtab_##name[]
\

__attribute__((section("__tracepoints_strings"))) = #name;
\

struct tracepoint __tracepoint_##name
\

__attribute__((section("__tracepoints"))) =
\

{ __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\

static struct tracepoint * const __tracepoint_ptr_##name __used
\

__attribute__((section("__tracepoints_ptrs"))) =
\

&__tracepoint_##name;

#define DEFINE_TRACE(name) \

DEFINE_TRACE_FN(name, NULL, NULL);

#define __DO_TRACE(tp, proto, args, cond, prercu, postrcu)
\

do { \

struct tracepoint_func *it_func_ptr;
\

void *it_func;
\

void *__data;
\

\

if (!(cond))
\

return;
\

prercu;
\

rcu_read_lock_sched_notrace();
\

it_func_ptr = rcu_dereference_sched((tp)->funcs);
\

if (it_func_ptr) {
\

do { \

it_func = (it_func_ptr)->func;
\

__data = (it_func_ptr)->data;
\

((void(*)(proto))(it_func))(args);
\

} while ((++it_func_ptr)->func);
\

} \

rcu_read_unlock_sched_notrace();
\

postrcu;
\

} while (0)

static inline void trace_##name(proto) \

{ \

if (static_key_false(&__tracepoint_##name.key))
\

__DO_TRACE(&__tracepoint_##name,
\

TP_PROTO(data_proto),
\

TP_ARGS(data_args),
\

TP_CONDITION(cond),,);
\

if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) {
\

rcu_read_lock_sched_notrace();
\

rcu_dereference_sched(__tracepoint_##name.funcs);\

rcu_read_unlock_sched_notrace();
\

} \

}

在文件 trace/trace_sched_switch.c文件中看到了register, 而文件sample中没有看到

TRACE_EVENT是DECLARE_TRACE的变种:

#define TRACE_EVENT(name, proto, args, struct, assign, print)
\

DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))

/*

* For use with the TRACE_EVENT macro:

*

* We define a tracepoint, its arguments, its printk format

* and its 'fast binary record' layout.

*

* Firstly, name your tracepoint via TRACE_EVENT(name : the

* 'subsystem_event' notation is fine.

*

* Think about this whole construct as the

* 'trace_sched_switch() function' from now on.

*

*

* TRACE_EVENT(sched_switch,

*

* *

* * A function has a regular function arguments

* * prototype, declare it via TP_PROTO():

* *

*

* TP_PROTO(struct rq *rq, struct task_struct *prev,

* struct task_struct *next),

*

* *

* * Define the call signature of the 'function'.

* * (Design sidenote: we use this instead of a

* * TP_PROTO1/TP_PROTO2/TP_PROTO3 ugliness.)

* *

*

* TP_ARGS(rq, prev, next),

*

* *

* * Fast binary tracing: define the trace record via

* * TP_STRUCT__entry(). You can think about it like a

* * regular C structure local variable definition.

* *

* * This is how the trace record is structured and will

* * be saved into the ring buffer. These are the fields

* * that will be exposed to user-space in

* * /sys/kernel/debug/tracing/events/<*>/format.

* *

* * The declared 'local variable' is called '__entry'

* *

* * __field(pid_t, prev_prid) is equivalent to a standard declariton:

* *

* * pid_t
prev_pid;

* *

* * __array(char, prev_comm, TASK_COMM_LEN) is equivalent to:

* *

* * char
prev_comm[TASK_COMM_LEN];

* *

*

* TP_STRUCT__entry(

* __array(
char, prev_comm,
TASK_COMM_LEN )

* __field(
pid_t, prev_pid
)

* __field(
int, prev_prio
)

* __array(
char, next_comm,
TASK_COMM_LEN )

* __field(
pid_t, next_pid
)

* __field(
int, next_prio
)

* ),

*

* *

* * Assign the entry into the trace record, by embedding

* * a full C statement block into TP_fast_assign(). You

* * can refer to the trace record as '__entry' -

* * otherwise you can put arbitrary C code in here.

* *

* * Note: this C code will execute every time a trace event

* * happens, on an active tracepoint.

* *

*

* TP_fast_assign(

* memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN);

* __entry->prev_pid
= prev->pid;

* __entry->prev_prio
= prev->prio;

* memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN);

* __entry->next_pid
= next->pid;

* __entry->next_prio
= next->prio;

* ),

*

* *

* * Formatted output of a trace record via TP_printk().

* * This is how the tracepoint will appear under ftrace

* * plugins that make use of this tracepoint.

* *

* * (raw-binary tracing wont actually perform this step.)

* *

*

* TP_printk("task %s:%d [%d] ==> %s:%d [%d]",

* __entry->prev_comm, __entry->prev_pid, __entry->prev_prio,

* __entry->next_comm, __entry->next_pid, __entry->next_prio),

*

* );

*

* This macro construct is thus used for the regular printk format

* tracing setup, it is used to construct a function pointer based

* tracepoint callback (this is used by programmatic plugins and

* can also by used by generic instrumentation like SystemTap), and

* it is also used to expose a structured trace record in

* /sys/kernel/debug/tracing/events/.

*

* A set of (un)registration functions can be passed to the variant

* TRACE_EVENT_FN to perform any (un)registration work.

*/

这里TP_printk的意思是:

#define TP_printk(fmt, args...) fmt "\n", args
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: