Skip to content

Commit 448b66a

Browse files
paulmckrcuFrederic Weisbecker
authored andcommitted
refscale: Add non-atomic per-CPU increment readers
This commit adds refscale readers based on READ_ONCE() and WRITE_ONCE() that are unprotected (can lose counts, "refscale.scale_type=incpercpu"), preempt-disabled ("refscale.scale_type=incpercpupreempt"), bh-disabled ("refscale.scale_type=incpercpubh"), and irq-disabled ("refscale.scale_type=incpercpuirqsave"). On my x86 laptop, these are about 4.3ns, 3.8ns, and 7.3ns per pair, respectively. Signed-off-by: Paul E. McKenney <paulmck@kernel.org> Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
1 parent bdba833 commit 448b66a

1 file changed

Lines changed: 153 additions & 2 deletions

File tree

kernel/rcu/refscale.c

Lines changed: 153 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,155 @@ static const struct ref_scale_ops percpuinc_ops = {
382382
.name = "percpuinc"
383383
};
384384

385+
// Note that this can lose counts in preemptible kernels.
386+
static void ref_incpercpu_section(const int nloops)
387+
{
388+
int i;
389+
390+
for (i = nloops; i >= 0; i--) {
391+
unsigned long *tap = this_cpu_ptr(&test_acqrel);
392+
393+
WRITE_ONCE(*tap, READ_ONCE(*tap) + 1);
394+
WRITE_ONCE(*tap, READ_ONCE(*tap) - 1);
395+
}
396+
}
397+
398+
static void ref_incpercpu_delay_section(const int nloops, const int udl, const int ndl)
399+
{
400+
int i;
401+
402+
for (i = nloops; i >= 0; i--) {
403+
unsigned long *tap = this_cpu_ptr(&test_acqrel);
404+
405+
WRITE_ONCE(*tap, READ_ONCE(*tap) + 1);
406+
un_delay(udl, ndl);
407+
WRITE_ONCE(*tap, READ_ONCE(*tap) - 1);
408+
}
409+
}
410+
411+
static const struct ref_scale_ops incpercpu_ops = {
412+
.init = rcu_sync_scale_init,
413+
.readsection = ref_incpercpu_section,
414+
.delaysection = ref_incpercpu_delay_section,
415+
.name = "incpercpu"
416+
};
417+
418+
static void ref_incpercpupreempt_section(const int nloops)
419+
{
420+
int i;
421+
422+
for (i = nloops; i >= 0; i--) {
423+
unsigned long *tap;
424+
425+
preempt_disable();
426+
tap = this_cpu_ptr(&test_acqrel);
427+
WRITE_ONCE(*tap, READ_ONCE(*tap) + 1);
428+
WRITE_ONCE(*tap, READ_ONCE(*tap) - 1);
429+
preempt_enable();
430+
}
431+
}
432+
433+
static void ref_incpercpupreempt_delay_section(const int nloops, const int udl, const int ndl)
434+
{
435+
int i;
436+
437+
for (i = nloops; i >= 0; i--) {
438+
unsigned long *tap;
439+
440+
preempt_disable();
441+
tap = this_cpu_ptr(&test_acqrel);
442+
WRITE_ONCE(*tap, READ_ONCE(*tap) + 1);
443+
un_delay(udl, ndl);
444+
WRITE_ONCE(*tap, READ_ONCE(*tap) - 1);
445+
preempt_enable();
446+
}
447+
}
448+
449+
static const struct ref_scale_ops incpercpupreempt_ops = {
450+
.init = rcu_sync_scale_init,
451+
.readsection = ref_incpercpupreempt_section,
452+
.delaysection = ref_incpercpupreempt_delay_section,
453+
.name = "incpercpupreempt"
454+
};
455+
456+
static void ref_incpercpubh_section(const int nloops)
457+
{
458+
int i;
459+
460+
for (i = nloops; i >= 0; i--) {
461+
unsigned long *tap;
462+
463+
local_bh_disable();
464+
tap = this_cpu_ptr(&test_acqrel);
465+
WRITE_ONCE(*tap, READ_ONCE(*tap) + 1);
466+
WRITE_ONCE(*tap, READ_ONCE(*tap) - 1);
467+
local_bh_enable();
468+
}
469+
}
470+
471+
static void ref_incpercpubh_delay_section(const int nloops, const int udl, const int ndl)
472+
{
473+
int i;
474+
475+
for (i = nloops; i >= 0; i--) {
476+
unsigned long *tap;
477+
478+
local_bh_disable();
479+
tap = this_cpu_ptr(&test_acqrel);
480+
WRITE_ONCE(*tap, READ_ONCE(*tap) + 1);
481+
un_delay(udl, ndl);
482+
WRITE_ONCE(*tap, READ_ONCE(*tap) - 1);
483+
local_bh_enable();
484+
}
485+
}
486+
487+
static const struct ref_scale_ops incpercpubh_ops = {
488+
.init = rcu_sync_scale_init,
489+
.readsection = ref_incpercpubh_section,
490+
.delaysection = ref_incpercpubh_delay_section,
491+
.name = "incpercpubh"
492+
};
493+
494+
static void ref_incpercpuirqsave_section(const int nloops)
495+
{
496+
int i;
497+
unsigned long flags;
498+
499+
for (i = nloops; i >= 0; i--) {
500+
unsigned long *tap;
501+
502+
local_irq_save(flags);
503+
tap = this_cpu_ptr(&test_acqrel);
504+
WRITE_ONCE(*tap, READ_ONCE(*tap) + 1);
505+
WRITE_ONCE(*tap, READ_ONCE(*tap) - 1);
506+
local_irq_restore(flags);
507+
}
508+
}
509+
510+
static void ref_incpercpuirqsave_delay_section(const int nloops, const int udl, const int ndl)
511+
{
512+
int i;
513+
unsigned long flags;
514+
515+
for (i = nloops; i >= 0; i--) {
516+
unsigned long *tap;
517+
518+
local_irq_save(flags);
519+
tap = this_cpu_ptr(&test_acqrel);
520+
WRITE_ONCE(*tap, READ_ONCE(*tap) + 1);
521+
un_delay(udl, ndl);
522+
WRITE_ONCE(*tap, READ_ONCE(*tap) - 1);
523+
local_irq_restore(flags);
524+
}
525+
}
526+
527+
static const struct ref_scale_ops incpercpuirqsave_ops = {
528+
.init = rcu_sync_scale_init,
529+
.readsection = ref_incpercpuirqsave_section,
530+
.delaysection = ref_incpercpuirqsave_delay_section,
531+
.name = "incpercpuirqsave"
532+
};
533+
385534
// Definitions for rwlock
386535
static rwlock_t test_rwlock;
387536

@@ -1318,8 +1467,10 @@ ref_scale_init(void)
13181467
int firsterr = 0;
13191468
static const struct ref_scale_ops *scale_ops[] = {
13201469
&rcu_ops, &srcu_ops, &srcu_fast_ops, RCU_TRACE_OPS RCU_TASKS_OPS
1321-
&refcnt_ops, &rwlock_ops, &rwsem_ops, &lock_ops, &lock_irq_ops,
1322-
&percpuinc_ops, &acqrel_ops, &sched_clock_ops, &clock_ops, &jiffies_ops,
1470+
&refcnt_ops, &percpuinc_ops, &incpercpu_ops, &incpercpupreempt_ops,
1471+
&incpercpubh_ops, &incpercpuirqsave_ops,
1472+
&rwlock_ops, &rwsem_ops, &lock_ops, &lock_irq_ops, &acqrel_ops,
1473+
&sched_clock_ops, &clock_ops, &jiffies_ops,
13231474
&preempt_ops, &bh_ops, &irq_ops, &irqsave_ops,
13241475
&typesafe_ref_ops, &typesafe_lock_ops, &typesafe_seqlock_ops,
13251476
};

0 commit comments

Comments
 (0)