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