読者です 読者をやめる 読者になる 読者になる

φ(.. )メモシテオコウ trace_kmem_cache_alloc()はどこに?

linux kernel

trace_kmem_cache_alloc()はどこにいるの?と思ったのでめもです。

まずはこのkmem_cache_alloc_trace()を呼んでいるのはどこかというとslub.cのkmem_cache_alloc()です。あ、うちはslabじゃなくてslubを使ってるのでファイルはslub.cを参照してます(;´∀`)
ソースはこれですね。

2398 void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
2399 {
2400         void *ret = slab_alloc(s, gfpflags, _RET_IP_);
2401 
2402         trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, s->size, gfpflags);
2403 
2404         return ret;
2405 }

この2402行目のtrace_kmem_cache_alloc()ですが、これは普通にgrepとかしても見つかりません/(^o^)\ Linuxカーネルにかぎらないけどマクロを使って関数とか構造体を定義するパターンありますよね~ trace_kmem_cache_alloc()もそのパターンです。ちなみにNetBSDのmbufもマクロで定義してますね。FreeBSDは違いましたけど。

/*
 * Definition of "struct mbuf".
 * Don't change this without understanding how MHLEN/MLEN are defined.
 */
#define	MBUF_DEFINE(name, mhlen, mlen)					\
	struct name {							\
		struct	m_hdr m_hdr;					\
		union {							\
			struct {					\
				struct	pkthdr MH_pkthdr;		\
				union {					\
					struct	_m_ext MH_ext;		\
					char MH_databuf[(mhlen)];	\
				} MH_dat;				\
			} MH;						\
			char M_databuf[(mlen)];				\
		} M_dat;						\
	}


/*
 * The *real* struct mbuf
 */
MBUF_DEFINE(mbuf, MHLEN, MLEN);

与太話はさておきtrace_kmem_cache_alloc()はどこで定義しているのかというとinclude/trace/events/kmem.hで以下のようになってます。

 53 DEFINE_EVENT(kmem_alloc, kmem_cache_alloc,
 54 
 55         TP_PROTO(unsigned long call_site, const void *ptr,
 56                  size_t bytes_req, size_t bytes_alloc, gfp_t gfp_flags),
 57 
 58         TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags)
 59 );
 60 

そしてこのマクロ達はどこにあるかというと[http://lxr.free-electrons.com/source/include/linux/tracepoint.h
:title=include/linux/tracepoint.h]にあります。
そしてDEFINE_EVENTマクロを見ていくと最終的に__DECLARE_TRACEマクロにたどり着きます。ホントはCONFIG_TRACEPOINTSが定義されてるかで変わりますけど、CONFIG_TRACEPOINTSが定義されていない場合は空の関数を作るだけなのでCONFIG_TRACEPOINTSアリの場合を見ましょう。。。

155 /*
156  * Make sure the alignment of the structure in the __tracepoints section will
157  * not add unwanted padding between the beginning of the section and the
158  * structure. Force alignment to the same alignment as the section start.
159  */
160 #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
161         extern struct tracepoint __tracepoint_##name;                   \
162         static inline void trace_##name(proto)                          \
163         {                                                               \
164                 if (static_key_false(&__tracepoint_##name.key))         \
165                         __DO_TRACE(&__tracepoint_##name,                \
166                                 TP_PROTO(data_proto),                   \
167                                 TP_ARGS(data_args),                     \
168                                 TP_CONDITION(cond),,);                  \
169         }                                                               \
170         __DECLARE_TRACE_RCU(name, PARAMS(proto), PARAMS(args),          \
171                 PARAMS(cond), PARAMS(data_proto), PARAMS(data_args))    \
172         static inline int                                               \
173         register_trace_##name(void (*probe)(data_proto), void *data)    \
174         {                                                               \
175                 return tracepoint_probe_register(#name, (void *)probe,  \
176                                                  data);                 \
177         }                                                               \
178         static inline int                                               \
179         unregister_trace_##name(void (*probe)(data_proto), void *data)  \
180         {                                                               \
181                 return tracepoint_probe_unregister(#name, (void *)probe, \
182                                                    data);               \
183         }                                                               \
184         static inline void                                              \
185         check_trace_callback_type_##name(void (*cb)(data_proto))        \
186         {                                                               \
187         }

このマクロを見ると関数名にtrace_が付加されることがわかりますね。
DEFINE_EVENTマクロの2番目の引数がnameでこれをDECLARE_TRACEマクロの一番目の引数として渡します。

379 #define DEFINE_EVENT(template, name, proto, args)               \
380         DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))

そうすると、kmem.hではkmem_cache_allocがnameになるので__DECLARE_TRACEマクロによってtrace_kmem_cache_allocという関数が作られるわけです。
ということでLinuxカーネルコードでtrace_xxx()という関数があったらイベントトレーサー用の関数だってことが分かりますね( ´∀`)bグッ!

今回のまとめとしては、普通にgrepしたりctagsやlxr等で見つからない関数や構造体があったらマクロで作られていると考えると良いかと思います。
自分はtrace_kmem_cache_alloc()を探すときにslub.cでincludeしているtrace/events/kmem.hが怪しいんじゃね?というところと名前にtraceがついているのでトレーサー関係だよな~というところから__DECLARE_TRACEマクロにたどり着きました(;´Д`)

そういえば_RET_IP_は予想通りな内容でした。

107 #define _RET_IP_                (unsigned long)__builtin_return_address(0)

( ´Д`)ノ~