Commit dcd36d01 authored by Paul E. McKenney's avatar Paul E. McKenney

Merge branches 'doc.2016.04.19a', 'exp.2016.03.31d', 'fixes.2016.03.31d' and...

Merge branches 'doc.2016.04.19a', 'exp.2016.03.31d', 'fixes.2016.03.31d' and 'torture.2016.04.21a' into HEAD

doc.2016.04.19a: Documentation updates
exp.2016.03.31d: Expedited grace-period updates
fixes.2016.03.31d: Miscellaneous fixes
torture.2016.004.21a Torture-test updates
...@@ -237,17 +237,17 @@ o "ktl" is the low-order 16 bits (in hexadecimal) of the count of ...@@ -237,17 +237,17 @@ o "ktl" is the low-order 16 bits (in hexadecimal) of the count of
The output of "cat rcu/rcu_preempt/rcuexp" looks as follows: The output of "cat rcu/rcu_preempt/rcuexp" looks as follows:
s=21872 wd0=0 wd1=0 wd2=0 wd3=5 n=0 enq=0 sc=21872 s=21872 wd1=0 wd2=0 wd3=5 n=0 enq=0 sc=21872
These fields are as follows: These fields are as follows:
o "s" is the sequence number, with an odd number indicating that o "s" is the sequence number, with an odd number indicating that
an expedited grace period is in progress. an expedited grace period is in progress.
o "wd0", "wd1", "wd2", and "wd3" are the number of times that an o "wd1", "wd2", and "wd3" are the number of times that an attempt
attempt to start an expedited grace period found that someone to start an expedited grace period found that someone else had
else had completed an expedited grace period that satisfies the completed an expedited grace period that satisfies the attempted
attempted request. "Our work is done." request. "Our work is done."
o "n" is number of times that a concurrent CPU-hotplug operation o "n" is number of times that a concurrent CPU-hotplug operation
forced a fallback to a normal grace period. forced a fallback to a normal grace period.
......
...@@ -3284,6 +3284,44 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -3284,6 +3284,44 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Lazy RCU callbacks are those which RCU can Lazy RCU callbacks are those which RCU can
prove do nothing more than free memory. prove do nothing more than free memory.
rcuperf.gp_exp= [KNL]
Measure performance of expedited synchronous
grace-period primitives.
rcuperf.holdoff= [KNL]
Set test-start holdoff period. The purpose of
this parameter is to delay the start of the
test until boot completes in order to avoid
interference.
rcuperf.nreaders= [KNL]
Set number of RCU readers. The value -1 selects
N, where N is the number of CPUs. A value
"n" less than -1 selects N-n+1, where N is again
the number of CPUs. For example, -2 selects N
(the number of CPUs), -3 selects N+1, and so on.
A value of "n" less than or equal to -N selects
a single reader.
rcuperf.nwriters= [KNL]
Set number of RCU writers. The values operate
the same as for rcuperf.nreaders.
N, where N is the number of CPUs
rcuperf.perf_runnable= [BOOT]
Start rcuperf running at boot time.
rcuperf.shutdown= [KNL]
Shut the system down after performance tests
complete. This is useful for hands-off automated
testing.
rcuperf.perf_type= [KNL]
Specify the RCU implementation to test.
rcuperf.verbose= [KNL]
Enable additional printk() statements.
rcutorture.cbflood_inter_holdoff= [KNL] rcutorture.cbflood_inter_holdoff= [KNL]
Set holdoff time (jiffies) between successive Set holdoff time (jiffies) between successive
callback-flood tests. callback-flood tests.
......
...@@ -508,14 +508,7 @@ int rcu_read_lock_bh_held(void); ...@@ -508,14 +508,7 @@ int rcu_read_lock_bh_held(void);
* CONFIG_DEBUG_LOCK_ALLOC, this assumes we are in an RCU-sched read-side * CONFIG_DEBUG_LOCK_ALLOC, this assumes we are in an RCU-sched read-side
* critical section unless it can prove otherwise. * critical section unless it can prove otherwise.
*/ */
#ifdef CONFIG_PREEMPT_COUNT
int rcu_read_lock_sched_held(void); int rcu_read_lock_sched_held(void);
#else /* #ifdef CONFIG_PREEMPT_COUNT */
static inline int rcu_read_lock_sched_held(void)
{
return 1;
}
#endif /* #else #ifdef CONFIG_PREEMPT_COUNT */
#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
...@@ -532,18 +525,10 @@ static inline int rcu_read_lock_bh_held(void) ...@@ -532,18 +525,10 @@ static inline int rcu_read_lock_bh_held(void)
return 1; return 1;
} }
#ifdef CONFIG_PREEMPT_COUNT
static inline int rcu_read_lock_sched_held(void) static inline int rcu_read_lock_sched_held(void)
{ {
return preempt_count() != 0 || irqs_disabled(); return !preemptible();
} }
#else /* #ifdef CONFIG_PREEMPT_COUNT */
static inline int rcu_read_lock_sched_held(void)
{
return 1;
}
#endif /* #else #ifdef CONFIG_PREEMPT_COUNT */
#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
#ifdef CONFIG_PROVE_RCU #ifdef CONFIG_PROVE_RCU
......
...@@ -149,6 +149,22 @@ static inline unsigned long rcu_batches_completed_sched(void) ...@@ -149,6 +149,22 @@ static inline unsigned long rcu_batches_completed_sched(void)
return 0; return 0;
} }
/*
* Return the number of expedited grace periods completed.
*/
static inline unsigned long rcu_exp_batches_completed(void)
{
return 0;
}
/*
* Return the number of expedited sched grace periods completed.
*/
static inline unsigned long rcu_exp_batches_completed_sched(void)
{
return 0;
}
static inline void rcu_force_quiescent_state(void) static inline void rcu_force_quiescent_state(void)
{ {
} }
......
...@@ -87,6 +87,8 @@ unsigned long rcu_batches_started_sched(void); ...@@ -87,6 +87,8 @@ unsigned long rcu_batches_started_sched(void);
unsigned long rcu_batches_completed(void); unsigned long rcu_batches_completed(void);
unsigned long rcu_batches_completed_bh(void); unsigned long rcu_batches_completed_bh(void);
unsigned long rcu_batches_completed_sched(void); unsigned long rcu_batches_completed_sched(void);
unsigned long rcu_exp_batches_completed(void);
unsigned long rcu_exp_batches_completed_sched(void);
void show_rcu_gp_kthreads(void); void show_rcu_gp_kthreads(void);
void rcu_force_quiescent_state(void); void rcu_force_quiescent_state(void);
......
...@@ -171,6 +171,77 @@ TRACE_EVENT(rcu_grace_period_init, ...@@ -171,6 +171,77 @@ TRACE_EVENT(rcu_grace_period_init,
__entry->grplo, __entry->grphi, __entry->qsmask) __entry->grplo, __entry->grphi, __entry->qsmask)
); );
/*
* Tracepoint for expedited grace-period events. Takes a string identifying
* the RCU flavor, the expedited grace-period sequence number, and a string
* identifying the grace-period-related event as follows:
*
* "snap": Captured snapshot of expedited grace period sequence number.
* "start": Started a real expedited grace period.
* "end": Ended a real expedited grace period.
* "endwake": Woke piggybackers up.
* "done": Someone else did the expedited grace period for us.
*/
TRACE_EVENT(rcu_exp_grace_period,
TP_PROTO(const char *rcuname, unsigned long gpseq, const char *gpevent),
TP_ARGS(rcuname, gpseq, gpevent),
TP_STRUCT__entry(
__field(const char *, rcuname)
__field(unsigned long, gpseq)
__field(const char *, gpevent)
),
TP_fast_assign(
__entry->rcuname = rcuname;
__entry->gpseq = gpseq;
__entry->gpevent = gpevent;
),
TP_printk("%s %lu %s",
__entry->rcuname, __entry->gpseq, __entry->gpevent)
);
/*
* Tracepoint for expedited grace-period funnel-locking events. Takes a
* string identifying the RCU flavor, an integer identifying the rcu_node
* combining-tree level, another pair of integers identifying the lowest-
* and highest-numbered CPU associated with the current rcu_node structure,
* and a string. identifying the grace-period-related event as follows:
*
* "nxtlvl": Advance to next level of rcu_node funnel
* "wait": Wait for someone else to do expedited GP
*/
TRACE_EVENT(rcu_exp_funnel_lock,
TP_PROTO(const char *rcuname, u8 level, int grplo, int grphi,
const char *gpevent),
TP_ARGS(rcuname, level, grplo, grphi, gpevent),
TP_STRUCT__entry(
__field(const char *, rcuname)
__field(u8, level)
__field(int, grplo)
__field(int, grphi)
__field(const char *, gpevent)
),
TP_fast_assign(
__entry->rcuname = rcuname;
__entry->level = level;
__entry->grplo = grplo;
__entry->grphi = grphi;
__entry->gpevent = gpevent;
),
TP_printk("%s %d %d %d %s",
__entry->rcuname, __entry->level, __entry->grplo,
__entry->grphi, __entry->gpevent)
);
/* /*
* Tracepoint for RCU no-CBs CPU callback handoffs. This event is intended * Tracepoint for RCU no-CBs CPU callback handoffs. This event is intended
* to assist debugging of these handoffs. * to assist debugging of these handoffs.
...@@ -704,11 +775,15 @@ TRACE_EVENT(rcu_barrier, ...@@ -704,11 +775,15 @@ TRACE_EVENT(rcu_barrier,
#else /* #ifdef CONFIG_RCU_TRACE */ #else /* #ifdef CONFIG_RCU_TRACE */
#define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0) #define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0)
#define trace_rcu_grace_period_init(rcuname, gpnum, level, grplo, grphi, \
qsmask) do { } while (0)
#define trace_rcu_future_grace_period(rcuname, gpnum, completed, c, \ #define trace_rcu_future_grace_period(rcuname, gpnum, completed, c, \
level, grplo, grphi, event) \ level, grplo, grphi, event) \
do { } while (0) do { } while (0)
#define trace_rcu_grace_period_init(rcuname, gpnum, level, grplo, grphi, \
qsmask) do { } while (0)
#define trace_rcu_exp_grace_period(rcuname, gqseq, gpevent) \
do { } while (0)
#define trace_rcu_exp_funnel_lock(rcuname, level, grplo, grphi, gpevent) \
do { } while (0)
#define trace_rcu_nocb_wake(rcuname, cpu, reason) do { } while (0) #define trace_rcu_nocb_wake(rcuname, cpu, reason) do { } while (0)
#define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0) #define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0)
#define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0) #define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0)
......
...@@ -5,6 +5,7 @@ KCOV_INSTRUMENT := n ...@@ -5,6 +5,7 @@ KCOV_INSTRUMENT := n
obj-y += update.o sync.o obj-y += update.o sync.o
obj-$(CONFIG_SRCU) += srcu.o obj-$(CONFIG_SRCU) += srcu.o
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
obj-$(CONFIG_RCU_PERF_TEST) += rcuperf.o
obj-$(CONFIG_TREE_RCU) += tree.o obj-$(CONFIG_TREE_RCU) += tree.o
obj-$(CONFIG_PREEMPT_RCU) += tree.o obj-$(CONFIG_PREEMPT_RCU) += tree.o
obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
......
This diff is collapsed.
...@@ -130,8 +130,8 @@ static struct rcu_torture __rcu *rcu_torture_current; ...@@ -130,8 +130,8 @@ static struct rcu_torture __rcu *rcu_torture_current;
static unsigned long rcu_torture_current_version; static unsigned long rcu_torture_current_version;
static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN]; static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
static DEFINE_SPINLOCK(rcu_torture_lock); static DEFINE_SPINLOCK(rcu_torture_lock);
static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) = { 0 }; static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count);
static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) = { 0 }; static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch);
static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1]; static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
static atomic_t n_rcu_torture_alloc; static atomic_t n_rcu_torture_alloc;
static atomic_t n_rcu_torture_alloc_fail; static atomic_t n_rcu_torture_alloc_fail;
...@@ -916,7 +916,7 @@ rcu_torture_fqs(void *arg) ...@@ -916,7 +916,7 @@ rcu_torture_fqs(void *arg)
static int static int
rcu_torture_writer(void *arg) rcu_torture_writer(void *arg)
{ {
bool can_expedite = !rcu_gp_is_expedited(); bool can_expedite = !rcu_gp_is_expedited() && !rcu_gp_is_normal();
int expediting = 0; int expediting = 0;
unsigned long gp_snap; unsigned long gp_snap;
bool gp_cond1 = gp_cond, gp_exp1 = gp_exp, gp_normal1 = gp_normal; bool gp_cond1 = gp_cond, gp_exp1 = gp_exp, gp_normal1 = gp_normal;
...@@ -932,7 +932,7 @@ rcu_torture_writer(void *arg) ...@@ -932,7 +932,7 @@ rcu_torture_writer(void *arg)
VERBOSE_TOROUT_STRING("rcu_torture_writer task started"); VERBOSE_TOROUT_STRING("rcu_torture_writer task started");
if (!can_expedite) { if (!can_expedite) {
pr_alert("%s" TORTURE_FLAG pr_alert("%s" TORTURE_FLAG
" Grace periods expedited from boot/sysfs for %s,\n", " GP expediting controlled from boot/sysfs for %s,\n",
torture_type, cur_ops->name); torture_type, cur_ops->name);
pr_alert("%s" TORTURE_FLAG pr_alert("%s" TORTURE_FLAG
" Disabled dynamic grace-period expediting.\n", " Disabled dynamic grace-period expediting.\n",
...@@ -1478,7 +1478,9 @@ static int rcu_torture_barrier_cbs(void *arg) ...@@ -1478,7 +1478,9 @@ static int rcu_torture_barrier_cbs(void *arg)
* The above smp_load_acquire() ensures barrier_phase load * The above smp_load_acquire() ensures barrier_phase load
* is ordered before the folloiwng ->call(). * is ordered before the folloiwng ->call().
*/ */
local_irq_disable(); /* Just to test no-irq call_rcu(). */
cur_ops->call(&rcu, rcu_torture_barrier_cbf); cur_ops->call(&rcu, rcu_torture_barrier_cbf);
local_irq_enable();
if (atomic_dec_and_test(&barrier_cbs_count)) if (atomic_dec_and_test(&barrier_cbs_count))
wake_up(&barrier_wq); wake_up(&barrier_wq);
} while (!torture_must_stop()); } while (!torture_must_stop());
...@@ -1585,7 +1587,7 @@ static int rcutorture_cpu_notify(struct notifier_block *self, ...@@ -1585,7 +1587,7 @@ static int rcutorture_cpu_notify(struct notifier_block *self,
{ {
long cpu = (long)hcpu; long cpu = (long)hcpu;
switch (action) { switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE: case CPU_ONLINE:
case CPU_DOWN_FAILED: case CPU_DOWN_FAILED:
(void)rcutorture_booster_init(cpu); (void)rcutorture_booster_init(cpu);
......
This diff is collapsed.
...@@ -70,7 +70,6 @@ ...@@ -70,7 +70,6 @@
# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0 } # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0 }
# define RCU_NODE_NAME_INIT { "rcu_node_0" } # define RCU_NODE_NAME_INIT { "rcu_node_0" }
# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0" } # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0" }
# define RCU_EXP_NAME_INIT { "rcu_node_exp_0" }
#elif NR_CPUS <= RCU_FANOUT_2 #elif NR_CPUS <= RCU_FANOUT_2
# define RCU_NUM_LVLS 2 # define RCU_NUM_LVLS 2
# define NUM_RCU_LVL_0 1 # define NUM_RCU_LVL_0 1
...@@ -79,7 +78,6 @@ ...@@ -79,7 +78,6 @@
# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1 } # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1 }
# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1" } # define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1" }
# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1" } # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1" }
# define RCU_EXP_NAME_INIT { "rcu_node_exp_0", "rcu_node_exp_1" }
#elif NR_CPUS <= RCU_FANOUT_3 #elif NR_CPUS <= RCU_FANOUT_3
# define RCU_NUM_LVLS 3 # define RCU_NUM_LVLS 3
# define NUM_RCU_LVL_0 1 # define NUM_RCU_LVL_0 1
...@@ -89,7 +87,6 @@ ...@@ -89,7 +87,6 @@
# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2 } # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2 }
# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2" } # define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2" }
# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" } # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" }
# define RCU_EXP_NAME_INIT { "rcu_node_exp_0", "rcu_node_exp_1", "rcu_node_exp_2" }
#elif NR_CPUS <= RCU_FANOUT_4 #elif NR_CPUS <= RCU_FANOUT_4
# define RCU_NUM_LVLS 4 # define RCU_NUM_LVLS 4
# define NUM_RCU_LVL_0 1 # define NUM_RCU_LVL_0 1
...@@ -100,7 +97,6 @@ ...@@ -100,7 +97,6 @@
# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, NUM_RCU_LVL_3 } # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, NUM_RCU_LVL_3 }
# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" } # define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" }
# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" } # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" }
# define RCU_EXP_NAME_INIT { "rcu_node_exp_0", "rcu_node_exp_1", "rcu_node_exp_2", "rcu_node_exp_3" }
#else #else
# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" # error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"
#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */ #endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */
...@@ -252,7 +248,9 @@ struct rcu_node { ...@@ -252,7 +248,9 @@ struct rcu_node {
/* Counts of upcoming no-CB GP requests. */ /* Counts of upcoming no-CB GP requests. */
raw_spinlock_t fqslock ____cacheline_internodealigned_in_smp; raw_spinlock_t fqslock ____cacheline_internodealigned_in_smp;
struct mutex exp_funnel_mutex ____cacheline_internodealigned_in_smp; spinlock_t exp_lock ____cacheline_internodealigned_in_smp;
unsigned long exp_seq_rq;
wait_queue_head_t exp_wq[4];
} ____cacheline_internodealigned_in_smp; } ____cacheline_internodealigned_in_smp;
/* /*
...@@ -387,11 +385,9 @@ struct rcu_data { ...@@ -387,11 +385,9 @@ struct rcu_data {
#ifdef CONFIG_RCU_FAST_NO_HZ #ifdef CONFIG_RCU_FAST_NO_HZ
struct rcu_head oom_head; struct rcu_head oom_head;
#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */ #endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
struct mutex exp_funnel_mutex; atomic_long_t exp_workdone1; /* # done by others #1. */
atomic_long_t expedited_workdone0; /* # done by others #0. */ atomic_long_t exp_workdone2; /* # done by others #2. */
atomic_long_t expedited_workdone1; /* # done by others #1. */ atomic_long_t exp_workdone3; /* # done by others #3. */
atomic_long_t expedited_workdone2; /* # done by others #2. */
atomic_long_t expedited_workdone3; /* # done by others #3. */
/* 7) Callback offloading. */ /* 7) Callback offloading. */
#ifdef CONFIG_RCU_NOCB_CPU #ifdef CONFIG_RCU_NOCB_CPU
...@@ -505,6 +501,8 @@ struct rcu_state { ...@@ -505,6 +501,8 @@ struct rcu_state {
/* _rcu_barrier(). */ /* _rcu_barrier(). */
/* End of fields guarded by barrier_mutex. */ /* End of fields guarded by barrier_mutex. */
struct mutex exp_mutex; /* Serialize expedited GP. */
struct mutex exp_wake_mutex; /* Serialize wakeup. */
unsigned long expedited_sequence; /* Take a ticket. */ unsigned long expedited_sequence; /* Take a ticket. */
atomic_long_t expedited_normal; /* # fallbacks to normal. */ atomic_long_t expedited_normal; /* # fallbacks to normal. */
atomic_t expedited_need_qs; /* # CPUs left to check in. */ atomic_t expedited_need_qs; /* # CPUs left to check in. */
...@@ -513,6 +511,8 @@ struct rcu_state { ...@@ -513,6 +511,8 @@ struct rcu_state {
unsigned long jiffies_force_qs; /* Time at which to invoke */ unsigned long jiffies_force_qs; /* Time at which to invoke */
/* force_quiescent_state(). */ /* force_quiescent_state(). */
unsigned long jiffies_kick_kthreads; /* Time at which to kick */
/* kthreads, if configured. */
unsigned long n_force_qs; /* Number of calls to */ unsigned long n_force_qs; /* Number of calls to */
/* force_quiescent_state(). */ /* force_quiescent_state(). */
unsigned long n_force_qs_lh; /* ~Number of calls leaving */ unsigned long n_force_qs_lh; /* ~Number of calls leaving */
......
...@@ -722,18 +722,22 @@ static void sync_rcu_exp_handler(void *info) ...@@ -722,18 +722,22 @@ static void sync_rcu_exp_handler(void *info)
* synchronize_rcu_expedited - Brute-force RCU grace period * synchronize_rcu_expedited - Brute-force RCU grace period
* *
* Wait for an RCU-preempt grace period, but expedite it. The basic * Wait for an RCU-preempt grace period, but expedite it. The basic
* idea is to invoke synchronize_sched_expedited() to push all the tasks to * idea is to IPI all non-idle non-nohz online CPUs. The IPI handler
* the ->blkd_tasks lists and wait for this list to drain. This consumes * checks whether the CPU is in an RCU-preempt critical section, and
* significant time on all CPUs and is unfriendly to real-time workloads, * if so, it sets a flag that causes the outermost rcu_read_unlock()
* so is thus not recommended for any sort of common-case code. * to report the quiescent state. On the other hand, if the CPU is
* In fact, if you are using synchronize_rcu_expedited() in a loop, * not in an RCU read-side critical section, the IPI handler reports
* please restructure your code to batch your updates, and then Use a * the quiescent state immediately.
* single synchronize_rcu() instead. *
* Although this is a greate improvement over previous expedited
* implementations, it is still unfriendly to real-time workloads, so is
* thus not recommended for any sort of common-case code. In fact, if
* you are using synchronize_rcu_expedited() in a loop, please restructure
* your code to batch your updates, and then Use a single synchronize_rcu()
* instead.
*/ */
void synchronize_rcu_expedited(void) void synchronize_rcu_expedited(void)
{ {
struct rcu_node *rnp;
struct rcu_node *rnp_unlock;
struct rcu_state *rsp = rcu_state_p; struct rcu_state *rsp = rcu_state_p;
unsigned long s; unsigned long s;
...@@ -744,23 +748,14 @@ void synchronize_rcu_expedited(void) ...@@ -744,23 +748,14 @@ void synchronize_rcu_expedited(void)
} }
s = rcu_exp_gp_seq_snap(rsp); s = rcu_exp_gp_seq_snap(rsp);
if (exp_funnel_lock(rsp, s))
rnp_unlock = exp_funnel_lock(rsp, s);
if (rnp_unlock == NULL)
return; /* Someone else did our work for us. */ return; /* Someone else did our work for us. */
rcu_exp_gp_seq_start(rsp);
/* Initialize the rcu_node tree in preparation for the wait. */ /* Initialize the rcu_node tree in preparation for the wait. */
sync_rcu_exp_select_cpus(rsp, sync_rcu_exp_handler); sync_rcu_exp_select_cpus(rsp, sync_rcu_exp_handler);
/* Wait for snapshotted ->blkd_tasks lists to drain. */ /* Wait for ->blkd_tasks lists to drain, then wake everyone up. */
rnp = rcu_get_root(rsp); rcu_exp_wait_wake(rsp, s);
synchronize_sched_expedited_wait(rsp);
/* Clean up and exit. */
rcu_exp_gp_seq_end(rsp);
mutex_unlock(&rnp_unlock->exp_funnel_mutex);
} }
EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
......
...@@ -185,17 +185,16 @@ static int show_rcuexp(struct seq_file *m, void *v) ...@@ -185,17 +185,16 @@ static int show_rcuexp(struct seq_file *m, void *v)
int cpu; int cpu;
struct rcu_state *rsp = (struct rcu_state *)m->private; struct rcu_state *rsp = (struct rcu_state *)m->private;
struct rcu_data *rdp; struct rcu_data *rdp;
unsigned long s0 = 0, s1 = 0, s2 = 0, s3 = 0; unsigned long s1 = 0, s2 = 0, s3 = 0;
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
rdp = per_cpu_ptr(rsp->rda, cpu); rdp = per_cpu_ptr(rsp->rda, cpu);
s0 += atomic_long_read(&rdp->expedited_workdone0); s1 += atomic_long_read(&rdp->exp_workdone1);
s1 += atomic_long_read(&rdp->expedited_workdone1); s2 += atomic_long_read(&rdp->exp_workdone2);
s2 += atomic_long_read(&rdp->expedited_workdone2); s3 += atomic_long_read(&rdp->exp_workdone3);
s3 += atomic_long_read(&rdp->expedited_workdone3);
} }
seq_printf(m, "s=%lu wd0=%lu wd1=%lu wd2=%lu wd3=%lu n=%lu enq=%d sc=%lu\n", seq_printf(m, "s=%lu wd1=%lu wd2=%lu wd3=%lu n=%lu enq=%d sc=%lu\n",
rsp->expedited_sequence, s0, s1, s2, s3, rsp->expedited_sequence, s1, s2, s3,
atomic_long_read(&rsp->expedited_normal), atomic_long_read(&rsp->expedited_normal),
atomic_read(&rsp->expedited_need_qs), atomic_read(&rsp->expedited_need_qs),
rsp->expedited_sequence / 2); rsp->expedited_sequence / 2);
......
...@@ -67,7 +67,7 @@ static int rcu_normal_after_boot; ...@@ -67,7 +67,7 @@ static int rcu_normal_after_boot;
module_param(rcu_normal_after_boot, int, 0); module_param(rcu_normal_after_boot, int, 0);
#endif /* #ifndef CONFIG_TINY_RCU */ #endif /* #ifndef CONFIG_TINY_RCU */
#if defined(CONFIG_DEBUG_LOCK_ALLOC) && defined(CONFIG_PREEMPT_COUNT) #ifdef CONFIG_DEBUG_LOCK_ALLOC
/** /**
* rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section? * rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section?
* *
...@@ -111,7 +111,7 @@ int rcu_read_lock_sched_held(void) ...@@ -111,7 +111,7 @@ int rcu_read_lock_sched_held(void)
return 0; return 0;
if (debug_locks) if (debug_locks)
lockdep_opinion = lock_is_held(&rcu_sched_lock_map); lockdep_opinion = lock_is_held(&rcu_sched_lock_map);
return lockdep_opinion || preempt_count() != 0 || irqs_disabled(); return lockdep_opinion || !preemptible();
} }
EXPORT_SYMBOL(rcu_read_lock_sched_held); EXPORT_SYMBOL(rcu_read_lock_sched_held);
#endif #endif
......
...@@ -451,6 +451,7 @@ static int torture_shutdown(void *arg) ...@@ -451,6 +451,7 @@ static int torture_shutdown(void *arg)
torture_shutdown_hook(); torture_shutdown_hook();
else else
VERBOSE_TOROUT_STRING("No torture_shutdown_hook(), skipping."); VERBOSE_TOROUT_STRING("No torture_shutdown_hook(), skipping.");
ftrace_dump(DUMP_ALL);
kernel_power_off(); /* Shut down the system. */ kernel_power_off(); /* Shut down the system. */
return 0; return 0;
} }
...@@ -602,8 +603,9 @@ bool torture_init_begin(char *ttype, bool v, int *runnable) ...@@ -602,8 +603,9 @@ bool torture_init_begin(char *ttype, bool v, int *runnable)
{ {
mutex_lock(&fullstop_mutex); mutex_lock(&fullstop_mutex);
if (torture_type != NULL) { if (torture_type != NULL) {
pr_alert("torture_init_begin: refusing %s init: %s running", pr_alert("torture_init_begin: Refusing %s init: %s running.\n",
ttype, torture_type); ttype, torture_type);
pr_alert("torture_init_begin: One torture test at a time!\n");
mutex_unlock(&fullstop_mutex); mutex_unlock(&fullstop_mutex);
return false; return false;
} }
......
...@@ -1289,6 +1289,39 @@ config TORTURE_TEST ...@@ -1289,6 +1289,39 @@ config TORTURE_TEST
tristate tristate
default n default n
config RCU_PERF_TEST
tristate "performance tests for RCU"
depends on DEBUG_KERNEL
select TORTURE_TEST
select SRCU
select TASKS_RCU
default n
help
This option provides a kernel module that runs performance
tests on the RCU infrastructure. The kernel module may be built
after the fact on the running kernel to be tested, if desired.
Say Y here if you want RCU performance tests to be built into
the kernel.
Say M if you want the RCU performance tests to build as a module.
Say N if you are unsure.
config RCU_PERF_TEST_RUNNABLE
bool "performance tests for RCU runnable by default"
depends on RCU_PERF_TEST = y
default n
help
This option provides a way to build the RCU performance tests
directly into the kernel without them starting up at boot time.
You can use /sys/module to manually override this setting.
This /proc file is available only when the RCU performance
tests have been built into the kernel.
Say Y here if you want the RCU performance tests to start during
boot (you probably don't).
Say N here if you want the RCU performance tests to start only
after being manually enabled via /sys/module.
config RCU_TORTURE_TEST config RCU_TORTURE_TEST
tristate "torture tests for RCU" tristate "torture tests for RCU"
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
......
#!/bin/bash
#
# Alternate sleeping and spinning on randomly selected CPUs. The purpose
# of this script is to inflict random OS jitter on a concurrently running
# test.
#
# Usage: jitter.sh me duration [ sleepmax [ spinmax ] ]
#
# me: Random-number-generator seed salt.
# duration: Time to run in seconds.
# sleepmax: Maximum microseconds to sleep, defaults to one second.
# spinmax: Maximum microseconds to spin, defaults to one millisecond.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you can access it online at
# http://www.gnu.org/licenses/gpl-2.0.html.
#
# Copyright (C) IBM Corporation, 2016
#
# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
me=$(($1 * 1000))
duration=$2
sleepmax=${3-1000000}
spinmax=${4-1000}
n=1
starttime=`awk 'BEGIN { print systime(); }' < /dev/null`
while :
do
# Check for done.
t=`awk -v s=$starttime 'BEGIN { print systime() - s; }' < /dev/null`
if test "$t" -gt "$duration"
then
exit 0;
fi
# Set affinity to randomly selected CPU
cpus=`ls /sys/devices/system/cpu/*/online |
sed -e 's,/[^/]*$,,' -e 's/^[^0-9]*//' |
grep -v '^0*$'`
cpumask=`awk -v cpus="$cpus" -v me=$me -v n=$n 'BEGIN {
srand(n + me + systime());
ncpus = split(cpus, ca);
curcpu = ca[int(rand() * ncpus + 1)];
mask = lshift(1, curcpu);
if (mask + 0 <= 0)
mask = 1;
printf("%#x\n", mask);
}' < /dev/null`
n=$(($n+1))
if ! taskset -p $cpumask $$ > /dev/null 2>&1
then
echo taskset failure: '"taskset -p ' $cpumask $$ '"'
exit 1
fi
# Sleep a random duration
sleeptime=`awk -v me=$me -v n=$n -v sleepmax=$sleepmax 'BEGIN {
srand(n + me + systime());
printf("%06d", int(rand() * sleepmax));
}' < /dev/null`
n=$(($n+1))
sleep .$sleeptime
# Spin a random duration
limit=`awk -v me=$me -v n=$n -v spinmax=$spinmax 'BEGIN {
srand(n + me + systime());
printf("%06d", int(rand() * spinmax));
}' < /dev/null`
n=$(($n+1))
for i in {1..$limit}
do
echo > /dev/null
done
done
exit 1
#!/bin/bash
#
# Analyze a given results directory for rcuperf performance measurements,
# looking for ftrace data. Exits with 0 if data was found, analyzed, and
# printed. Intended to be invoked from kvm-recheck-rcuperf.sh after
# argument checking.
#
# Usage: kvm-recheck-rcuperf-ftrace.sh resdir
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you can access it online at
# http://www.gnu.org/licenses/gpl-2.0.html.
#
# Copyright (C) IBM Corporation, 2016
#
# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
i="$1"
. tools/testing/selftests/rcutorture/bin/functions.sh
if test "`grep -c 'rcu_exp_grace_period.*start' < $i/console.log`" -lt 100
then
exit 10
fi
sed -e 's/^\[[^]]*]//' < $i/console.log |
grep 'us : rcu_exp_grace_period' |
sed -e 's/us : / : /' |
tr -d '\015' |
awk '
$8 == "start" {
if (starttask != "")
nlost++;
starttask = $1;
starttime = $3;
startseq = $7;
}
$8 == "end" {
if (starttask == $1 && startseq == $7) {
curgpdur = $3 - starttime;
gptimes[++n] = curgpdur;
gptaskcnt[starttask]++;
sum += curgpdur;
if (curgpdur > 1000)
print "Long GP " starttime "us to " $3 "us (" curgpdur "us)";
starttask = "";
} else {
# Lost a message or some such, reset.
starttask = "";
nlost++;
}
}
$8 == "done" {
piggybackcnt[$1]++;
}
END {
newNR = asort(gptimes);
if (newNR <= 0) {
print "No ftrace records found???"
exit 10;
}
pct50 = int(newNR * 50 / 100);
if (pct50 < 1)
pct50 = 1;
pct90 = int(newNR * 90 / 100);
if (pct90 < 1)
pct90 = 1;
pct99 = int(newNR * 99 / 100);
if (pct99 < 1)
pct99 = 1;
div = 10 ** int(log(gptimes[pct90]) / log(10) + .5) / 100;
print "Histogram bucket size: " div;
last = gptimes[1] - 10;
count = 0;
for (i = 1; i <= newNR; i++) {
current = div * int(gptimes[i] / div);
if (last == current) {
count++;
} else {
if (count > 0)
print last, count;
count = 1;
last = current;
}
}
if (count > 0)
print last, count;
print "Distribution of grace periods across tasks:";
for (i in gptaskcnt) {
print "\t" i, gptaskcnt[i];
nbatches += gptaskcnt[i];
}
ngps = nbatches;
print "Distribution of piggybacking across tasks:";
for (i in piggybackcnt) {
print "\t" i, piggybackcnt[i];
ngps += piggybackcnt[i];
}
print "Average grace-period duration: " sum / newNR " microseconds";
print "Minimum grace-period duration: " gptimes[1];
print "50th percentile grace-period duration: " gptimes[pct50];
print "90th percentile grace-period duration: " gptimes[pct90];
print "99th percentile grace-period duration: " gptimes[pct99];
print "Maximum grace-period duration: " gptimes[newNR];
print "Grace periods: " ngps + 0 " Batches: " nbatches + 0 " Ratio: " ngps / nbatches " Lost: " nlost + 0;
print "Computed from ftrace data.";
}'
exit 0
#!/bin/bash
#
# Analyze a given results directory for rcuperf performance measurements.
#
# Usage: kvm-recheck-rcuperf.sh resdir
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you can access it online at
# http://www.gnu.org/licenses/gpl-2.0.html.
#
# Copyright (C) IBM Corporation, 2016
#
# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
i="$1"
if test -d $i
then
:
else
echo Unreadable results directory: $i
exit 1
fi
PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH
. tools/testing/selftests/rcutorture/bin/functions.sh
if kvm-recheck-rcuperf-ftrace.sh $i
then
# ftrace data was successfully analyzed, call it good!
exit 0
fi
configfile=`echo $i | sed -e 's/^.*\///'`
sed -e 's/^\[[^]]*]//' < $i/console.log |
awk '
/-perf: .* gps: .* batches:/ {
ngps = $9;
nbatches = $11;
}
/-perf: .*writer-duration/ {
gptimes[++n] = $5 / 1000.;
sum += $5 / 1000.;
}
END {
newNR = asort(gptimes);
if (newNR <= 0) {
print "No rcuperf records found???"
exit;
}
pct50 = int(newNR * 50 / 100);
if (pct50 < 1)
pct50 = 1;
pct90 = int(newNR * 90 / 100);
if (pct90 < 1)
pct90 = 1;
pct99 = int(newNR * 99 / 100);
if (pct99 < 1)
pct99 = 1;
div = 10 ** int(log(gptimes[pct90]) / log(10) + .5) / 100;
print "Histogram bucket size: " div;
last = gptimes[1] - 10;
count = 0;
for (i = 1; i <= newNR; i++) {
current = div * int(gptimes[i] / div);
if (last == current) {
count++;
} else {
if (count > 0)
print last, count;
count = 1;
last = current;
}
}
if (count > 0)
print last, count;
print "Average grace-period duration: " sum / newNR " microseconds";
print "Minimum grace-period duration: " gptimes[1];
print "50th percentile grace-period duration: " gptimes[pct50];
print "90th percentile grace-period duration: " gptimes[pct90];
print "99th percentile grace-period duration: " gptimes[pct99];
print "Maximum grace-period duration: " gptimes[newNR];
print "Grace periods: " ngps + 0 " Batches: " nbatches + 0 " Ratio: " ngps / nbatches;
print "Computed from rcuperf printk output.";
}'
...@@ -48,7 +48,10 @@ do ...@@ -48,7 +48,10 @@ do
cat $i/Make.oldconfig.err cat $i/Make.oldconfig.err
fi fi
parse-build.sh $i/Make.out $configfile parse-build.sh $i/Make.out $configfile
parse-torture.sh $i/console.log $configfile if test "$TORTURE_SUITE" != rcuperf
then
parse-torture.sh $i/console.log $configfile
fi
parse-console.sh $i/console.log $configfile parse-console.sh $i/console.log $configfile
if test -r $i/Warnings if test -r $i/Warnings
then then
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# Execute this in the source tree. Do not run it as a background task # Execute this in the source tree. Do not run it as a background task
# because qemu does not seem to like that much. # because qemu does not seem to like that much.
# #
# Usage: kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args # Usage: kvm-test-1-run.sh config builddir resdir seconds qemu-args boot_args
# #
# qemu-args defaults to "-enable-kvm -soundhw pcspk -nographic", along with # qemu-args defaults to "-enable-kvm -soundhw pcspk -nographic", along with
# arguments specifying the number of CPUs and other # arguments specifying the number of CPUs and other
...@@ -91,25 +91,33 @@ fi ...@@ -91,25 +91,33 @@ fi
# CONFIG_PCMCIA=n # CONFIG_PCMCIA=n
# CONFIG_CARDBUS=n # CONFIG_CARDBUS=n
# CONFIG_YENTA=n # CONFIG_YENTA=n
if kvm-build.sh $config_template $builddir $T base_resdir=`echo $resdir | sed -e 's/\.[0-9]\+$//'`
if test "$base_resdir" != "$resdir" -a -f $base_resdir/bzImage -a -f $base_resdir/vmlinux
then then
# Rerunning previous test, so use that test's kernel.
QEMU="`identify_qemu $base_resdir/vmlinux`"
KERNEL=$base_resdir/bzImage
ln -s $base_resdir/Make*.out $resdir # for kvm-recheck.sh
ln -s $base_resdir/.config $resdir # for kvm-recheck.sh
elif kvm-build.sh $config_template $builddir $T
then
# Had to build a kernel for this test.
QEMU="`identify_qemu $builddir/vmlinux`" QEMU="`identify_qemu $builddir/vmlinux`"
BOOT_IMAGE="`identify_boot_image $QEMU`" BOOT_IMAGE="`identify_boot_image $QEMU`"
cp $builddir/Make*.out $resdir cp $builddir/Make*.out $resdir
cp $builddir/vmlinux $resdir
cp $builddir/.config $resdir cp $builddir/.config $resdir
if test -n "$BOOT_IMAGE" if test -n "$BOOT_IMAGE"
then then
cp $builddir/$BOOT_IMAGE $resdir cp $builddir/$BOOT_IMAGE $resdir
KERNEL=$resdir/bzImage
else else
echo No identifiable boot image, not running KVM, see $resdir. echo No identifiable boot image, not running KVM, see $resdir.
echo Do the torture scripts know about your architecture? echo Do the torture scripts know about your architecture?
fi fi
parse-build.sh $resdir/Make.out $title parse-build.sh $resdir/Make.out $title
if test -f $builddir.wait
then
mv $builddir.wait $builddir.ready
fi
else else
# Build failed.
cp $builddir/Make*.out $resdir cp $builddir/Make*.out $resdir
cp $builddir/.config $resdir || : cp $builddir/.config $resdir || :
echo Build failed, not running KVM, see $resdir. echo Build failed, not running KVM, see $resdir.
...@@ -119,12 +127,15 @@ else ...@@ -119,12 +127,15 @@ else
fi fi
exit 1 exit 1
fi fi
if test -f $builddir.wait
then
mv $builddir.wait $builddir.ready
fi
while test -f $builddir.ready while test -f $builddir.ready
do do
sleep 1 sleep 1
done done
minutes=$4 seconds=$4
seconds=$(($minutes * 60))
qemu_args=$5 qemu_args=$5
boot_args=$6 boot_args=$6
...@@ -167,15 +178,26 @@ then ...@@ -167,15 +178,26 @@ then
exit 0 exit 0
fi fi
echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log
echo $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd echo $QEMU $qemu_args -m 512 -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
( $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) & ( $QEMU $qemu_args -m 512 -kernel $KERNEL -append "$qemu_append $boot_args"& echo $! > $resdir/qemu_pid; wait `cat $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) &
qemu_pid=$!
commandcompleted=0 commandcompleted=0
echo Monitoring qemu job at pid $qemu_pid sleep 10 # Give qemu's pid a chance to reach the file
if test -s "$resdir/qemu_pid"
then
qemu_pid=`cat "$resdir/qemu_pid"`
echo Monitoring qemu job at pid $qemu_pid
else
qemu_pid=""
echo Monitoring qemu job at yet-as-unknown pid
fi
while : while :
do do
if test -z "$qemu_pid" -a -s "$resdir/qemu_pid"
then
qemu_pid=`cat "$resdir/qemu_pid"`
fi
kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null` kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null`
if kill -0 $qemu_pid > /dev/null 2>&1 if test -z "$qemu_pid" || kill -0 "$qemu_pid" > /dev/null 2>&1
then then
if test $kruntime -ge $seconds if test $kruntime -ge $seconds
then then
...@@ -195,12 +217,16 @@ do ...@@ -195,12 +217,16 @@ do
ps -fp $killpid >> $resdir/Warnings 2>&1 ps -fp $killpid >> $resdir/Warnings 2>&1
fi fi
else else
echo ' ---' `date`: Kernel done echo ' ---' `date`: "Kernel done"
fi fi
break break
fi fi
done done
if test $commandcompleted -eq 0 if test -z "$qemu_pid" -a -s "$resdir/qemu_pid"
then
qemu_pid=`cat "$resdir/qemu_pid"`
fi
if test $commandcompleted -eq 0 -a -n "$qemu_pid"
then then
echo Grace period for qemu job at pid $qemu_pid echo Grace period for qemu job at pid $qemu_pid
while : while :
...@@ -220,6 +246,9 @@ then ...@@ -220,6 +246,9 @@ then
fi fi
sleep 1 sleep 1
done done
elif test -z "$qemu_pid"
then
echo Unknown PID, cannot kill qemu command
fi fi
parse-torture.sh $resdir/console.log $title parse-torture.sh $resdir/console.log $title
......
...@@ -34,7 +34,7 @@ T=/tmp/kvm.sh.$$ ...@@ -34,7 +34,7 @@ T=/tmp/kvm.sh.$$
trap 'rm -rf $T' 0 trap 'rm -rf $T' 0
mkdir $T mkdir $T
dur=30 dur=$((30*60))
dryrun="" dryrun=""
KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
PATH=${KVM}/bin:$PATH; export PATH PATH=${KVM}/bin:$PATH; export PATH
...@@ -48,6 +48,7 @@ resdir="" ...@@ -48,6 +48,7 @@ resdir=""
configs="" configs=""
cpus=0 cpus=0
ds=`date +%Y.%m.%d-%H:%M:%S` ds=`date +%Y.%m.%d-%H:%M:%S`
jitter=0
. functions.sh . functions.sh
...@@ -63,6 +64,7 @@ usage () { ...@@ -63,6 +64,7 @@ usage () {
echo " --dryrun sched|script" echo " --dryrun sched|script"
echo " --duration minutes" echo " --duration minutes"
echo " --interactive" echo " --interactive"
echo " --jitter N [ maxsleep (us) [ maxspin (us) ] ]"
echo " --kmake-arg kernel-make-arguments" echo " --kmake-arg kernel-make-arguments"
echo " --mac nn:nn:nn:nn:nn:nn" echo " --mac nn:nn:nn:nn:nn:nn"
echo " --no-initrd" echo " --no-initrd"
...@@ -116,12 +118,17 @@ do ...@@ -116,12 +118,17 @@ do
;; ;;
--duration) --duration)
checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error' checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error'
dur=$2 dur=$(($2*60))
shift shift
;; ;;
--interactive) --interactive)
TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE
;; ;;
--jitter)
checkarg --jitter "(# threads [ sleep [ spin ] ])" $# "$2" '^-\{,1\}[0-9]\+\( \+[0-9]\+\)\{,2\} *$' '^error$'
jitter="$2"
shift
;;
--kmake-arg) --kmake-arg)
checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$' checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$'
TORTURE_KMAKE_ARG="$2" TORTURE_KMAKE_ARG="$2"
...@@ -156,7 +163,7 @@ do ...@@ -156,7 +163,7 @@ do
shift shift
;; ;;
--torture) --torture)
checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--' checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\)$' '^--'
TORTURE_SUITE=$2 TORTURE_SUITE=$2
shift shift
;; ;;
...@@ -299,6 +306,7 @@ awk < $T/cfgcpu.pack \ ...@@ -299,6 +306,7 @@ awk < $T/cfgcpu.pack \
-v CONFIGDIR="$CONFIGFRAG/" \ -v CONFIGDIR="$CONFIGFRAG/" \
-v KVM="$KVM" \ -v KVM="$KVM" \
-v ncpus=$cpus \ -v ncpus=$cpus \
-v jitter="$jitter" \
-v rd=$resdir/$ds/ \ -v rd=$resdir/$ds/ \
-v dur=$dur \ -v dur=$dur \
-v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \ -v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \
...@@ -359,6 +367,16 @@ function dump(first, pastlast, batchnum) ...@@ -359,6 +367,16 @@ function dump(first, pastlast, batchnum)
print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log"; print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log";
print "fi" print "fi"
} }
njitter = 0;
split(jitter, ja);
if (ja[1] == -1 && ncpus == 0)
njitter = 1;
else if (ja[1] == -1)
njitter = ncpus;
else
njitter = ja[1];
for (j = 0; j < njitter; j++)
print "jitter.sh " j " " dur " " ja[2] " " ja[3] "&"
print "wait" print "wait"
print "if test -z \"$TORTURE_BUILDONLY\"" print "if test -z \"$TORTURE_BUILDONLY\""
print "then" print "then"
......
...@@ -14,7 +14,7 @@ CONFIG_HOTPLUG_CPU=n ...@@ -14,7 +14,7 @@ CONFIG_HOTPLUG_CPU=n
CONFIG_SUSPEND=n CONFIG_SUSPEND=n
CONFIG_HIBERNATION=n CONFIG_HIBERNATION=n
CONFIG_RCU_FANOUT=4 CONFIG_RCU_FANOUT=4
CONFIG_RCU_FANOUT_LEAF=4 CONFIG_RCU_FANOUT_LEAF=3
CONFIG_RCU_NOCB_CPU=n CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
......
rcutorture.torture_type=rcu_bh rcutorture.torture_type=rcu_bh rcutree.rcu_fanout_leaf=4
CONFIG_RCU_PERF_TEST=y
CONFIG_PRINTK_TIME=y
CONFIG_SMP=y
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
#CHECK#CONFIG_PREEMPT_RCU=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
CONFIG_RCU_FAST_NO_HZ=n
CONFIG_RCU_TRACE=n
CONFIG_HOTPLUG_CPU=n
CONFIG_SUSPEND=n
CONFIG_HIBERNATION=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_PROVE_LOCKING=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
CONFIG_RCU_EXPERT=y
CONFIG_RCU_TRACE=y
CONFIG_SMP=y
CONFIG_NR_CPUS=54
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
#CHECK#CONFIG_PREEMPT_RCU=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
CONFIG_RCU_FAST_NO_HZ=n
CONFIG_RCU_TRACE=n
CONFIG_HOTPLUG_CPU=n
CONFIG_SUSPEND=n
CONFIG_HIBERNATION=n
CONFIG_RCU_FANOUT=3
CONFIG_RCU_FANOUT_LEAF=2
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_PROVE_LOCKING=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
CONFIG_RCU_EXPERT=y
CONFIG_RCU_TRACE=y
#!/bin/bash
#
# Torture-suite-dependent shell functions for the rest of the scripts.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you can access it online at
# http://www.gnu.org/licenses/gpl-2.0.html.
#
# Copyright (C) IBM Corporation, 2015
#
# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
# rcuperf_param_nreaders bootparam-string
#
# Adds nreaders rcuperf module parameter if not already specified.
rcuperf_param_nreaders () {
if ! echo "$1" | grep -q "rcuperf.nreaders"
then
echo rcuperf.nreaders=-1
fi
}
# rcuperf_param_nwriters bootparam-string
#
# Adds nwriters rcuperf module parameter if not already specified.
rcuperf_param_nwriters () {
if ! echo "$1" | grep -q "rcuperf.nwriters"
then
echo rcuperf.nwriters=-1
fi
}
# per_version_boot_params bootparam-string config-file seconds
#
# Adds per-version torture-module parameters to kernels supporting them.
per_version_boot_params () {
echo $1 `rcuperf_param_nreaders "$1"` \
`rcuperf_param_nwriters "$1"` \
rcuperf.perf_runnable=1 \
rcuperf.shutdown=1 \
rcuperf.verbose=1
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment