22#include  <test_progs.h> 
33#include  "kprobe_multi.skel.h" 
44#include  "trace_helpers.h" 
5+ #include  "kprobe_multi_empty.skel.h" 
6+ #include  "bpf/libbpf_internal.h" 
7+ #include  "bpf/hashmap.h" 
58
69static  void  kprobe_multi_test_run (struct  kprobe_multi  * skel , bool  test_return )
710{
@@ -301,6 +304,144 @@ static void test_attach_api_fails(void)
301304	kprobe_multi__destroy (skel );
302305}
303306
307+ static  inline  __u64  get_time_ns (void )
308+ {
309+ 	struct  timespec  t ;
310+ 
311+ 	clock_gettime (CLOCK_MONOTONIC , & t );
312+ 	return  (__u64 ) t .tv_sec  *  1000000000  +  t .tv_nsec ;
313+ }
314+ 
315+ static  size_t  symbol_hash (const  void  * key , void  * ctx  __maybe_unused )
316+ {
317+ 	return  str_hash ((const  char  * ) key );
318+ }
319+ 
320+ static  bool  symbol_equal (const  void  * key1 , const  void  * key2 , void  * ctx  __maybe_unused )
321+ {
322+ 	return  strcmp ((const  char  * ) key1 , (const  char  * ) key2 ) ==  0 ;
323+ }
324+ 
325+ static  int  get_syms (char  * * * symsp , size_t  * cntp )
326+ {
327+ 	size_t  cap  =  0 , cnt  =  0 , i ;
328+ 	char  * name , * * syms  =  NULL ;
329+ 	struct  hashmap  * map ;
330+ 	char  buf [256 ];
331+ 	FILE  * f ;
332+ 	int  err ;
333+ 
334+ 	/* 
335+ 	 * The available_filter_functions contains many duplicates, 
336+ 	 * but other than that all symbols are usable in kprobe multi 
337+ 	 * interface. 
338+ 	 * Filtering out duplicates by using hashmap__add, which won't 
339+ 	 * add existing entry. 
340+ 	 */ 
341+ 	f  =  fopen ("/sys/kernel/debug/tracing/available_filter_functions" , "r" );
342+ 	if  (!f )
343+ 		return  - EINVAL ;
344+ 
345+ 	map  =  hashmap__new (symbol_hash , symbol_equal , NULL );
346+ 	if  (IS_ERR (map ))
347+ 		goto error ;
348+ 
349+ 	while  (fgets (buf , sizeof (buf ), f )) {
350+ 		/* skip modules */ 
351+ 		if  (strchr (buf , '[' ))
352+ 			continue ;
353+ 		if  (sscanf (buf , "%ms$*[^\n]\n" , & name ) !=  1 )
354+ 			continue ;
355+ 		/* 
356+ 		 * We attach to almost all kernel functions and some of them 
357+ 		 * will cause 'suspicious RCU usage' when fprobe is attached 
358+ 		 * to them. Filter out the current culprits - arch_cpu_idle 
359+ 		 * and rcu_* functions. 
360+ 		 */ 
361+ 		if  (!strcmp (name , "arch_cpu_idle" ))
362+ 			continue ;
363+ 		if  (!strncmp (name , "rcu_" , 4 ))
364+ 			continue ;
365+ 		err  =  hashmap__add (map , name , NULL );
366+ 		if  (err ) {
367+ 			free (name );
368+ 			if  (err  ==  - EEXIST )
369+ 				continue ;
370+ 			goto error ;
371+ 		}
372+ 		err  =  libbpf_ensure_mem ((void  * * ) & syms , & cap ,
373+ 					sizeof (* syms ), cnt  +  1 );
374+ 		if  (err ) {
375+ 			free (name );
376+ 			goto error ;
377+ 		}
378+ 		syms [cnt ] =  name ;
379+ 		cnt ++ ;
380+ 	}
381+ 
382+ 	* symsp  =  syms ;
383+ 	* cntp  =  cnt ;
384+ 
385+ error :
386+ 	fclose (f );
387+ 	hashmap__free (map );
388+ 	if  (err ) {
389+ 		for  (i  =  0 ; i  <  cnt ; i ++ )
390+ 			free (syms [cnt ]);
391+ 		free (syms );
392+ 	}
393+ 	return  err ;
394+ }
395+ 
396+ static  void  test_bench_attach (void )
397+ {
398+ 	LIBBPF_OPTS (bpf_kprobe_multi_opts , opts );
399+ 	struct  kprobe_multi_empty  * skel  =  NULL ;
400+ 	long  attach_start_ns , attach_end_ns ;
401+ 	long  detach_start_ns , detach_end_ns ;
402+ 	double  attach_delta , detach_delta ;
403+ 	struct  bpf_link  * link  =  NULL ;
404+ 	char  * * syms  =  NULL ;
405+ 	size_t  cnt , i ;
406+ 
407+ 	if  (!ASSERT_OK (get_syms (& syms , & cnt ), "get_syms" ))
408+ 		return ;
409+ 
410+ 	skel  =  kprobe_multi_empty__open_and_load ();
411+ 	if  (!ASSERT_OK_PTR (skel , "kprobe_multi_empty__open_and_load" ))
412+ 		goto cleanup ;
413+ 
414+ 	opts .syms  =  (const  char  * * ) syms ;
415+ 	opts .cnt  =  cnt ;
416+ 
417+ 	attach_start_ns  =  get_time_ns ();
418+ 	link  =  bpf_program__attach_kprobe_multi_opts (skel -> progs .test_kprobe_empty ,
419+ 						     NULL , & opts );
420+ 	attach_end_ns  =  get_time_ns ();
421+ 
422+ 	if  (!ASSERT_OK_PTR (link , "bpf_program__attach_kprobe_multi_opts" ))
423+ 		goto cleanup ;
424+ 
425+ 	detach_start_ns  =  get_time_ns ();
426+ 	bpf_link__destroy (link );
427+ 	detach_end_ns  =  get_time_ns ();
428+ 
429+ 	attach_delta  =  (attach_end_ns  -  attach_start_ns ) / 1000000000.0 ;
430+ 	detach_delta  =  (detach_end_ns  -  detach_start_ns ) / 1000000000.0 ;
431+ 
432+ 	printf ("%s: found %lu functions\n" , __func__ , cnt );
433+ 	printf ("%s: attached in %7.3lfs\n" , __func__ , attach_delta );
434+ 	printf ("%s: detached in %7.3lfs\n" , __func__ , detach_delta );
435+ 
436+ cleanup :
437+ 	kprobe_multi_empty__destroy (skel );
438+ 	if  (syms ) {
439+ 		for  (i  =  0 ; i  <  cnt ; i ++ )
440+ 			free (syms [i ]);
441+ 		free (syms );
442+ 	}
443+ }
444+ 
304445void  test_kprobe_multi_test (void )
305446{
306447	if  (!ASSERT_OK (load_kallsyms (), "load_kallsyms" ))
@@ -320,4 +461,6 @@ void test_kprobe_multi_test(void)
320461		test_attach_api_syms ();
321462	if  (test__start_subtest ("attach_api_fails" ))
322463		test_attach_api_fails ();
464+ 	if  (test__start_subtest ("bench_attach" ))
465+ 		test_bench_attach ();
323466}
0 commit comments