You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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
This commit is contained in:
@@ -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:
|
||||
|
||||
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:
|
||||
|
||||
o "s" is the sequence number, with an odd number indicating that
|
||||
an expedited grace period is in progress.
|
||||
|
||||
o "wd0", "wd1", "wd2", and "wd3" are the number of times that an
|
||||
attempt to start an expedited grace period found that someone
|
||||
else had completed an expedited grace period that satisfies the
|
||||
attempted request. "Our work is done."
|
||||
o "wd1", "wd2", and "wd3" are the number of times that an attempt
|
||||
to start an expedited grace period found that someone else had
|
||||
completed an expedited grace period that satisfies the attempted
|
||||
request. "Our work is done."
|
||||
|
||||
o "n" is number of times that a concurrent CPU-hotplug operation
|
||||
forced a fallback to a normal grace period.
|
||||
|
||||
@@ -3284,6 +3284,44 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
Lazy RCU callbacks are those which RCU can
|
||||
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]
|
||||
Set holdoff time (jiffies) between successive
|
||||
callback-flood tests.
|
||||
|
||||
@@ -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
|
||||
* critical section unless it can prove otherwise.
|
||||
*/
|
||||
#ifdef CONFIG_PREEMPT_COUNT
|
||||
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 */
|
||||
|
||||
@@ -532,18 +525,10 @@ static inline int rcu_read_lock_bh_held(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PREEMPT_COUNT
|
||||
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 */
|
||||
|
||||
#ifdef CONFIG_PROVE_RCU
|
||||
|
||||
@@ -149,6 +149,22 @@ static inline unsigned long rcu_batches_completed_sched(void)
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ unsigned long rcu_batches_started_sched(void);
|
||||
unsigned long rcu_batches_completed(void);
|
||||
unsigned long rcu_batches_completed_bh(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 rcu_force_quiescent_state(void);
|
||||
|
||||
@@ -171,6 +171,77 @@ TRACE_EVENT(rcu_grace_period_init,
|
||||
__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
|
||||
* to assist debugging of these handoffs.
|
||||
@@ -704,11 +775,15 @@ TRACE_EVENT(rcu_barrier,
|
||||
#else /* #ifdef CONFIG_RCU_TRACE */
|
||||
|
||||
#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, \
|
||||
level, grplo, grphi, event) \
|
||||
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_preempt_task(rcuname, pid, gpnum) do { } while (0)
|
||||
#define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0)
|
||||
|
||||
@@ -5,6 +5,7 @@ KCOV_INSTRUMENT := n
|
||||
obj-y += update.o sync.o
|
||||
obj-$(CONFIG_SRCU) += srcu.o
|
||||
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
|
||||
obj-$(CONFIG_RCU_PERF_TEST) += rcuperf.o
|
||||
obj-$(CONFIG_TREE_RCU) += tree.o
|
||||
obj-$(CONFIG_PREEMPT_RCU) += tree.o
|
||||
obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -130,8 +130,8 @@ static struct rcu_torture __rcu *rcu_torture_current;
|
||||
static unsigned long rcu_torture_current_version;
|
||||
static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
|
||||
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_batch) = { 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);
|
||||
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_fail;
|
||||
@@ -916,7 +916,7 @@ rcu_torture_fqs(void *arg)
|
||||
static int
|
||||
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;
|
||||
unsigned long gp_snap;
|
||||
bool gp_cond1 = gp_cond, gp_exp1 = gp_exp, gp_normal1 = gp_normal;
|
||||
@@ -932,7 +932,7 @@ rcu_torture_writer(void *arg)
|
||||
VERBOSE_TOROUT_STRING("rcu_torture_writer task started");
|
||||
if (!can_expedite) {
|
||||
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);
|
||||
pr_alert("%s" TORTURE_FLAG
|
||||
" Disabled dynamic grace-period expediting.\n",
|
||||
@@ -1478,7 +1478,9 @@ static int rcu_torture_barrier_cbs(void *arg)
|
||||
* The above smp_load_acquire() ensures barrier_phase load
|
||||
* is ordered before the folloiwng ->call().
|
||||
*/
|
||||
local_irq_disable(); /* Just to test no-irq call_rcu(). */
|
||||
cur_ops->call(&rcu, rcu_torture_barrier_cbf);
|
||||
local_irq_enable();
|
||||
if (atomic_dec_and_test(&barrier_cbs_count))
|
||||
wake_up(&barrier_wq);
|
||||
} while (!torture_must_stop());
|
||||
@@ -1585,7 +1587,7 @@ static int rcutorture_cpu_notify(struct notifier_block *self,
|
||||
{
|
||||
long cpu = (long)hcpu;
|
||||
|
||||
switch (action) {
|
||||
switch (action & ~CPU_TASKS_FROZEN) {
|
||||
case CPU_ONLINE:
|
||||
case CPU_DOWN_FAILED:
|
||||
(void)rcutorture_booster_init(cpu);
|
||||
|
||||
+211
-87
File diff suppressed because it is too large
Load Diff
+10
-10
@@ -70,7 +70,6 @@
|
||||
# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0 }
|
||||
# define RCU_NODE_NAME_INIT { "rcu_node_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
|
||||
# define RCU_NUM_LVLS 2
|
||||
# define NUM_RCU_LVL_0 1
|
||||
@@ -79,7 +78,6 @@
|
||||
# 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_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
|
||||
# define RCU_NUM_LVLS 3
|
||||
# define NUM_RCU_LVL_0 1
|
||||
@@ -89,7 +87,6 @@
|
||||
# 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_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
|
||||
# define RCU_NUM_LVLS 4
|
||||
# define NUM_RCU_LVL_0 1
|
||||
@@ -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 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_EXP_NAME_INIT { "rcu_node_exp_0", "rcu_node_exp_1", "rcu_node_exp_2", "rcu_node_exp_3" }
|
||||
#else
|
||||
# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"
|
||||
#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */
|
||||
@@ -252,7 +248,9 @@ struct rcu_node {
|
||||
/* Counts of upcoming no-CB GP requests. */
|
||||
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;
|
||||
|
||||
/*
|
||||
@@ -387,11 +385,9 @@ struct rcu_data {
|
||||
#ifdef CONFIG_RCU_FAST_NO_HZ
|
||||
struct rcu_head oom_head;
|
||||
#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
|
||||
struct mutex exp_funnel_mutex;
|
||||
atomic_long_t expedited_workdone0; /* # done by others #0. */
|
||||
atomic_long_t expedited_workdone1; /* # done by others #1. */
|
||||
atomic_long_t expedited_workdone2; /* # done by others #2. */
|
||||
atomic_long_t expedited_workdone3; /* # done by others #3. */
|
||||
atomic_long_t exp_workdone1; /* # done by others #1. */
|
||||
atomic_long_t exp_workdone2; /* # done by others #2. */
|
||||
atomic_long_t exp_workdone3; /* # done by others #3. */
|
||||
|
||||
/* 7) Callback offloading. */
|
||||
#ifdef CONFIG_RCU_NOCB_CPU
|
||||
@@ -505,6 +501,8 @@ struct rcu_state {
|
||||
/* _rcu_barrier(). */
|
||||
/* 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. */
|
||||
atomic_long_t expedited_normal; /* # fallbacks to normal. */
|
||||
atomic_t expedited_need_qs; /* # CPUs left to check in. */
|
||||
@@ -513,6 +511,8 @@ struct rcu_state {
|
||||
|
||||
unsigned long jiffies_force_qs; /* Time at which to invoke */
|
||||
/* 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 */
|
||||
/* force_quiescent_state(). */
|
||||
unsigned long n_force_qs_lh; /* ~Number of calls leaving */
|
||||
|
||||
+16
-21
@@ -722,18 +722,22 @@ static void sync_rcu_exp_handler(void *info)
|
||||
* synchronize_rcu_expedited - Brute-force RCU grace period
|
||||
*
|
||||
* 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
|
||||
* the ->blkd_tasks lists and wait for this list to drain. This consumes
|
||||
* significant time on all CPUs and is 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.
|
||||
* idea is to IPI all non-idle non-nohz online CPUs. The IPI handler
|
||||
* checks whether the CPU is in an RCU-preempt critical section, and
|
||||
* if so, it sets a flag that causes the outermost rcu_read_unlock()
|
||||
* to report the quiescent state. On the other hand, if the CPU is
|
||||
* not in an RCU read-side critical section, the IPI handler reports
|
||||
* the quiescent state immediately.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
struct rcu_node *rnp;
|
||||
struct rcu_node *rnp_unlock;
|
||||
struct rcu_state *rsp = rcu_state_p;
|
||||
unsigned long s;
|
||||
|
||||
@@ -744,23 +748,14 @@ void synchronize_rcu_expedited(void)
|
||||
}
|
||||
|
||||
s = rcu_exp_gp_seq_snap(rsp);
|
||||
|
||||
rnp_unlock = exp_funnel_lock(rsp, s);
|
||||
if (rnp_unlock == NULL)
|
||||
if (exp_funnel_lock(rsp, s))
|
||||
return; /* Someone else did our work for us. */
|
||||
|
||||
rcu_exp_gp_seq_start(rsp);
|
||||
|
||||
/* Initialize the rcu_node tree in preparation for the wait. */
|
||||
sync_rcu_exp_select_cpus(rsp, sync_rcu_exp_handler);
|
||||
|
||||
/* Wait for snapshotted ->blkd_tasks lists to drain. */
|
||||
rnp = rcu_get_root(rsp);
|
||||
synchronize_sched_expedited_wait(rsp);
|
||||
|
||||
/* Clean up and exit. */
|
||||
rcu_exp_gp_seq_end(rsp);
|
||||
mutex_unlock(&rnp_unlock->exp_funnel_mutex);
|
||||
/* Wait for ->blkd_tasks lists to drain, then wake everyone up. */
|
||||
rcu_exp_wait_wake(rsp, s);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
|
||||
|
||||
|
||||
@@ -185,17 +185,16 @@ static int show_rcuexp(struct seq_file *m, void *v)
|
||||
int cpu;
|
||||
struct rcu_state *rsp = (struct rcu_state *)m->private;
|
||||
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) {
|
||||
rdp = per_cpu_ptr(rsp->rda, cpu);
|
||||
s0 += atomic_long_read(&rdp->expedited_workdone0);
|
||||
s1 += atomic_long_read(&rdp->expedited_workdone1);
|
||||
s2 += atomic_long_read(&rdp->expedited_workdone2);
|
||||
s3 += atomic_long_read(&rdp->expedited_workdone3);
|
||||
s1 += atomic_long_read(&rdp->exp_workdone1);
|
||||
s2 += atomic_long_read(&rdp->exp_workdone2);
|
||||
s3 += atomic_long_read(&rdp->exp_workdone3);
|
||||
}
|
||||
seq_printf(m, "s=%lu wd0=%lu wd1=%lu wd2=%lu wd3=%lu n=%lu enq=%d sc=%lu\n",
|
||||
rsp->expedited_sequence, s0, s1, s2, s3,
|
||||
seq_printf(m, "s=%lu wd1=%lu wd2=%lu wd3=%lu n=%lu enq=%d sc=%lu\n",
|
||||
rsp->expedited_sequence, s1, s2, s3,
|
||||
atomic_long_read(&rsp->expedited_normal),
|
||||
atomic_read(&rsp->expedited_need_qs),
|
||||
rsp->expedited_sequence / 2);
|
||||
|
||||
+2
-2
@@ -67,7 +67,7 @@ static int rcu_normal_after_boot;
|
||||
module_param(rcu_normal_after_boot, int, 0);
|
||||
#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?
|
||||
*
|
||||
@@ -111,7 +111,7 @@ int rcu_read_lock_sched_held(void)
|
||||
return 0;
|
||||
if (debug_locks)
|
||||
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);
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -451,6 +451,7 @@ static int torture_shutdown(void *arg)
|
||||
torture_shutdown_hook();
|
||||
else
|
||||
VERBOSE_TOROUT_STRING("No torture_shutdown_hook(), skipping.");
|
||||
ftrace_dump(DUMP_ALL);
|
||||
kernel_power_off(); /* Shut down the system. */
|
||||
return 0;
|
||||
}
|
||||
@@ -602,8 +603,9 @@ bool torture_init_begin(char *ttype, bool v, int *runnable)
|
||||
{
|
||||
mutex_lock(&fullstop_mutex);
|
||||
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);
|
||||
pr_alert("torture_init_begin: One torture test at a time!\n");
|
||||
mutex_unlock(&fullstop_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1289,6 +1289,39 @@ config TORTURE_TEST
|
||||
tristate
|
||||
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
|
||||
tristate "torture tests for RCU"
|
||||
depends on DEBUG_KERNEL
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
#!/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
|
||||
@@ -0,0 +1,121 @@
|
||||
#!/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
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/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
|
||||
cat $i/Make.oldconfig.err
|
||||
fi
|
||||
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
|
||||
if test -r $i/Warnings
|
||||
then
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user