Skip to content

Commit b4d1e34

Browse files
committed
refperf: Add read-side delay module parameter
This commit adds a refperf.readdelay module parameter that controls the duration of each critical section. This parameter allows gathering data showing how the performance differences between the various primitives vary with critical-section length. Cc: Joel Fernandes (Google) <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent 96af866 commit b4d1e34

File tree

1 file changed

+89
-19
lines changed

1 file changed

+89
-19
lines changed

kernel/rcu/refperf.c

Lines changed: 89 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ torture_param(long, loops, 10000000, "Number of loops per experiment.");
6666
torture_param(int, nreaders, -1, "Number of readers, -1 for 75% of CPUs.");
6767
// Number of runs.
6868
torture_param(int, nruns, 30, "Number of experiments to run.");
69-
// Reader delay in nanoseconds, 0 for no delay.
70-
torture_param(int, readdelay, 0, "Read-side delay in nanoseconds.");
69+
// Reader delay in microseconds, 0 for no delay.
70+
torture_param(int, readdelay, 0, "Read-side delay in microseconds.");
7171

7272
#ifdef MODULE
7373
# define REFPERF_SHUTDOWN 0
@@ -111,6 +111,7 @@ struct ref_perf_ops {
111111
void (*init)(void);
112112
void (*cleanup)(void);
113113
void (*readsection)(const int nloops);
114+
void (*delaysection)(const int nloops, const int ndelay);
114115
const char *name;
115116
};
116117

@@ -126,13 +127,25 @@ static void ref_rcu_read_section(const int nloops)
126127
}
127128
}
128129

130+
static void ref_rcu_delay_section(const int nloops, const int ndelay)
131+
{
132+
int i;
133+
134+
for (i = nloops; i >= 0; i--) {
135+
rcu_read_lock();
136+
udelay(ndelay);
137+
rcu_read_unlock();
138+
}
139+
}
140+
129141
static void rcu_sync_perf_init(void)
130142
{
131143
}
132144

133145
static struct ref_perf_ops rcu_ops = {
134146
.init = rcu_sync_perf_init,
135147
.readsection = ref_rcu_read_section,
148+
.delaysection = ref_rcu_delay_section,
136149
.name = "rcu"
137150
};
138151

@@ -141,7 +154,7 @@ static struct ref_perf_ops rcu_ops = {
141154
DEFINE_STATIC_SRCU(srcu_refctl_perf);
142155
static struct srcu_struct *srcu_ctlp = &srcu_refctl_perf;
143156

144-
static void srcu_ref_perf_read_section(int nloops)
157+
static void srcu_ref_perf_read_section(const int nloops)
145158
{
146159
int i;
147160
int idx;
@@ -152,16 +165,29 @@ static void srcu_ref_perf_read_section(int nloops)
152165
}
153166
}
154167

168+
static void srcu_ref_perf_delay_section(const int nloops, const int ndelay)
169+
{
170+
int i;
171+
int idx;
172+
173+
for (i = nloops; i >= 0; i--) {
174+
idx = srcu_read_lock(srcu_ctlp);
175+
udelay(ndelay);
176+
srcu_read_unlock(srcu_ctlp, idx);
177+
}
178+
}
179+
155180
static struct ref_perf_ops srcu_ops = {
156181
.init = rcu_sync_perf_init,
157182
.readsection = srcu_ref_perf_read_section,
183+
.delaysection = srcu_ref_perf_delay_section,
158184
.name = "srcu"
159185
};
160186

161187
// Definitions for reference count
162188
static atomic_t refcnt;
163189

164-
static void ref_perf_refcnt_section(const int nloops)
190+
static void ref_refcnt_section(const int nloops)
165191
{
166192
int i;
167193

@@ -171,45 +197,69 @@ static void ref_perf_refcnt_section(const int nloops)
171197
}
172198
}
173199

200+
static void ref_refcnt_delay_section(const int nloops, const int ndelay)
201+
{
202+
int i;
203+
204+
for (i = nloops; i >= 0; i--) {
205+
atomic_inc(&refcnt);
206+
udelay(ndelay);
207+
atomic_dec(&refcnt);
208+
}
209+
}
210+
174211
static struct ref_perf_ops refcnt_ops = {
175212
.init = rcu_sync_perf_init,
176-
.readsection = ref_perf_refcnt_section,
213+
.readsection = ref_refcnt_section,
214+
.delaysection = ref_refcnt_delay_section,
177215
.name = "refcnt"
178216
};
179217

180218
// Definitions for rwlock
181219
static rwlock_t test_rwlock;
182220

183-
static void ref_perf_rwlock_init(void)
221+
static void ref_rwlock_init(void)
184222
{
185223
rwlock_init(&test_rwlock);
186224
}
187225

188-
static void ref_perf_rwlock_section(const int nloops)
226+
static void ref_rwlock_section(const int nloops)
227+
{
228+
int i;
229+
230+
for (i = nloops; i >= 0; i--) {
231+
read_lock(&test_rwlock);
232+
read_unlock(&test_rwlock);
233+
}
234+
}
235+
236+
static void ref_rwlock_delay_section(const int nloops, const int ndelay)
189237
{
190238
int i;
191239

192240
for (i = nloops; i >= 0; i--) {
193241
read_lock(&test_rwlock);
242+
udelay(ndelay);
194243
read_unlock(&test_rwlock);
195244
}
196245
}
197246

198247
static struct ref_perf_ops rwlock_ops = {
199-
.init = ref_perf_rwlock_init,
200-
.readsection = ref_perf_rwlock_section,
248+
.init = ref_rwlock_init,
249+
.readsection = ref_rwlock_section,
250+
.delaysection = ref_rwlock_delay_section,
201251
.name = "rwlock"
202252
};
203253

204254
// Definitions for rwsem
205255
static struct rw_semaphore test_rwsem;
206256

207-
static void ref_perf_rwsem_init(void)
257+
static void ref_rwsem_init(void)
208258
{
209259
init_rwsem(&test_rwsem);
210260
}
211261

212-
static void ref_perf_rwsem_section(const int nloops)
262+
static void ref_rwsem_section(const int nloops)
213263
{
214264
int i;
215265

@@ -219,12 +269,32 @@ static void ref_perf_rwsem_section(const int nloops)
219269
}
220270
}
221271

272+
static void ref_rwsem_delay_section(const int nloops, const int ndelay)
273+
{
274+
int i;
275+
276+
for (i = nloops; i >= 0; i--) {
277+
down_read(&test_rwsem);
278+
udelay(ndelay);
279+
up_read(&test_rwsem);
280+
}
281+
}
282+
222283
static struct ref_perf_ops rwsem_ops = {
223-
.init = ref_perf_rwsem_init,
224-
.readsection = ref_perf_rwsem_section,
284+
.init = ref_rwsem_init,
285+
.readsection = ref_rwsem_section,
286+
.delaysection = ref_rwsem_delay_section,
225287
.name = "rwsem"
226288
};
227289

290+
static void rcu_perf_one_reader(void)
291+
{
292+
if (readdelay <= 0)
293+
cur_ops->readsection(loops);
294+
else
295+
cur_ops->delaysection(loops, readdelay);
296+
}
297+
228298
// Reader kthread. Repeatedly does empty RCU read-side
229299
// critical section, minimizing update-side interference.
230300
static int
@@ -265,16 +335,16 @@ ref_perf_reader(void *arg)
265335

266336
// To reduce noise, do an initial cache-warming invocation, check
267337
// in, and then keep warming until everyone has checked in.
268-
cur_ops->readsection(loops);
338+
rcu_perf_one_reader();
269339
if (!atomic_dec_return(&n_warmedup))
270340
while (atomic_read_acquire(&n_warmedup))
271-
cur_ops->readsection(loops);
341+
rcu_perf_one_reader();
272342
// Also keep interrupts disabled. This also has the effect
273343
// of preventing entries into slow path for rcu_read_unlock().
274344
local_irq_save(flags);
275345
start = ktime_get_mono_fast_ns();
276346

277-
cur_ops->readsection(loops);
347+
rcu_perf_one_reader();
278348

279349
duration = ktime_get_mono_fast_ns() - start;
280350
local_irq_restore(flags);
@@ -284,7 +354,7 @@ ref_perf_reader(void *arg)
284354
// everyone is done.
285355
if (!atomic_dec_return(&n_cooleddown))
286356
while (atomic_read_acquire(&n_cooleddown))
287-
cur_ops->readsection(loops);
357+
rcu_perf_one_reader();
288358

289359
if (atomic_dec_and_test(&nreaders_exp))
290360
wake_up(&main_wq);
@@ -449,8 +519,8 @@ static void
449519
ref_perf_print_module_parms(struct ref_perf_ops *cur_ops, const char *tag)
450520
{
451521
pr_alert("%s" PERF_FLAG
452-
"--- %s: verbose=%d shutdown=%d holdoff=%d loops=%ld nreaders=%d nruns=%d\n", perf_type, tag,
453-
verbose, shutdown, holdoff, loops, nreaders, nruns);
522+
"--- %s: verbose=%d shutdown=%d holdoff=%d loops=%ld nreaders=%d nruns=%d readdelay=%d\n", perf_type, tag,
523+
verbose, shutdown, holdoff, loops, nreaders, nruns, readdelay);
454524
}
455525

456526
static void

0 commit comments

Comments
 (0)