mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Ian Rogers <irogers@google.com>
To: Peter Zijlstra <peterz@infradead.org>,
	Ingo Molnar <mingo@redhat.com>,
	 Arnaldo Carvalho de Melo <acme@kernel.org>,
	Namhyung Kim <namhyung@kernel.org>, Jiri Olsa <jolsa@kernel.org>,
	 Ian Rogers <irogers@google.com>,
	Adrian Hunter <adrian.hunter@intel.com>,
	 James Clark <james.clark@linaro.org>,
	Thomas Falcon <thomas.falcon@intel.com>,
	 Thomas Richter <tmricht@linux.ibm.com>,
	linux-perf-users@vger.kernel.org,  linux-kernel@vger.kernel.org
Cc: Andi Kleen <ak@linux.intel.com>
Subject: [PATCH v2 3/4] perf tool_pmu: Add schedstat events
Date: Fri, 13 Nov 2026 15:37:38 -0800	[thread overview]
Message-ID: <20261113233739.3626499-4-irogers@google.com> (raw)
In-Reply-To: <20261113233739.3626499-1-irogers@google.com>

Add per-CPU tool PMU events backed by /proc/schedstat runqueue
statistics:
- schedstat_yield: Calls to sched_yield().
- schedstat_schedule: Calls to schedule().
- schedstat_schedule_idle: Calls to schedule() leaving the CPU idle.
- schedstat_wake: Calls to try_to_wake_up().
- schedstat_wake_local: Calls to try_to_wake_up() for the local CPU.
- schedstat_runtime: Task runtime on this CPU in nanoseconds.
- schedstat_wait: Task runqueue wait time on this CPU in nanoseconds.
- schedstat_timeslices: Number of timeslices run on this CPU.

Because /proc/schedstat reports per-CPU runqueue counters, reject
per-process and cgroup modes, exclude schedstat events from
perf_pmu__reads_only_on_cpu_idx0(), and update should_skip_zero_counter()
so zero-valued per-CPU tool events are not suppressed on CPUs > 0. Track
initial and accumulated values across enable/disable transitions to
report deltas over the measurement interval.

Example system-wide and per-CPU output:

  $ perf stat -a -e schedstat_yield,schedstat_schedule \
      -e schedstat_runtime,schedstat_wait,schedstat_timeslices sleep 0.1

   Performance counter stats for 'system wide':

                   0      schedstat_yield
                   0      schedstat_schedule
         455,566,105      schedstat_runtime
             348,262      schedstat_wait
              63,336      schedstat_timeslices

         0.112807668 seconds time elapsed

  $ perf stat -A -C 0,1 -e schedstat_schedule,schedstat_runtime \
      -e schedstat_wait,schedstat_timeslices sleep 0.1

   Performance counter stats for 'CPU(s) 0,1':

  CPU0                    0      tool/schedstat_schedule/
  CPU1                    0      tool/schedstat_schedule/
  CPU0            6,217,341      tool/schedstat_runtime/
  CPU1           25,243,949      tool/schedstat_runtime/
  CPU0               11,005      tool/schedstat_wait/
  CPU1               20,921      tool/schedstat_wait/
  CPU0                  115      tool/schedstat_timeslices/
  CPU1                3,535      tool/schedstat_timeslices/

         0.101808548 seconds time elapsed

Signed-off-by: Ian Rogers <irogers@google.com>
---
 .../pmu-events/arch/common/common/tool.json   |  48 ++++
 tools/perf/pmu-events/empty-pmu-events.c      | 254 ++++++++++--------
 tools/perf/util/pmu.c                         |   4 +-
 tools/perf/util/stat-display.c                |   8 +-
 tools/perf/util/tool_pmu.c                    | 133 ++++++++-
 tools/perf/util/tool_pmu.h                    |   9 +
 6 files changed, 340 insertions(+), 116 deletions(-)

diff --git a/tools/perf/pmu-events/arch/common/common/tool.json b/tools/perf/pmu-events/arch/common/common/tool.json
index a332cbf842f7..7c6e03055ca3 100644
--- a/tools/perf/pmu-events/arch/common/common/tool.json
+++ b/tools/perf/pmu-events/arch/common/common/tool.json
@@ -334,5 +334,53 @@
     "EventName": "net_tx_compressed",
     "BriefDescription": "System-wide network transmitted compressed packets",
     "ConfigCode": "56"
