u64 time = sample->time;
struct perf_time_interval *ptime = &kwork->ptime;
- if ((kwork->cpu_list != NULL) && !test_bit(cpu, kwork->cpu_bitmap))
+ /* Guard test_bit: cpu == -1 (absent PERF_SAMPLE_CPU) would index past the bitmap */
+ if ((kwork->cpu_list != NULL) &&
+ ((unsigned int)cpu >= MAX_NR_CPUS || !test_bit(cpu, kwork->cpu_bitmap)))
return false;
if (((ptime->start != 0) && (ptime->start > time)) ||
next = rb_first_cached(&class->work_root);
while (next) {
work = rb_entry(next, struct kwork_work, node);
- BUG_ON(work->cpu >= MAX_NR_CPUS);
+ /*
+ * work->cpu comes from sample->cpu which is -1 when
+ * PERF_SAMPLE_CPU is absent. As int that's -1, but as
+ * unsigned it exceeds MAX_NR_CPUS — skip to avoid OOB
+ * on cpus_runtime[].
+ */
+ /* Counted and reported in perf_kwork__top_report() */
+ if ((unsigned int)work->cpu >= MAX_NR_CPUS) {
+ stat->nr_skipped_cpu++;
+ next = rb_next(next);
+ continue;
+ }
stat->cpus_runtime[work->cpu].total += work->total_runtime;
stat->cpus_runtime[MAX_NR_CPUS].total += work->total_runtime;
next = rb_next(next);
{
struct kwork_top_stat *stat = &kwork->top_stat;
- if (work->id == 0) {
+ /* See comment in top_calc_total_runtime() */
+ if (work->id == 0 && (unsigned int)work->cpu < MAX_NR_CPUS) {
stat->cpus_runtime[work->cpu].idle += work->total_runtime;
stat->cpus_runtime[MAX_NR_CPUS].idle += work->total_runtime;
}
{
struct kwork_top_stat *stat = &kwork->top_stat;
+ /* See comment in top_calc_total_runtime() */
+ if ((unsigned int)work->cpu >= MAX_NR_CPUS)
+ return;
+
if (type == KWORK_CLASS_IRQ) {
stat->cpus_runtime[work->cpu].irq += work->total_runtime;
stat->cpus_runtime[MAX_NR_CPUS].irq += work->total_runtime;
if (work->total_runtime == 0)
goto next;
+ /* See comment in top_calc_total_runtime() */
+ if ((unsigned int)work->cpu >= MAX_NR_CPUS)
+ goto next;
+
__set_bit(work->cpu, stat->all_cpus_bitmap);
top_subtract_irq_runtime(kwork, work);
- work->cpu_usage = work->total_runtime * 10000 /
- stat->cpus_runtime[work->cpu].total;
+ /* Guard against division by zero if no runtime was accumulated */
+ if (stat->cpus_runtime[work->cpu].total) {
+ work->cpu_usage = work->total_runtime * 10000 /
+ stat->cpus_runtime[work->cpu].total;
+ }
top_calc_idle_time(kwork, work);
next:
{
struct kwork_top_stat *stat = &kwork->top_stat;
- if (work->id != 0) {
+ /* See comment in top_calc_total_runtime() */
+ if (work->id != 0 && (unsigned int)work->cpu < MAX_NR_CPUS) {
stat->cpus_runtime[work->cpu].load += work->total_runtime;
stat->cpus_runtime[MAX_NR_CPUS].load += work->total_runtime;
}
next = rb_next(next);
}
+ if (kwork->top_stat.nr_skipped_cpu) {
+ printf(" Warning: %u work entries with invalid CPU were excluded from totals.\n"
+ " Task runtimes may appear inflated (IRQ time not subtracted).\n"
+ " Consider re-recording with PERF_SAMPLE_CPU enabled.\n",
+ kwork->top_stat.nr_skipped_cpu);
+ }
+
printf("\n");
}