Skip to content

Commit bba8d3d

Browse files
committed
Merge branch 'stall.2023.01.09a' into HEAD
stall.2023.01.09a: RCU CPU stall-warning updates.
2 parents 8e1704b + 84ec7c2 commit bba8d3d

File tree

9 files changed

+112
-5
lines changed

9 files changed

+112
-5
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5113,6 +5113,12 @@
51135113
rcupdate.rcu_cpu_stall_timeout to be used (after
51145114
conversion from seconds to milliseconds).
51155115

5116+
rcupdate.rcu_cpu_stall_cputime= [KNL]
5117+
Provide statistics on the cputime and count of
5118+
interrupts and tasks during the sampling period. For
5119+
multiple continuous RCU stalls, all sampling periods
5120+
begin at half of the first RCU stall timeout.
5121+
51165122
rcupdate.rcu_exp_stall_task_details= [KNL]
51175123
Print stack dumps of any tasks blocking the
51185124
current expedited RCU grace period during an

include/linux/kernel_stat.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ DECLARE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
5252
#define kstat_cpu(cpu) per_cpu(kstat, cpu)
5353
#define kcpustat_cpu(cpu) per_cpu(kernel_cpustat, cpu)
5454

55+
extern unsigned long long nr_context_switches_cpu(int cpu);
5556
extern unsigned long long nr_context_switches(void);
5657

5758
extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
@@ -67,6 +68,17 @@ static inline unsigned int kstat_softirqs_cpu(unsigned int irq, int cpu)
6768
return kstat_cpu(cpu).softirqs[irq];
6869
}
6970

71+
static inline unsigned int kstat_cpu_softirqs_sum(int cpu)
72+
{
73+
int i;
74+
unsigned int sum = 0;
75+
76+
for (i = 0; i < NR_SOFTIRQS; i++)
77+
sum += kstat_softirqs_cpu(i, cpu);
78+
79+
return sum;
80+
}
81+
7082
/*
7183
* Number of interrupts per specific IRQ source, since bootup
7284
*/
@@ -75,7 +87,7 @@ extern unsigned int kstat_irqs_usr(unsigned int irq);
7587
/*
7688
* Number of interrupts per cpu, since bootup
7789
*/
78-
static inline unsigned int kstat_cpu_irqs_sum(unsigned int cpu)
90+
static inline unsigned long kstat_cpu_irqs_sum(unsigned int cpu)
7991
{
8092
return kstat_cpu(cpu).irqs_sum;
8193
}

kernel/rcu/Kconfig.debug

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ config RCU_CPU_STALL_TIMEOUT
8282
config RCU_EXP_CPU_STALL_TIMEOUT
8383
int "Expedited RCU CPU stall timeout in milliseconds"
8484
depends on RCU_STALL_COMMON
85-
range 0 21000
85+
range 0 300000
8686
default 0
8787
help
8888
If a given expedited RCU grace period extends more than the
@@ -92,6 +92,19 @@ config RCU_EXP_CPU_STALL_TIMEOUT
9292
says to use the RCU_CPU_STALL_TIMEOUT value converted from
9393
seconds to milliseconds.
9494

95+
config RCU_CPU_STALL_CPUTIME
96+
bool "Provide additional RCU stall debug information"
97+
depends on RCU_STALL_COMMON
98+
default n
99+
help
100+
Collect statistics during the sampling period, such as the number of
101+
(hard interrupts, soft interrupts, task switches) and the cputime of
102+
(hard interrupts, soft interrupts, kernel tasks) are added to the
103+
RCU stall report. For multiple continuous RCU stalls, all sampling
104+
periods begin at half of the first RCU stall timeout.
105+
The boot option rcupdate.rcu_cpu_stall_cputime has the same function
106+
as this one, but will override this if it exists.
107+
95108
config RCU_TRACE
96109
bool "Enable tracing for RCU"
97110
depends on DEBUG_KERNEL

kernel/rcu/rcu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ extern int rcu_cpu_stall_ftrace_dump;
224224
extern int rcu_cpu_stall_suppress;
225225
extern int rcu_cpu_stall_timeout;
226226
extern int rcu_exp_cpu_stall_timeout;
227+
extern int rcu_cpu_stall_cputime;
227228
extern bool rcu_exp_stall_task_details __read_mostly;
228229
int rcu_jiffies_till_stall_check(void);
229230
int rcu_exp_jiffies_till_stall_check(void);

kernel/rcu/tree.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,24 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
866866
rdp->rcu_iw_gp_seq = rnp->gp_seq;
867867
irq_work_queue_on(&rdp->rcu_iw, rdp->cpu);
868868
}
869+
870+
if (rcu_cpu_stall_cputime && rdp->snap_record.gp_seq != rdp->gp_seq) {
871+
int cpu = rdp->cpu;
872+
struct rcu_snap_record *rsrp;
873+
struct kernel_cpustat *kcsp;
874+
875+
kcsp = &kcpustat_cpu(cpu);
876+
877+
rsrp = &rdp->snap_record;
878+
rsrp->cputime_irq = kcpustat_field(kcsp, CPUTIME_IRQ, cpu);
879+
rsrp->cputime_softirq = kcpustat_field(kcsp, CPUTIME_SOFTIRQ, cpu);
880+
rsrp->cputime_system = kcpustat_field(kcsp, CPUTIME_SYSTEM, cpu);
881+
rsrp->nr_hardirqs = kstat_cpu_irqs_sum(rdp->cpu);
882+
rsrp->nr_softirqs = kstat_cpu_softirqs_sum(rdp->cpu);
883+
rsrp->nr_csw = nr_context_switches_cpu(rdp->cpu);
884+
rsrp->jiffies = jiffies;
885+
rsrp->gp_seq = rdp->gp_seq;
886+
}
869887
}
870888

871889
return 0;

kernel/rcu/tree.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,23 @@ union rcu_noqs {
158158
u16 s; /* Set of bits, aggregate OR here. */
159159
};
160160

161+
/*
162+
* Record the snapshot of the core stats at half of the first RCU stall timeout.
163+
* The member gp_seq is used to ensure that all members are updated only once
164+
* during the sampling period. The snapshot is taken only if this gp_seq is not
165+
* equal to rdp->gp_seq.
166+
*/
167+
struct rcu_snap_record {
168+
unsigned long gp_seq; /* Track rdp->gp_seq counter */
169+
u64 cputime_irq; /* Accumulated cputime of hard irqs */
170+
u64 cputime_softirq;/* Accumulated cputime of soft irqs */
171+
u64 cputime_system; /* Accumulated cputime of kernel tasks */
172+
unsigned long nr_hardirqs; /* Accumulated number of hard irqs */
173+
unsigned int nr_softirqs; /* Accumulated number of soft irqs */
174+
unsigned long long nr_csw; /* Accumulated number of task switches */
175+
unsigned long jiffies; /* Track jiffies value */
176+
};
177+
161178
/* Per-CPU data for read-copy update. */
162179
struct rcu_data {
163180
/* 1) quiescent-state and grace-period handling : */
@@ -262,6 +279,8 @@ struct rcu_data {
262279
short rcu_onl_gp_flags; /* ->gp_flags at last online. */
263280
unsigned long last_fqs_resched; /* Time of last rcu_resched(). */
264281
unsigned long last_sched_clock; /* Jiffies of last rcu_sched_clock_irq(). */
282+
struct rcu_snap_record snap_record; /* Snapshot of core stats at half of */
283+
/* the first RCU stall timeout */
265284

266285
long lazy_len; /* Length of buffered lazy callbacks. */
267286
int cpu;

kernel/rcu/tree_stall.h

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ int rcu_exp_jiffies_till_stall_check(void)
3939
// CONFIG_RCU_EXP_CPU_STALL_TIMEOUT, so check the allowed range.
4040
// The minimum clamped value is "2UL", because at least one full
4141
// tick has to be guaranteed.
42-
till_stall_check = clamp(msecs_to_jiffies(cpu_stall_timeout), 2UL, 21UL * HZ);
42+
till_stall_check = clamp(msecs_to_jiffies(cpu_stall_timeout), 2UL, 300UL * HZ);
4343

4444
if (cpu_stall_timeout && jiffies_to_msecs(till_stall_check) != cpu_stall_timeout)
4545
WRITE_ONCE(rcu_exp_cpu_stall_timeout, jiffies_to_msecs(till_stall_check));
@@ -428,6 +428,35 @@ static bool rcu_is_rcuc_kthread_starving(struct rcu_data *rdp, unsigned long *jp
428428
return j > 2 * HZ;
429429
}
430430

431+
static void print_cpu_stat_info(int cpu)
432+
{
433+
struct rcu_snap_record rsr, *rsrp;
434+
struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
435+
struct kernel_cpustat *kcsp = &kcpustat_cpu(cpu);
436+
437+
if (!rcu_cpu_stall_cputime)
438+
return;
439+
440+
rsrp = &rdp->snap_record;
441+
if (rsrp->gp_seq != rdp->gp_seq)
442+
return;
443+
444+
rsr.cputime_irq = kcpustat_field(kcsp, CPUTIME_IRQ, cpu);
445+
rsr.cputime_softirq = kcpustat_field(kcsp, CPUTIME_SOFTIRQ, cpu);
446+
rsr.cputime_system = kcpustat_field(kcsp, CPUTIME_SYSTEM, cpu);
447+
448+
pr_err("\t hardirqs softirqs csw/system\n");
449+
pr_err("\t number: %8ld %10d %12lld\n",
450+
kstat_cpu_irqs_sum(cpu) - rsrp->nr_hardirqs,
451+
kstat_cpu_softirqs_sum(cpu) - rsrp->nr_softirqs,
452+
nr_context_switches_cpu(cpu) - rsrp->nr_csw);
453+
pr_err("\tcputime: %8lld %10lld %12lld ==> %d(ms)\n",
454+
div_u64(rsr.cputime_irq - rsrp->cputime_irq, NSEC_PER_MSEC),
455+
div_u64(rsr.cputime_softirq - rsrp->cputime_softirq, NSEC_PER_MSEC),
456+
div_u64(rsr.cputime_system - rsrp->cputime_system, NSEC_PER_MSEC),
457+
jiffies_to_msecs(jiffies - rsrp->jiffies));
458+
}
459+
431460
/*
432461
* Print out diagnostic information for the specified stalled CPU.
433462
*
@@ -484,6 +513,8 @@ static void print_cpu_stall_info(int cpu)
484513
data_race(rcu_state.n_force_qs) - rcu_state.n_force_qs_gpstart,
485514
rcuc_starved ? buf : "",
486515
falsepositive ? " (false positive?)" : "");
516+
517+
print_cpu_stat_info(cpu);
487518
}
488519

489520
/* Complain about starvation of grace-period kthread. */
@@ -588,7 +619,7 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
588619

589620
for_each_possible_cpu(cpu)
590621
totqlen += rcu_get_n_cbs_cpu(cpu);
591-
pr_cont("\t(detected by %d, t=%ld jiffies, g=%ld, q=%lu ncpus=%d)\n",
622+
pr_err("\t(detected by %d, t=%ld jiffies, g=%ld, q=%lu ncpus=%d)\n",
592623
smp_processor_id(), (long)(jiffies - gps),
593624
(long)rcu_seq_current(&rcu_state.gp_seq), totqlen, rcu_state.n_online_cpus);
594625
if (ndetected) {
@@ -649,7 +680,7 @@ static void print_cpu_stall(unsigned long gps)
649680
raw_spin_unlock_irqrestore_rcu_node(rdp->mynode, flags);
650681
for_each_possible_cpu(cpu)
651682
totqlen += rcu_get_n_cbs_cpu(cpu);
652-
pr_cont("\t(t=%lu jiffies g=%ld q=%lu ncpus=%d)\n",
683+
pr_err("\t(t=%lu jiffies g=%ld q=%lu ncpus=%d)\n",
653684
jiffies - gps,
654685
(long)rcu_seq_current(&rcu_state.gp_seq), totqlen, rcu_state.n_online_cpus);
655686

kernel/rcu/update.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,8 @@ int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
547547
module_param(rcu_cpu_stall_timeout, int, 0644);
548548
int rcu_exp_cpu_stall_timeout __read_mostly = CONFIG_RCU_EXP_CPU_STALL_TIMEOUT;
549549
module_param(rcu_exp_cpu_stall_timeout, int, 0644);
550+
int rcu_cpu_stall_cputime __read_mostly = IS_ENABLED(CONFIG_RCU_CPU_STALL_CPUTIME);
551+
module_param(rcu_cpu_stall_cputime, int, 0644);
550552
bool rcu_exp_stall_task_details __read_mostly;
551553
module_param(rcu_exp_stall_task_details, bool, 0644);
552554
#endif /* #ifdef CONFIG_RCU_STALL_COMMON */

kernel/sched/core.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5282,6 +5282,11 @@ bool single_task_running(void)
52825282
}
52835283
EXPORT_SYMBOL(single_task_running);
52845284

5285+
unsigned long long nr_context_switches_cpu(int cpu)
5286+
{
5287+
return cpu_rq(cpu)->nr_switches;
5288+
}
5289+
52855290
unsigned long long nr_context_switches(void)
52865291
{
52875292
int i;

0 commit comments

Comments
 (0)