+  },
+  {
+    "Unit": "tool",
+    "EventName": "schedstat_yield",
+    "BriefDescription": "Number of times sched_yield() was called",
+    "ConfigCode": "57"
+  },
+  {
+    "Unit": "tool",
+    "EventName": "schedstat_schedule",
+    "BriefDescription": "Number of times schedule() was called",
+    "ConfigCode": "58"
+  },
+  {
+    "Unit": "tool",
+    "EventName": "schedstat_schedule_idle",
+    "BriefDescription": "Number of times schedule() left the processor idle",
+    "ConfigCode": "59"
+  },
+  {
+    "Unit": "tool",
+    "EventName": "schedstat_wake",
+    "BriefDescription": "Number of times try_to_wake_up() was called",
+    "ConfigCode": "60"
+  },
+  {
+    "Unit": "tool",
+    "EventName": "schedstat_wake_local",
+    "BriefDescription": "Number of times try_to_wake_up() was called to wake up the local cpu",
+    "ConfigCode": "61"
+  },
+  {
+    "Unit": "tool",
+    "EventName": "schedstat_runtime",
+    "BriefDescription": "Sum of all time spent running by tasks on this processor (in nanoseconds)",
+    "ConfigCode": "62"
+  },
+  {
+    "Unit": "tool",
+    "EventName": "schedstat_wait",
+    "BriefDescription": "Sum of all time spent waiting to run by tasks on this processor (in nanoseconds)",
+    "ConfigCode": "63"
+  },
+  {
+    "Unit": "tool",
+    "EventName": "schedstat_timeslices",
+    "BriefDescription": "Number of timeslices run on this cpu",
+    "ConfigCode": "64"
   }
 ]
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 8705f32563a6..49e2d3f8b3f1 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -2628,116 +2628,132 @@ static const char *const big_c_string =
 /* offset=130002 */
 "net_tx_compressed\000tool\000System-wide network transmitted compressed packets\000config=0x38\000\00000\000\000\000\000\000"
 /* offset=130096 */
+"schedstat_yield\000tool\000Number of times sched_yield() was called\000config=0x39\000\00000\000\000\000\000\000"
+/* offset=130178 */
+"schedstat_schedule\000tool\000Number of times schedule() was called\000config=0x3a\000\00000\000\000\000\000\000"
+/* offset=130260 */
+"schedstat_schedule_idle\000tool\000Number of times schedule() left the processor idle\000config=0x3b\000\00000\000\000\000\000\000"
+/* offset=130360 */
+"schedstat_wake\000tool\000Number of times try_to_wake_up() was called\000config=0x3c\000\00000\000\000\000\000\000"
+/* offset=130444 */
+"schedstat_wake_local\000tool\000Number of times try_to_wake_up() was called to wake up the local cpu\000config=0x3d\000\00000\000\000\000\000\000"
+/* offset=130559 */
+"schedstat_runtime\000tool\000Sum of all time spent running by tasks on this processor (in nanoseconds)\000config=0x3e\000\00000\000\000\000\000\000"
+/* offset=130676 */
+"schedstat_wait\000tool\000Sum of all time spent waiting to run by tasks on this processor (in nanoseconds)\000config=0x3f\000\00000\000\000\000\000\000"
+/* offset=130797 */
+"schedstat_timeslices\000tool\000Number of timeslices run on this cpu\000config=0x40\000\00000\000\000\000\000\000"
+/* offset=130880 */
 "bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000\000\000\000"
-/* offset=130158 */
+/* offset=130942 */
 "bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000\000\000\000"
-/* offset=130220 */
+/* offset=131004 */
 "l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000\000\000\000Attributable Level 3 cache access, read\000"
-/* offset=130318 */
+/* offset=131102 */
 "segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000\000\000\000"
-/* offset=130420 */
+/* offset=131204 */
 "dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000\000\000\000"
-/* offset=130553 */
+/* offset=131337 */
 "eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000\000\000\000"
-/* offset=130671 */
+/* offset=131455 */
 "hisi_sccl,ddrc\000"
-/* offset=130686 */
+/* offset=131470 */
 "uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000\000\000\000\000"
-/* offset=130756 */
+/* offset=131540 */
 "uncore_cbox\000"
-/* offset=130768 */
+/* offset=131552 */
 "unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000\000\000\000\000"
-/* offset=130922 */
+/* offset=131706 */
 "event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000\000\000\000\000"
-/* offset=130976 */
+/* offset=131760 */
 "event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000\000\000\000\000"
-/* offset=131034 */
+/* offset=131818 */
 "hisi_sccl,l3c\000"
-/* offset=131048 */
+/* offset=131832 */
 "uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000\000\000\000\000"
-/* offset=131116 */
+/* offset=131900 */
 "uncore_imc_free_running\000"
-/* offset=131140 */
+/* offset=131924 */
 "uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000\000\000\000\000"
-/* offset=131220 */
+/* offset=132004 */
 "uncore_imc\000"
-/* offset=131231 */
+/* offset=132015 */
 "uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000\000\000\000\000"
-/* offset=131296 */
+/* offset=132080 */
 "uncore_sys_ddr_pmu\000"
-/* offset=131315 */
+/* offset=132099 */
 "sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000\000\000\000"
-/* offset=131391 */
+/* offset=132175 */
 "uncore_sys_ccn_pmu\000"
