@@ -86,6 +86,7 @@ torture_param(bool, shutdown, RCUPERF_SHUTDOWN,
86
86
"Shutdown at end of performance tests." );
87
87
torture_param (int , verbose , 1 , "Enable verbose debugging printk()s" );
88
88
torture_param (int , writer_holdoff , 0 , "Holdoff (us) between GPs, zero to disable" );
89
+ torture_param (int , kfree_rcu_test , 0 , "Do we run a kfree_rcu() perf test?" );
89
90
90
91
static char * perf_type = "rcu" ;
91
92
module_param (perf_type , charp , 0444 );
@@ -105,8 +106,8 @@ static atomic_t n_rcu_perf_writer_finished;
105
106
static wait_queue_head_t shutdown_wq ;
106
107
static u64 t_rcu_perf_writer_started ;
107
108
static u64 t_rcu_perf_writer_finished ;
108
- static unsigned long b_rcu_perf_writer_started ;
109
- static unsigned long b_rcu_perf_writer_finished ;
109
+ static unsigned long b_rcu_gp_test_started ;
110
+ static unsigned long b_rcu_gp_test_finished ;
110
111
static DEFINE_PER_CPU (atomic_t , n_async_inflight ) ;
111
112
112
113
#define MAX_MEAS 10000
@@ -378,10 +379,10 @@ rcu_perf_writer(void *arg)
378
379
if (atomic_inc_return (& n_rcu_perf_writer_started ) >= nrealwriters ) {
379
380
t_rcu_perf_writer_started = t ;
380
381
if (gp_exp ) {
381
- b_rcu_perf_writer_started =
382
+ b_rcu_gp_test_started =
382
383
cur_ops -> exp_completed () / 2 ;
383
384
} else {
384
- b_rcu_perf_writer_started = cur_ops -> get_gp_seq ();
385
+ b_rcu_gp_test_started = cur_ops -> get_gp_seq ();
385
386
}
386
387
}
387
388
@@ -429,10 +430,10 @@ rcu_perf_writer(void *arg)
429
430
PERFOUT_STRING ("Test complete" );
430
431
t_rcu_perf_writer_finished = t ;
431
432
if (gp_exp ) {
432
- b_rcu_perf_writer_finished =
433
+ b_rcu_gp_test_finished =
433
434
cur_ops -> exp_completed () / 2 ;
434
435
} else {
435
- b_rcu_perf_writer_finished =
436
+ b_rcu_gp_test_finished =
436
437
cur_ops -> get_gp_seq ();
437
438
}
438
439
if (shutdown ) {
@@ -515,8 +516,8 @@ rcu_perf_cleanup(void)
515
516
t_rcu_perf_writer_finished -
516
517
t_rcu_perf_writer_started ,
517
518
ngps ,
518
- rcuperf_seq_diff (b_rcu_perf_writer_finished ,
519
- b_rcu_perf_writer_started ));
519
+ rcuperf_seq_diff (b_rcu_gp_test_finished ,
520
+ b_rcu_gp_test_started ));
520
521
for (i = 0 ; i < nrealwriters ; i ++ ) {
521
522
if (!writer_durations )
522
523
break ;
@@ -584,6 +585,167 @@ rcu_perf_shutdown(void *arg)
584
585
return - EINVAL ;
585
586
}
586
587
588
+ /*
589
+ * kfree_rcu() performance tests: Start a kfree_rcu() loop on all CPUs for number
590
+ * of iterations and measure total time and number of GP for all iterations to complete.
591
+ */
592
+
593
+ torture_param (int , kfree_nthreads , -1 , "Number of threads running loops of kfree_rcu()." );
594
+ torture_param (int , kfree_alloc_num , 8000 , "Number of allocations and frees done in an iteration." );
595
+ torture_param (int , kfree_loops , 10 , "Number of loops doing kfree_alloc_num allocations and frees." );
596
+ torture_param (int , kfree_no_batch , 0 , "Use the non-batching (slower) version of kfree_rcu()." );
597
+
598
+ static struct task_struct * * kfree_reader_tasks ;
599
+ static int kfree_nrealthreads ;
600
+ static atomic_t n_kfree_perf_thread_started ;
601
+ static atomic_t n_kfree_perf_thread_ended ;
602
+
603
+ struct kfree_obj {
604
+ char kfree_obj [8 ];
605
+ struct rcu_head rh ;
606
+ };
607
+
608
+ static int
609
+ kfree_perf_thread (void * arg )
610
+ {
611
+ int i , loop = 0 ;
612
+ long me = (long )arg ;
613
+ struct kfree_obj * alloc_ptr ;
614
+ u64 start_time , end_time ;
615
+
616
+ VERBOSE_PERFOUT_STRING ("kfree_perf_thread task started" );
617
+ set_cpus_allowed_ptr (current , cpumask_of (me % nr_cpu_ids ));
618
+ set_user_nice (current , MAX_NICE );
619
+
620
+ start_time = ktime_get_mono_fast_ns ();
621
+
622
+ if (atomic_inc_return (& n_kfree_perf_thread_started ) >= kfree_nrealthreads ) {
623
+ if (gp_exp )
624
+ b_rcu_gp_test_started = cur_ops -> exp_completed () / 2 ;
625
+ else
626
+ b_rcu_gp_test_started = cur_ops -> get_gp_seq ();
627
+ }
628
+
629
+ do {
630
+ for (i = 0 ; i < kfree_alloc_num ; i ++ ) {
631
+ alloc_ptr = kmalloc (sizeof (struct kfree_obj ), GFP_KERNEL );
632
+ if (!alloc_ptr )
633
+ return - ENOMEM ;
634
+
635
+ if (!kfree_no_batch ) {
636
+ kfree_rcu (alloc_ptr , rh );
637
+ } else {
638
+ rcu_callback_t cb ;
639
+
640
+ cb = (rcu_callback_t )(unsigned long )offsetof(struct kfree_obj , rh );
641
+ kfree_call_rcu_nobatch (& (alloc_ptr -> rh ), cb );
642
+ }
643
+ }
644
+
645
+ cond_resched ();
646
+ } while (!torture_must_stop () && ++ loop < kfree_loops );
647
+
648
+ if (atomic_inc_return (& n_kfree_perf_thread_ended ) >= kfree_nrealthreads ) {
649
+ end_time = ktime_get_mono_fast_ns ();
650
+
651
+ if (gp_exp )
652
+ b_rcu_gp_test_finished = cur_ops -> exp_completed () / 2 ;
653
+ else
654
+ b_rcu_gp_test_finished = cur_ops -> get_gp_seq ();
655
+
656
+ pr_alert ("Total time taken by all kfree'ers: %llu ns, loops: %d, batches: %ld\n" ,
657
+ (unsigned long long )(end_time - start_time ), kfree_loops ,
658
+ rcuperf_seq_diff (b_rcu_gp_test_finished , b_rcu_gp_test_started ));
659
+ if (shutdown ) {
660
+ smp_mb (); /* Assign before wake. */
661
+ wake_up (& shutdown_wq );
662
+ }
663
+ }
664
+
665
+ torture_kthread_stopping ("kfree_perf_thread" );
666
+ return 0 ;
667
+ }
668
+
669
+ static void
670
+ kfree_perf_cleanup (void )
671
+ {
672
+ int i ;
673
+
674
+ if (torture_cleanup_begin ())
675
+ return ;
676
+
677
+ if (kfree_reader_tasks ) {
678
+ for (i = 0 ; i < kfree_nrealthreads ; i ++ )
679
+ torture_stop_kthread (kfree_perf_thread ,
680
+ kfree_reader_tasks [i ]);
681
+ kfree (kfree_reader_tasks );
682
+ }
683
+
684
+ torture_cleanup_end ();
685
+ }
686
+
687
+ /*
688
+ * shutdown kthread. Just waits to be awakened, then shuts down system.
689
+ */
690
+ static int
691
+ kfree_perf_shutdown (void * arg )
692
+ {
693
+ do {
694
+ wait_event (shutdown_wq ,
695
+ atomic_read (& n_kfree_perf_thread_ended ) >=
696
+ kfree_nrealthreads );
697
+ } while (atomic_read (& n_kfree_perf_thread_ended ) < kfree_nrealthreads );
698
+
699
+ smp_mb (); /* Wake before output. */
700
+
701
+ kfree_perf_cleanup ();
702
+ kernel_power_off ();
703
+ return - EINVAL ;
704
+ }
705
+
706
+ static int __init
707
+ kfree_perf_init (void )
708
+ {
709
+ long i ;
710
+ int firsterr = 0 ;
711
+
712
+ kfree_nrealthreads = compute_real (kfree_nthreads );
713
+ /* Start up the kthreads. */
714
+ if (shutdown ) {
715
+ init_waitqueue_head (& shutdown_wq );
716
+ firsterr = torture_create_kthread (kfree_perf_shutdown , NULL ,
717
+ shutdown_task );
718
+ if (firsterr )
719
+ goto unwind ;
720
+ schedule_timeout_uninterruptible (1 );
721
+ }
722
+
723
+ kfree_reader_tasks = kcalloc (kfree_nrealthreads , sizeof (kfree_reader_tasks [0 ]),
724
+ GFP_KERNEL );
725
+ if (kfree_reader_tasks == NULL ) {
726
+ firsterr = - ENOMEM ;
727
+ goto unwind ;
728
+ }
729
+
730
+ for (i = 0 ; i < kfree_nrealthreads ; i ++ ) {
731
+ firsterr = torture_create_kthread (kfree_perf_thread , (void * )i ,
732
+ kfree_reader_tasks [i ]);
733
+ if (firsterr )
734
+ goto unwind ;
735
+ }
736
+
737
+ while (atomic_read (& n_kfree_perf_thread_started ) < kfree_nrealthreads )
738
+ schedule_timeout_uninterruptible (1 );
739
+
740
+ torture_init_end ();
741
+ return 0 ;
742
+
743
+ unwind :
744
+ torture_init_end ();
745
+ kfree_perf_cleanup ();
746
+ return firsterr ;
747
+ }
748
+
587
749
static int __init
588
750
rcu_perf_init (void )
589
751
{
@@ -616,6 +778,9 @@ rcu_perf_init(void)
616
778
if (cur_ops -> init )
617
779
cur_ops -> init ();
618
780
781
+ if (kfree_rcu_test )
782
+ return kfree_perf_init ();
783
+
619
784
nrealwriters = compute_real (nwriters );
620
785
nrealreaders = compute_real (nreaders );
621
786
atomic_set (& n_rcu_perf_reader_started , 0 );
0 commit comments