-/* offset=131410 */
+/* offset=132194 */
 "sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000\000\000\000"
-/* offset=131487 */
+/* offset=132271 */
 "uncore_sys_cmn_pmu\000"
-/* offset=131506 */
+/* offset=132290 */
 "sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000\000\000\000"
-/* offset=131649 */
+/* offset=132433 */
 "CPUs_utilized\000Default\000(software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@) / (duration_time * 1e9)\000\000Average CPU utilization\000\0001CPUs\000\000\000\000011"
-/* offset=131835 */
+/* offset=132619 */
 "cs_per_second\000Default\000software@context\\-switches\\,name\\=context\\-switches@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Context switches per CPU second\000\0001cs/sec\000\000\000\000011"
-/* offset=132068 */
+/* offset=132852 */
 "migrations_per_second\000Default\000software@cpu\\-migrations\\,name\\=cpu\\-migrations@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Process migrations to a new CPU per CPU second\000\0001migrations/sec\000\000\000\000011"
-/* offset=132328 */
+/* offset=133112 */
 "page_faults_per_second\000Default\000software@page\\-faults\\,name\\=page\\-faults@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Page faults per CPU second\000\0001faults/sec\000\000\000\000011"
-/* offset=132559 */
+/* offset=133343 */
 "insn_per_cycle\000Default\000instructions / cpu\\-cycles\000insn_per_cycle < 1\000Instructions Per Cycle\000\0001instructions\000\000\000\000001"
-/* offset=132672 */
+/* offset=133456 */
 "stalled_cycles_per_instruction\000Default\000(max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions if has_event(stalled\\-cycles\\-frontend) & has_event(stalled\\-cycles\\-backend) else (stalled\\-cycles\\-frontend / instructions if has_event(stalled\\-cycles\\-frontend) else (stalled\\-cycles\\-backend / instructions if has_event(stalled\\-cycles\\-backend) else 0)))\000\000Max front or backend stalls per instruction\000\000\000\000\000\000001"
-/* offset=133097 */
+/* offset=133881 */
 "frontend_cycles_idle\000Default\000(stalled\\-cycles\\-frontend / cpu\\-cycles if has_event(stalled\\-cycles\\-frontend) else 0)\000frontend_cycles_idle > 0.1\000Frontend stalls per cycle\000\000\000\000\000\000001"
-/* offset=133276 */
+/* offset=134060 */
 "backend_cycles_idle\000Default\000(stalled\\-cycles\\-backend / cpu\\-cycles if has_event(stalled\\-cycles\\-backend) else 0)\000backend_cycles_idle > 0.2\000Backend stalls per cycle\000\000\000\000\000\000001"
-/* offset=133450 */
+/* offset=134234 */
 "cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Cycles per CPU second\000\0001GHz\000\000\000\000011"
-/* offset=133626 */
+/* offset=134410 */
 "branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Branches per CPU second\000\0001000M/sec\000\000\000\000011"
-/* offset=133806 */
+/* offset=134590 */
 "branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > 0.05\000Branch miss rate\000\000100%\000\000\000\000001"
-/* offset=133910 */
+/* offset=134694 */
 "l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\000l1d_miss_rate > 0.05\000L1D  miss rate\000\000100%\000\000\000\000001"
-/* offset=134026 */
+/* offset=134810 */
 "llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate > 0.05\000LLC miss rate\000\000100%\000\000\000\000001"
-/* offset=134127 */
+/* offset=134911 */
 "l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\000l1i_miss_rate > 0.05\000L1I miss rate\000\000100%\000\000\000\000001"
-/* offset=134242 */
+/* offset=135026 */
 "dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_rate > 0.05\000dTLB miss rate\000\000100%\000\000\000\000001"
-/* offset=134348 */
+/* offset=135132 */
 "itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_rate > 0.05\000iTLB miss rate\000\000100%\000\000\000\000001"
-/* offset=134454 */
+/* offset=135238 */
 "l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcache\\-prefetches\000l1_prefetch_miss_rate > 0.05\000L1 prefetch miss rate\000\000100%\000\000\000\000001"
-/* offset=134602 */
+/* offset=135386 */
 "CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000"
-/* offset=134625 */
+/* offset=135409 */
 "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\000000"
-/* offset=134689 */
+/* offset=135473 */
 "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\000000"
-/* offset=134856 */
+/* offset=135640 */
 "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000"
-/* offset=134921 */
+/* offset=135705 */
 "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000"
-/* offset=134989 */
+/* offset=135773 */
 "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\000000"
-/* offset=135061 */
+/* offset=135845 */
 "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\000000"
-/* offset=135156 */
+/* offset=135940 */
 "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\000000"
-/* offset=135291 */
+/* offset=136075 */
 "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\000000"
-/* offset=135356 */
+/* offset=136140 */
 "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\000000"
-/* offset=135425 */
+/* offset=136209 */
 "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\000000"
-/* offset=135496 */
+/* offset=136280 */
 "M1\000\000ipc + M2\000\000\000\000\000\000\000\000000"
-/* offset=135519 */
+/* offset=136303 */
 "M2\000\000ipc + M1\000\000\000\000\000\000\000\000000"
-/* offset=135542 */
+/* offset=136326 */
 "M3\000\0001 / M3\000\000\000\000\000\000\000\000000"
-/* offset=135563 */
+/* offset=136347 */
 "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\000000"
 ;
 
@@ -5336,6 +5352,22 @@ static const struct compact_pmu_event pmu_events__common_tool[] = {
 	{ 125728 },
 	/* num_packages\000tool\000Number of packages. Each package has 1 or more die\000co... */
 	{ 125804 },
+	/* schedstat_runtime\000tool\000Sum of all time spent running by tasks on this proc... */
+	{ 130559 },
+	/* schedstat_schedule\000tool\000Number of times schedule() was called\000config=0x... */
+	{ 130178 },
+	/* schedstat_schedule_idle\000tool\000Number of times schedule() left the processor... */
+	{ 130260 },
+	/* schedstat_timeslices\000tool\000Number of timeslices run on this cpu\000config=0... */
+	{ 130797 },
+	/* schedstat_wait\000tool\000Sum of all time spent waiting to run by tasks on this ... */
+	{ 130676 },
+	/* schedstat_wake\000tool\000Number of times try_to_wake_up() was called\000config=... */
+	{ 130360 },
+	/* schedstat_wake_local\000tool\000Number of times try_to_wake_up() was called to w... */
+	{ 130444 },
+	/* schedstat_yield\000tool\000Number of times sched_yield() was called\000config=0x... */
+	{ 130096 },
 	/* slots\000tool\000Number of functional units that in parallel can execute parts o... */
 	{ 125890 },
 	/* smt_on\000tool\0001 if simultaneous multithreading (aka hyperthreading) is enabl... */
@@ -5371,39 +5403,39 @@ static const struct pmu_table_entry pmu_events__common[] = {
 
 static const struct compact_pmu_event pmu_metrics__common_default_core[] = {
 	/* CPUs_utilized\000Default\000(software@cpu\\-clock\\,name\\=cpu\\-clock@ if #targ... */
-	{ 131649 },
+	{ 132433 },
 	/* backend_cycles_idle\000Default\000(stalled\\-cycles\\-backend / cpu\\-cycles if ... */
-	{ 133276 },
+	{ 134060 },
 	/* branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-c... */
-	{ 133626 },
+	{ 134410 },
 	/* branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > ... */
-	{ 133806 },
+	{ 134590 },
 	/* cs_per_second\000Default\000software@context\\-switches\\,name\\=context\\-switc... */
-	{ 131835 },
+	{ 132619 },
 	/* cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu... */
-	{ 133450 },
+	{ 134234 },
 	/* dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_r... */
-	{ 134242 },
+	{ 135026 },
 	/* frontend_cycles_idle\000Default\000(stalled\\-cycles\\-frontend / cpu\\-cycles i... */
-	{ 133097 },
+	{ 133881 },
 	/* insn_per_cycle\000Default\000instructions / cpu\\-cycles\000insn_per_cycle < 1\0... */
-	{ 132559 },
+	{ 133343 },
 	/* itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_r... */
-	{ 134348 },
+	{ 135132 },
 	/* l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcac... */
-	{ 134454 },
+	{ 135238 },
 	/* l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\0... */
-	{ 133910 },
+	{ 134694 },
 	/* l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\0... */
-	{ 134127 },
+	{ 134911 },
 	/* llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate ... */
-	{ 134026 },
+	{ 134810 },
 	/* migrations_per_second\000Default\000software@cpu\\-migrations\\,name\\=cpu\\-mig... */
-	{ 132068 },
+	{ 132852 },
 	/* page_faults_per_second\000Default\000software@page\\-faults\\,name\\=page\\-faul... */
-	{ 132328 },
+	{ 133112 },
 	/* stalled_cycles_per_instruction\000Default\000(max(stalled\\-cycles\\-frontend, s... */
-	{ 132672 },
+	{ 133456 },
 
 };
 
@@ -5417,41 +5449,41 @@ static const struct pmu_table_entry pmu_metrics__common[] = {
 
 static const struct compact_pmu_event pmu_events__test_soc_cpu_default_core[] = {
 	/* bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000... */
-	{ 130096 },
+	{ 130880 },
 	/* bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000... */
-	{ 130158 },
+	{ 130942 },
 	/* dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispat... */
-	{ 130420 },
+	{ 131204 },
 	/* eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) t... */
-	{ 130553 },
+	{ 131337 },
 	/* l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000\000\00... */
-	{ 130220 },
+	{ 131004 },
 	/* segment_reg_loads.any\000other\000Number of segment register loads\000event=6,pe... */
-	{ 130318 },
+	{ 131102 },
 };
 static const struct compact_pmu_event pmu_events__test_soc_cpu_hisi_sccl_ddrc[] = {
 	/* uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000... */
-	{ 130686 },
+	{ 131470 },
 };
 static const struct compact_pmu_event pmu_events__test_soc_cpu_hisi_sccl_l3c[] = {
 	/* uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\0... */
-	{ 131048 },
+	{ 131832 },
 };
 static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_cbox[] = {
 	/* event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000\000\000\000... */
-	{ 130922 },
+	{ 131706 },
 	/* event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000\000\000... */
-	{ 130976 },
+	{ 131760 },
 	/* unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted fro... */
-	{ 130768 },
+	{ 131552 },
 };
 static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_imc[] = {
 	/* uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000\... */
-	{ 131231 },
+	{ 132015 },
 };
 static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_imc_free_running[] = {
 	/* uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12... */
-	{ 131140 },
+	{ 131924 },
 
 };
 
@@ -5464,61 +5496,61 @@ static const struct pmu_table_entry pmu_events__test_soc_cpu[] = {
 	{
 		.entries = pmu_events__test_soc_cpu_hisi_sccl_ddrc,
 		.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_hisi_sccl_ddrc),
-		.pmu_name = { 130671 /* hisi_sccl,ddrc\000 */ },
+		.pmu_name = { 131455 /* hisi_sccl,ddrc\000 */ },
 	},
 	{
 		.entries = pmu_events__test_soc_cpu_hisi_sccl_l3c,
 		.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_hisi_sccl_l3c),
-		.pmu_name = { 131034 /* hisi_sccl,l3c\000 */ },
+		.pmu_name = { 131818 /* hisi_sccl,l3c\000 */ },
 	},
 	{
 		.entries = pmu_events__test_soc_cpu_uncore_cbox,
 		.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_cbox),
-		.pmu_name = { 130756 /* uncore_cbox\000 */ },
+		.pmu_name = { 131540 /* uncore_cbox\000 */ },
 	},
 	{
 		.entries = pmu_events__test_soc_cpu_uncore_imc,
 		.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_imc),
-		.pmu_name = { 131220 /* uncore_imc\000 */ },
+		.pmu_name = { 132004 /* uncore_imc\000 */ },
 	},
 	{
 		.entries = pmu_events__test_soc_cpu_uncore_imc_free_running,
 		.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_imc_free_running),
-		.pmu_name = { 131116 /* uncore_imc_free_running\000 */ },
+		.pmu_name = { 131900 /* uncore_imc_free_running\000 */ },
 	},
 };
 
 static const struct compact_pmu_event pmu_metrics__test_soc_cpu_default_core[] = {
 	/* CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000 */
-	{ 134602 },
+	{ 135386 },
 	/* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000... */
-	{ 135291 },
+	{ 136075 },
 	/* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqs... */
-	{ 135061 },
+	{ 135845 },
 	/* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data... */
-	{ 135156 },
+	{ 135940 },
 	/* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000... */
-	{ 135356 },
+	{ 136140 },
 	/* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\0... */
-	{ 135425 },
+	{ 136209 },
 	/* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.t... */
-	{ 134689 },
+	{ 135473 },
 	/* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\... */
-	{ 134625 },
+	{ 135409 },
 	/* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\... */
-	{ 135563 },
+	{ 136347 },
 	/* M1\000\000ipc + M2\000\000\000\000\000\000\000\000000 */
-	{ 135496 },
+	{ 136280 },
 	/* M2\000\000ipc + M1\000\000\000\000\000\000\000\000000 */
-	{ 135519 },
+	{ 136303 },
 	/* M3\000\0001 / M3\000\000\000\000\000\000\000\000000 */
-	{ 135542 },
+	{ 136326 },
 	/* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\... */
-	{ 134989 },
+	{ 135773 },
 	/* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\0... */
-	{ 134856 },
+	{ 135640 },
 	/* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\00... */
-	{ 134921 },
+	{ 135705 },
 
 };
 
@@ -5532,15 +5564,15 @@ static const struct pmu_table_entry pmu_metrics__test_soc_cpu[] = {
 
 static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_ccn_pmu[] = {
 	/* sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x0... */
-	{ 131410 },
+	{ 132194 },
 };
 static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_cmn_pmu[] = {
 	/* sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first looku... */
-	{ 131506 },
+	{ 132290 },
 };
 static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_ddr_pmu[] = {
 	/* sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8... */
-	{ 131315 },
+	{ 132099 },
 
 };
 
@@ -5548,17 +5580,17 @@ static const struct pmu_table_entry pmu_events__test_soc_sys[] = {
 	{
 		.entries = pmu_events__test_soc_sys_uncore_sys_ccn_pmu,
 		.num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_ccn_pmu),
-		.pmu_name = { 131391 /* uncore_sys_ccn_pmu\000 */ },
+		.pmu_name = { 132175 /* uncore_sys_ccn_pmu\000 */ },
 	},
 	{
 		.entries = pmu_events__test_soc_sys_uncore_sys_cmn_pmu,
 		.num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_cmn_pmu),
-		.pmu_name = { 131487 /* uncore_sys_cmn_pmu\000 */ },
+		.pmu_name = { 132271 /* uncore_sys_cmn_pmu\000 */ },
 	},
 	{
 		.entries = pmu_events__test_soc_sys_uncore_sys_ddr_pmu,
 		.num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_ddr_pmu),
-		.pmu_name = { 131296 /* uncore_sys_ddr_pmu\000 */ },
+		.pmu_name = { 132080 /* uncore_sys_ddr_pmu\000 */ },
 	},
 };
 
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 01753d5c69d1..f4560a0ec1db 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -2830,5 +2830,7 @@ bool perf_pmu__reads_only_on_cpu_idx0(const struct perf_event_attr *attr)
 		return false;
 
 	event = (enum tool_pmu_event)attr->config;
-	return event != TOOL_PMU__EVENT_USER_TIME && event != TOOL_PMU__EVENT_SYSTEM_TIME;
+	return event != TOOL_PMU__EVENT_USER_TIME &&
+	       event != TOOL_PMU__EVENT_SYSTEM_TIME &&
+	       !tool_pmu__is_sched_stat_event(event);
 }
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
index b337cc23f413..6671403c587c 100644
--- a/tools/perf/util/stat-display.c
+++ b/tools/perf/util/stat-display.c
@@ -929,9 +929,13 @@ static bool should_skip_zero_counter(struct perf_stat_config *config,
 	 * system_time, but for many the first index is the only one used, for
 	 * example num_cores. Don't skip for the first index.
 	 */
-	if (evsel__is_tool(counter)) {
+	if (evsel__is_tool(counter) &&
+	    (counter->core.reads_only_on_cpu_idx0 || counter->pid_stat)) {
+		struct perf_cpu first_cpu = perf_cpu_map__cpu(counter->core.cpus, 0);
 		struct aggr_cpu_id own_id =
-			config->aggr_get_id(config, (struct perf_cpu){ .cpu = 0 });
+			config->aggr_get_id(config,
+					    first_cpu.cpu >= 0 ? first_cpu
+							       : (struct perf_cpu){ .cpu = 0 });
 
 		return !aggr_cpu_id__equal(id, &own_id);
 	}
diff --git a/tools/perf/util/tool_pmu.c b/tools/perf/util/tool_pmu.c
index 655b22104320..b92aaf0d7671 100644
--- a/tools/perf/util/tool_pmu.c
+++ b/tools/perf/util/tool_pmu.c
@@ -84,6 +84,14 @@ static const char *const tool_pmu__event_names[TOOL_PMU__EVENT_MAX] = {
 	"net_tx_colls",
 	"net_tx_carrier",
 	"net_tx_compressed",
+	"schedstat_yield",
+	"schedstat_schedule",
+	"schedstat_schedule_idle",
+	"schedstat_wake",
+	"schedstat_wake_local",
+	"schedstat_runtime",
+	"schedstat_wait",
+	"schedstat_timeslices",
 };
 
 bool tool_pmu__skip_event(const char *name __maybe_unused)
@@ -205,6 +213,83 @@ static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val)
 	return -EINVAL;
 }
 
+bool tool_pmu__is_sched_stat_event(enum tool_pmu_event ev)
+{
+	return ev >= TOOL_PMU__EVENT_SCHEDSTAT_YIELD &&
+	       ev <= TOOL_PMU__EVENT_SCHEDSTAT_TIMESLICES;
+}
+
+static int sched_stat_event_to_field(enum tool_pmu_event ev)
+{
+	if (!tool_pmu__is_sched_stat_event(ev))
+		return -EINVAL;
+	if (ev == TOOL_PMU__EVENT_SCHEDSTAT_YIELD)
+		return 1;
+	/* Field 2 is legacy 0 in /proc/schedstat v15+. */
+	return (ev - TOOL_PMU__EVENT_SCHEDSTAT_YIELD) + 2;
+}
+
+static int read_sched_stat(int fd, struct perf_cpu cpu, enum tool_pmu_event ev, __u64 *val)
+{
+	int field = sched_stat_event_to_field(ev);
+	char buf[4096];
+	struct io io;
+	int ch;
+
+	if (field < 0)
+		return field;
+
+	io__init(&io, fd, buf, sizeof(buf));
+	lseek(fd, 0, SEEK_SET);
+
+	/* Search for "cpu<N> " */
+	while ((ch = io__get_char(&io)) != -1) {
+		__u64 cpu_num;
+		int i = 1, c;
+
+		if (ch != 'c') {
+			if (ch != '\n')
+				read_until_char(&io, '\n');
+			continue;
+		}
+		c = io__get_char(&io);
+		if (c != 'p') {
+			if (c != '\n' && c != -1)
+				read_until_char(&io, '\n');
+			continue;
+		}
+		c = io__get_char(&io);
+		if (c != 'u') {
+			if (c != '\n' && c != -1)
+				read_until_char(&io, '\n');
+			continue;
+		}
+		c = io__get_dec(&io, &cpu_num);
+		if (c != ' ' || (int)cpu_num != cpu.cpu) {
+			if (c != '\n' && c != -1)
+				read_until_char(&io, '\n');
+			continue;
+		}
+
+		/* Found our CPU. Now read the field. */
+		while (true) {
+			__u64 v;
+			int sep = io__get_dec(&io, &v);
+
+			if (sep < 0)
+				return -EINVAL;
+			if (i == field) {
+				*val = v;
+				return 0;
+			}
+			if (sep == '\n')
+				return -EINVAL; /* Field not found on line */
+			i++;
+		}
+	}
+	return -EINVAL;
+}
+
 static int read_pid_stat_field(int fd, int field, __u64 *val)
 {
 	char buf[256];
@@ -303,6 +388,14 @@ static const char *tool_pmu__memory_event_to_key(enum tool_pmu_event ev)
 	case TOOL_PMU__EVENT_NET_TX_COLLS:
 	case TOOL_PMU__EVENT_NET_TX_CARRIER:
 	case TOOL_PMU__EVENT_NET_TX_COMPRESSED:
+	case TOOL_PMU__EVENT_SCHEDSTAT_YIELD:
+	case TOOL_PMU__EVENT_SCHEDSTAT_SCHEDULE:
+	case TOOL_PMU__EVENT_SCHEDSTAT_SCHEDULE_IDLE:
+	case TOOL_PMU__EVENT_SCHEDSTAT_WAKE:
+	case TOOL_PMU__EVENT_SCHEDSTAT_WAKE_LOCAL:
+	case TOOL_PMU__EVENT_SCHEDSTAT_RUNTIME:
+	case TOOL_PMU__EVENT_SCHEDSTAT_WAIT:
+	case TOOL_PMU__EVENT_SCHEDSTAT_TIMESLICES:
 	case TOOL_PMU__EVENT_DURATION_TIME:
 	case TOOL_PMU__EVENT_USER_TIME:
 	case TOOL_PMU__EVENT_SYSTEM_TIME:
@@ -477,7 +570,8 @@ static bool tool_pmu__has_start_times(enum tool_pmu_event ev)
 {
 	return ev == TOOL_PMU__EVENT_USER_TIME ||
 	       ev == TOOL_PMU__EVENT_SYSTEM_TIME ||
-	       tool_pmu__is_net_event(ev);
+	       tool_pmu__is_net_event(ev) ||
+	       tool_pmu__is_sched_stat_event(ev);
 }
 
 static int read_net_dev_col(struct io *io, __u64 *val, int *term)
@@ -609,6 +703,16 @@ static int tool_pmu__read_stat(struct evsel *evsel, int cpu_map_idx, int thread,
 		return 0;
 	}
 
+	if (tool_pmu__is_sched_stat_event(ev)) {
+		if (thread == 0) {
+			struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus, cpu_map_idx);
+
+			return read_sched_stat(fd, cpu, ev, val);
+		}
+		*val = 0;
+		return 0;
+	}
+
 	lseek(fd, 0, SEEK_SET);
 	if (evsel->pid_stat) {
 		if (cpu_map_idx == 0)
@@ -702,6 +806,15 @@ static int evsel__tool_pmu_open_one(struct evsel *evsel, enum tool_pmu_event ev,
 				if (fd < 0)
 					return -errno;
 			}
+		} else if (tool_pmu__is_sched_stat_event(ev)) {
+			if (pid > -1 || evsel->cgrp)
+				return -EINVAL;
+			if (thread == 0) {
+				snprintf(buf, sizeof(buf), "%s/schedstat", procfs__mountpoint());
+				fd = open(buf, O_RDONLY);
+				if (fd < 0)
+					return -errno;
+			}
 		} else {
 			if (pid > -1) {
 				snprintf(buf, sizeof(buf), "%s/%d/stat", procfs__mountpoint(), pid);
@@ -1005,6 +1118,14 @@ bool tool_pmu__read_event(enum tool_pmu_event ev,
 	case TOOL_PMU__EVENT_NET_TX_COLLS:
 	case TOOL_PMU__EVENT_NET_TX_CARRIER:
 	case TOOL_PMU__EVENT_NET_TX_COMPRESSED:
+	case TOOL_PMU__EVENT_SCHEDSTAT_YIELD:
+	case TOOL_PMU__EVENT_SCHEDSTAT_SCHEDULE:
+	case TOOL_PMU__EVENT_SCHEDSTAT_SCHEDULE_IDLE:
+	case TOOL_PMU__EVENT_SCHEDSTAT_WAKE:
+	case TOOL_PMU__EVENT_SCHEDSTAT_WAKE_LOCAL:
+	case TOOL_PMU__EVENT_SCHEDSTAT_RUNTIME:
+	case TOOL_PMU__EVENT_SCHEDSTAT_WAIT:
+	case TOOL_PMU__EVENT_SCHEDSTAT_TIMESLICES:
 	case TOOL_PMU__EVENT_NONE:
 	case TOOL_PMU__EVENT_DURATION_TIME:
 	case TOOL_PMU__EVENT_USER_TIME:
@@ -1261,7 +1382,15 @@ int evsel__tool_pmu_read(struct evsel *evsel, int cpu_map_idx, int thread)
 	case TOOL_PMU__EVENT_NET_TX_FIFO:
 	case TOOL_PMU__EVENT_NET_TX_COLLS:
 	case TOOL_PMU__EVENT_NET_TX_CARRIER:
-	case TOOL_PMU__EVENT_NET_TX_COMPRESSED: {
+	case TOOL_PMU__EVENT_NET_TX_COMPRESSED:
+	case TOOL_PMU__EVENT_SCHEDSTAT_YIELD:
+	case TOOL_PMU__EVENT_SCHEDSTAT_SCHEDULE:
+	case TOOL_PMU__EVENT_SCHEDSTAT_SCHEDULE_IDLE:
+	case TOOL_PMU__EVENT_SCHEDSTAT_WAKE:
+	case TOOL_PMU__EVENT_SCHEDSTAT_WAKE_LOCAL:
+	case TOOL_PMU__EVENT_SCHEDSTAT_RUNTIME:
+	case TOOL_PMU__EVENT_SCHEDSTAT_WAIT:
+	case TOOL_PMU__EVENT_SCHEDSTAT_TIMESLICES: {
 		__u64 *accumulated_ptr = evsel->process_time.accumulated_times ?
 			xyarray__entry(evsel->process_time.accumulated_times, cpu_map_idx, thread) :
 			NULL;
diff --git a/tools/perf/util/tool_pmu.h b/tools/perf/util/tool_pmu.h
index f972995bb8ed..5a290a9e7555 100644
--- a/tools/perf/util/tool_pmu.h
+++ b/tools/perf/util/tool_pmu.h
@@ -66,6 +66,14 @@ enum tool_pmu_event {
 	TOOL_PMU__EVENT_NET_TX_COLLS,
 	TOOL_PMU__EVENT_NET_TX_CARRIER,
 	TOOL_PMU__EVENT_NET_TX_COMPRESSED,
+	TOOL_PMU__EVENT_SCHEDSTAT_YIELD,
+	TOOL_PMU__EVENT_SCHEDSTAT_SCHEDULE,
+	TOOL_PMU__EVENT_SCHEDSTAT_SCHEDULE_IDLE,
+	TOOL_PMU__EVENT_SCHEDSTAT_WAKE,
+	TOOL_PMU__EVENT_SCHEDSTAT_WAKE_LOCAL,
+	TOOL_PMU__EVENT_SCHEDSTAT_RUNTIME,
+	TOOL_PMU__EVENT_SCHEDSTAT_WAIT,
+	TOOL_PMU__EVENT_SCHEDSTAT_TIMESLICES,
 
 	TOOL_PMU__EVENT_MAX,
 };
@@ -77,6 +85,7 @@ const char *tool_pmu__event_to_str(enum tool_pmu_event ev);
 enum tool_pmu_event tool_pmu__str_to_event(const char *str);
 bool tool_pmu__skip_event(const char *name);
 int tool_pmu__num_skip_events(void);
+bool tool_pmu__is_sched_stat_event(enum tool_pmu_event ev);
 
 bool tool_pmu__read_event(enum tool_pmu_event ev,
 			  struct evsel *evsel,
-- 
2.56.1.703.gf848ed807c-goog


  parent reply	other threads:[~2026-11-13 23:37 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-13 23:37 [PATCH v2 0/4] perf tool_pmu: Add procfs memory, network and " Ian Rogers
2026-11-13 23:37 ` [PATCH v2 1/4] perf tool_pmu: Add memory events Ian Rogers
2026-11-13 23:37 ` [PATCH v2 2/4] perf tool_pmu: Add network events Ian Rogers
2026-11-13 23:37 ` Ian Rogers [this message]
2026-11-13 23:37 ` [PATCH v2 4/4] perf test tool_pmu: Add memory, network and schedstat tests Ian Rogers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261113233739.3626499-4-irogers@google.com \
    --to=irogers@google.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=ak@linux.intel.com \
    --cc=james.clark@linaro.org \
    --cc=jolsa@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=peterz@infradead.org \
    --cc=thomas.falcon@intel.com \
    --cc=tmricht@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®