The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v3 00/11] sched_ext: Implement core event counters
@ 2025-01-31  7:09 Changwoo Min
  2025-01-31  7:09 ` [PATCH v3 01/11] sched_ext: Implement event counter infrastructure Changwoo Min
                   ` (11 more replies)
  0 siblings, 12 replies; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

The sched_ext core often has to override the BPF scheduler decisions,
and some events could be interesting but not easily visible.

This patchset aims to address such a problem in the following manner:
  - Introduce an infrastructure to collect such events in a scalable and
    extensible way and to expose the collected events to the BPF scheduler
    in a compatible way.
  - Define seven events to be collected.
  - Modify an scx scheduler to demonstrate the usage of the new BPF APIs.

ChangeLog: v2 -> v3
  - Rename scx_bpf_event_stats() to scx_bpf_events().
  - Add a prefix SCX_EV_ to all event names.
  - Change the implementation SCX_EV_SELECT_CPU_FALLBACK such that
    record the selected cpu (p->scx.selected_cpu) in
    select_task_rq_scx() and compare it in enqueue_task_scx() to
    reliably count events.
  - Change the implementation of SCX_EV_BYPASS_DISPATCH such that log
    the event where the condition is initially detected.
  - Modify scx_qmap to print the core event counter every second.
  - Remove unnecessary white space in patch 6.

ChangeLog: v1 -> v2
  - Rename scx_event_stat and scx_bpf_event_stat() to scx_event_stats and
    scx_bpf_event_stats().
  - Rename event names following the convention of $COMPONENT_$EVENT.
  - Rename event_stats to event_stats_cpu.
  - Drop the enum scx_event_kind and related macros.
  - Revise scx_add_event() to use this_cpu_add().
  - Add __scx_add_event() to use __this_cpu_add().
  - Move the event counter resetting code to the loading of a BPF scheduler.
  - The bypass-related event is further categorized into three events:
    BYPASS_ACTIVATE, BYPASS_DISPATCH, and BYPASS_DURATION.
  - Revise SELECT_CPU_FALLBACK to capture the case of the chosen CPU is not
    allowed.
  - Move is_cpu_allowed() from core.c to sched.h to use in the
    SELECT_CPU_FALLBACK code.

Changwoo Min (11):
  sched_ext: Implement event counter infrastructure
  sched_ext: Add an event, SCX_EV_SELECT_CPU_FALLBACK
  sched_ext: Add an event, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE
  sched_ext: Add an event, SCX_EV_DISPATCH_KEEP_LAST
  sched_ext: Add an event, SCX_EV_ENQ_SKIP_EXITING
  sched_ext: Add an event, SCX_EV_BYPASS_ACTIVATE
  sched_ext: Add an event, SCX_EV_BYPASS_DISPATCH
  sched_ext: Add an event, SCX_EV_BYPASS_DURATION
  sched_ext: Add scx_bpf_events() and scx_read_event() for BPF
    schedulers
  sched_ext: Print core event count in scx_central scheduler
  sched_ext: Print core event count in scx_qmap scheduler

 include/linux/sched/ext.h                |   1 +
 kernel/sched/ext.c                       | 197 ++++++++++++++++++++++-
 tools/sched_ext/include/scx/common.bpf.h |   4 +
 tools/sched_ext/scx_central.bpf.c        |  21 +++
 tools/sched_ext/scx_qmap.bpf.c           |  19 +++
 5 files changed, 237 insertions(+), 5 deletions(-)

-- 
2.48.1


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v3 01/11] sched_ext: Implement event counter infrastructure
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-01-31  7:09 ` [PATCH v3 02/11] sched_ext: Add an event, SCX_EV_SELECT_CPU_FALLBACK Changwoo Min
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Collect the statistics of specific types of behavior in the sched_ext core,
which are not easily visible but still interesting to an scx scheduler.

An event type is defined in 'struct scx_event_stats.' When an event occurs,
its counter is accumulated using 'scx_add_event()' and '__scx_add_event()'
to per-CPU 'struct scx_event_stats' for efficiency. 'scx_bpf_events()'
aggregates all the per-CPU counters and exposes a system-wide counters.

For convenience and readability of the code, 'scx_agg_event()' and
'scx_dump_event()' are provided.

The collected events can be observed after a BPF scheduler is unloaded
beforea new BPF scheduler is loaded so the per-CPU 'struct scx_event_stats'
are reset.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 kernel/sched/ext.c | 103 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 5f6a425d4ffe..4e28e88e88d4 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -1440,6 +1440,64 @@ static struct task_struct *scx_task_iter_next_locked(struct scx_task_iter *iter)
 	return p;
 }
 
+/*
+ * Collection of event counters. Event types are placed in descending order.
+ */
+struct scx_event_stats {
+};
+
+/*
+ * The event counter is organized by a per-CPU variable to minimize the
+ * accounting overhead without synchronization. A system-wide view on the
+ * event counter is constructed when requested by scx_bpf_get_event_stat().
+ */
+static DEFINE_PER_CPU(struct scx_event_stats, event_stats_cpu);
+
+/**
+ * scx_add_event - Increase an event counter for 'name' by 'cnt'
+ * @name: an event name defined in struct scx_event_stats
+ * @cnt: the number of the event occured
+ *
+ * This can be used when preemption is not disabled.
+ */
+#define scx_add_event(name, cnt) do {						\
+	this_cpu_add(event_stats_cpu.name, cnt);				\
+} while(0)
+
+/**
+ * __scx_add_event - Increase an event counter for 'name' by 'cnt'
+ * @name: an event name defined in struct scx_event_stats
+ * @cnt: the number of the event occured
+ *
+ * This should be used only when preemption is disabled.
+ */
+#define __scx_add_event(name, cnt) do {						\
+	__this_cpu_add(event_stats_cpu.name, cnt);				\
+} while(0)
+
+/**
+ * scx_agg_event - Aggregate an event counter 'kind' from 'src_e' to 'dst_e'
+ * @dst_e: destination event stats
+ * @src_e: source event stats
+ * @kind: a kind of event to be aggregated
+ */
+#define scx_agg_event(dst_e, src_e, kind) do {					\
+	(dst_e)->kind += READ_ONCE((src_e)->kind);				\
+} while(0)
+
+/**
+ * scx_dump_event - Dump an event 'kind' in 'events' to 's'
+ * @s: output seq_buf
+ * @events: event stats
+ * @kind: a kind of event to dump
+ */
+#define scx_dump_event(s, events, kind) do {					\
+	dump_line(&(s), "%30s: %16llu", #kind, (events)->kind);			\
+} while (0)
+
+
+static void scx_bpf_events(struct scx_event_stats *events, size_t events__sz);
+
 static enum scx_ops_enable_state scx_ops_enable_state(void)
 {
 	return atomic_read(&scx_ops_enable_state_var);
@@ -4785,6 +4843,7 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
 		.at_jiffies = jiffies,
 	};
 	struct seq_buf s;
+	struct scx_event_stats events;
 	unsigned long flags;
 	char *buf;
 	int cpu;
@@ -4893,6 +4952,12 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
 		rq_unlock(rq, &rf);
 	}
 
+	dump_newline(&s);
+	dump_line(&s, "Event counters");
+	dump_line(&s, "--------------");
+
+	scx_bpf_events(&events, sizeof(events));
+
 	if (seq_buf_has_overflowed(&s) && dump_len >= sizeof(trunc_marker))
 		memcpy(ei->dump + dump_len - sizeof(trunc_marker),
 		       trunc_marker, sizeof(trunc_marker));
@@ -5000,6 +5065,15 @@ static int scx_ops_enable(struct sched_ext_ops *ops, struct bpf_link *link)
 
 	mutex_lock(&scx_ops_enable_mutex);
 
+	/*
+	 * Clear event counters so a new scx scheduler gets
+	 * fresh event counter values.
+	 */
+	for_each_possible_cpu(cpu) {
+		struct scx_event_stats *e = per_cpu_ptr(&event_stats_cpu, cpu);
+		memset(e, 0, sizeof(*e));
+	}
+
 	if (!scx_ops_helper) {
 		WRITE_ONCE(scx_ops_helper,
 			   scx_create_rt_helper("sched_ext_ops_helper"));
@@ -7001,6 +7075,34 @@ __bpf_kfunc u64 scx_bpf_now(void)
 	return clock;
 }
 
+/*
+ * scx_bpf_events - Get a system-wide event counter to
+ * @events: output buffer from a BPF program
+ * @events__sz: @events len, must end in '__sz'' for the verifier
+ */
+__bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
+				size_t events__sz)
+{
+	struct scx_event_stats e_sys, *e_cpu;
+	int cpu;
+
+	/* Aggregate per-CPU event counters into the system-wide counters. */
+	memset(&e_sys, 0, sizeof(e_sys));
+	for_each_possible_cpu(cpu) {
+		e_cpu = per_cpu_ptr(&event_stats_cpu, cpu);
+	}
+
+	/*
+	 * We cannot entirely trust a BPF-provided size since a BPF program
+	 * might be compiled against a different vmlinux.h, of which
+	 * scx_event_stats would be larger (a newer vmlinux.h) or smaller
+	 * (an older vmlinux.h). Hence, we use the smaller size to avoid
+	 * memory corruption.
+	 */
+	events__sz = min(events__sz, sizeof(*events));
+	memcpy(events, &e_sys, events__sz);
+}
+
 __bpf_kfunc_end_defs();
 
 BTF_KFUNCS_START(scx_kfunc_ids_any)
@@ -7033,6 +7135,7 @@ BTF_ID_FLAGS(func, scx_bpf_cpu_rq)
 BTF_ID_FLAGS(func, scx_bpf_task_cgroup, KF_RCU | KF_ACQUIRE)
 #endif
 BTF_ID_FLAGS(func, scx_bpf_now)
+BTF_ID_FLAGS(func, scx_bpf_events, KF_TRUSTED_ARGS)
 BTF_KFUNCS_END(scx_kfunc_ids_any)
 
 static const struct btf_kfunc_id_set scx_kfunc_set_any = {
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 02/11] sched_ext: Add an event, SCX_EV_SELECT_CPU_FALLBACK
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
  2025-01-31  7:09 ` [PATCH v3 01/11] sched_ext: Implement event counter infrastructure Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-02-02 17:34   ` Tejun Heo
  2025-01-31  7:09 ` [PATCH v3 03/11] sched_ext: Add an event, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE Changwoo Min
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Add a core event, SCX_EV_SELECT_CPU_FALLBACK, which represents how many times
ops.select_cpu() returns a CPU that the task can't use.

__scx_add_event() is used since the caller holds an rq lock,
so the preemption has already been disabled.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 include/linux/sched/ext.h |  1 +
 kernel/sched/ext.c        | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/include/linux/sched/ext.h b/include/linux/sched/ext.h
index 1d70a9867fb1..f7545430a548 100644
--- a/include/linux/sched/ext.h
+++ b/include/linux/sched/ext.h
@@ -146,6 +146,7 @@ struct sched_ext_entity {
 	u32			weight;
 	s32			sticky_cpu;
 	s32			holding_cpu;
+	s32			selected_cpu;
 	u32			kf_mask;	/* see scx_kf_mask above */
 	struct task_struct	*kf_tasks[2];	/* see SCX_CALL_OP_TASK() */
 	atomic_long_t		ops_state;
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 4e28e88e88d4..4d3b32aca48d 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -1444,6 +1444,11 @@ static struct task_struct *scx_task_iter_next_locked(struct scx_task_iter *iter)
  * Collection of event counters. Event types are placed in descending order.
  */
 struct scx_event_stats {
+	/*
+	 * If ops.select_cpu() returns a CPU which can't be used by the task,
+	 * the core scheduler code silently picks a fallback CPU.
+	 */
+	u64		SCX_EV_SELECT_CPU_FALLBACK;
 };
 
 /*
@@ -2170,6 +2175,11 @@ static void enqueue_task_scx(struct rq *rq, struct task_struct *p, int enq_flags
 	do_enqueue_task(rq, p, enq_flags, sticky_cpu);
 out:
 	rq->scx.flags &= ~SCX_RQ_IN_WAKEUP;
+
+	if ((enq_flags & SCX_ENQ_CPU_SELECTED) &&
+	    (cpu_of(rq) != p->scx.selected_cpu)) {
+		__scx_add_event(SCX_EV_SELECT_CPU_FALLBACK, 1);
+	}
 }
 
 static void ops_dequeue(struct task_struct *p, u64 deq_flags)
@@ -3240,6 +3250,7 @@ static int select_task_rq_scx(struct task_struct *p, int prev_cpu, int wake_flag
 
 		cpu = SCX_CALL_OP_TASK_RET(SCX_KF_ENQUEUE | SCX_KF_SELECT_CPU,
 					   select_cpu, p, prev_cpu, wake_flags);
+		p->scx.selected_cpu = cpu;
 		*ddsp_taskp = NULL;
 		if (ops_cpu_valid(cpu, "from ops.select_cpu()"))
 			return cpu;
@@ -3250,6 +3261,7 @@ static int select_task_rq_scx(struct task_struct *p, int prev_cpu, int wake_flag
 		s32 cpu;
 
 		cpu = scx_select_cpu_dfl(p, prev_cpu, wake_flags, &found);
+		p->scx.selected_cpu = cpu;
 		if (found) {
 			p->scx.slice = SCX_SLICE_DFL;
 			p->scx.ddsp_dsq_id = SCX_DSQ_LOCAL;
@@ -4957,6 +4969,7 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
 	dump_line(&s, "--------------");
 
 	scx_bpf_events(&events, sizeof(events));
+	scx_dump_event(s, &events, SCX_EV_SELECT_CPU_FALLBACK);
 
 	if (seq_buf_has_overflowed(&s) && dump_len >= sizeof(trunc_marker))
 		memcpy(ei->dump + dump_len - sizeof(trunc_marker),
@@ -7090,6 +7103,7 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
 	memset(&e_sys, 0, sizeof(e_sys));
 	for_each_possible_cpu(cpu) {
 		e_cpu = per_cpu_ptr(&event_stats_cpu, cpu);
+		scx_agg_event(&e_sys, e_cpu, SCX_EV_SELECT_CPU_FALLBACK);
 	}
 
 	/*
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 03/11] sched_ext: Add an event, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
  2025-01-31  7:09 ` [PATCH v3 01/11] sched_ext: Implement event counter infrastructure Changwoo Min
  2025-01-31  7:09 ` [PATCH v3 02/11] sched_ext: Add an event, SCX_EV_SELECT_CPU_FALLBACK Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-01-31  7:09 ` [PATCH v3 04/11] sched_ext: Add an event, SCX_EV_DISPATCH_KEEP_LAST Changwoo Min
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Add a core event, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE, which represents how
many times a BPF scheduler tries to dispatch to an offlined local DSQ.

__scx_add_event() is used since the caller holds an rq lock,
so the preemption has already been disabled.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 kernel/sched/ext.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 4d3b32aca48d..041b0af3551a 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -1449,6 +1449,12 @@ struct scx_event_stats {
 	 * the core scheduler code silently picks a fallback CPU.
 	 */
 	u64		SCX_EV_SELECT_CPU_FALLBACK;
+
+	/*
+	 * When dispatching to a local DSQ, the CPU may have gone offline in
+	 * the meantime. In this case, the task is bounced to the global DSQ.
+	 */
+	u64		SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE;
 };
 
 /*
@@ -2644,6 +2650,7 @@ static void dispatch_to_local_dsq(struct rq *rq, struct scx_dispatch_q *dst_dsq,
 	if (unlikely(!task_can_run_on_remote_rq(p, dst_rq, true))) {
 		dispatch_enqueue(find_global_dsq(p), p,
 				 enq_flags | SCX_ENQ_CLEAR_OPSS);
+		__scx_add_event(SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE, 1);
 		return;
 	}
 
@@ -4970,6 +4977,7 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
 
 	scx_bpf_events(&events, sizeof(events));
 	scx_dump_event(s, &events, SCX_EV_SELECT_CPU_FALLBACK);
+	scx_dump_event(s, &events, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
 
 	if (seq_buf_has_overflowed(&s) && dump_len >= sizeof(trunc_marker))
 		memcpy(ei->dump + dump_len - sizeof(trunc_marker),
@@ -7104,6 +7112,7 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
 	for_each_possible_cpu(cpu) {
 		e_cpu = per_cpu_ptr(&event_stats_cpu, cpu);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_SELECT_CPU_FALLBACK);
+		scx_agg_event(&e_sys, e_cpu, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
 	}
 
 	/*
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 04/11] sched_ext: Add an event, SCX_EV_DISPATCH_KEEP_LAST
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
                   ` (2 preceding siblings ...)
  2025-01-31  7:09 ` [PATCH v3 03/11] sched_ext: Add an event, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-02-02 17:24   ` Tejun Heo
  2025-01-31  7:09 ` [PATCH v3 05/11] sched_ext: Add an event, SCX_EV_ENQ_SKIP_EXITING Changwoo Min
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Add a core event, SCX_EV_DISPATCH_KEEP_LAST, which represents how many
times a task is continued to run without ops.enqueue() when
SCX_OPS_ENQ_LAST is not set.

__scx_add_event() is used since the caller holds an rq lock,
so the preemption has already been disabled.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 kernel/sched/ext.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 041b0af3551a..7147f730850b 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -1455,6 +1455,12 @@ struct scx_event_stats {
 	 * the meantime. In this case, the task is bounced to the global DSQ.
 	 */
 	u64		SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE;
+
+	/*
+	 * If SCX_OPS_ENQ_LAST is not set, the number of times that a task
+	 * continued to run because there were no other tasks on the CPU.
+	 */
+	u64		SCX_EV_DISPATCH_KEEP_LAST;
 };
 
 /*
@@ -2908,6 +2914,7 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
 	if (prev_on_rq && (!static_branch_unlikely(&scx_ops_enq_last) ||
 	     scx_rq_bypassing(rq))) {
 		rq->scx.flags |= SCX_RQ_BAL_KEEP;
+		__scx_add_event(SCX_EV_DISPATCH_KEEP_LAST, 1);
 		goto has_tasks;
 	}
 	rq->scx.flags &= ~SCX_RQ_IN_BALANCE;
@@ -4978,6 +4985,7 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
 	scx_bpf_events(&events, sizeof(events));
 	scx_dump_event(s, &events, SCX_EV_SELECT_CPU_FALLBACK);
 	scx_dump_event(s, &events, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
+	scx_dump_event(s, &events, SCX_EV_DISPATCH_KEEP_LAST);
 
 	if (seq_buf_has_overflowed(&s) && dump_len >= sizeof(trunc_marker))
 		memcpy(ei->dump + dump_len - sizeof(trunc_marker),
@@ -7113,6 +7121,7 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
 		e_cpu = per_cpu_ptr(&event_stats_cpu, cpu);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_SELECT_CPU_FALLBACK);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
+		scx_agg_event(&e_sys, e_cpu, SCX_EV_DISPATCH_KEEP_LAST);
 	}
 
 	/*
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 05/11] sched_ext: Add an event, SCX_EV_ENQ_SKIP_EXITING
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
                   ` (3 preceding siblings ...)
  2025-01-31  7:09 ` [PATCH v3 04/11] sched_ext: Add an event, SCX_EV_DISPATCH_KEEP_LAST Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-02-02 17:20   ` Tejun Heo
  2025-01-31  7:09 ` [PATCH v3 06/11] sched_ext: Add an event, SCX_EV_BYPASS_ACTIVATE Changwoo Min
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Add a core event, SCX_EV_ENQ_SKIP_EXITING, which represents how many
times a task is enqueued to a local DSQ when exiting if
SCX_OPS_ENQ_EXITING is not set.

__scx_add_event() is used since the caller holds an rq lock,
so the preemption has already been disabled.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 kernel/sched/ext.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 7147f730850b..37f86a84ac5d 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -1461,6 +1461,12 @@ struct scx_event_stats {
 	 * continued to run because there were no other tasks on the CPU.
 	 */
 	u64		SCX_EV_DISPATCH_KEEP_LAST;
+
+	/*
+	 * If SCX_OPS_ENQ_EXITING is not set, the number of times that a task
+	 * is dispatched to a local DSQ when exiting.
+	 */
+	u64		SCX_EV_ENQ_SKIP_EXITING;
 };
 
 /*
@@ -2068,8 +2074,10 @@ static void do_enqueue_task(struct rq *rq, struct task_struct *p, u64 enq_flags,
 
 	/* see %SCX_OPS_ENQ_EXITING */
 	if (!static_branch_unlikely(&scx_ops_enq_exiting) &&
-	    unlikely(p->flags & PF_EXITING))
+	    unlikely(p->flags & PF_EXITING)) {
+		__scx_add_event(SCX_EV_ENQ_SKIP_EXITING, 1);
 		goto local;
+	}
 
 	if (!SCX_HAS_OP(enqueue))
 		goto global;
@@ -4986,6 +4994,7 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
 	scx_dump_event(s, &events, SCX_EV_SELECT_CPU_FALLBACK);
 	scx_dump_event(s, &events, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
 	scx_dump_event(s, &events, SCX_EV_DISPATCH_KEEP_LAST);
+	scx_dump_event(s, &events, SCX_EV_ENQ_SKIP_EXITING);
 
 	if (seq_buf_has_overflowed(&s) && dump_len >= sizeof(trunc_marker))
 		memcpy(ei->dump + dump_len - sizeof(trunc_marker),
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 06/11] sched_ext: Add an event, SCX_EV_BYPASS_ACTIVATE
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
                   ` (4 preceding siblings ...)
  2025-01-31  7:09 ` [PATCH v3 05/11] sched_ext: Add an event, SCX_EV_ENQ_SKIP_EXITING Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-01-31  7:09 ` [PATCH v3 07/11] sched_ext: Add an event, SCX_EV_BYPASS_DISPATCH Changwoo Min
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Add a core event, SCX_EV_BYPASS_ACTIVATE, which represents how many
times the bypass mode has been triggered.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 kernel/sched/ext.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 37f86a84ac5d..07d54b52e971 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -1467,6 +1467,11 @@ struct scx_event_stats {
 	 * is dispatched to a local DSQ when exiting.
 	 */
 	u64		SCX_EV_ENQ_SKIP_EXITING;
+
+	/*
+	 * The number of times the bypassing mode has been activated.
+	 */
+	u64		SCX_EV_BYPASS_ACTIVATE;
 };
 
 /*
@@ -4400,6 +4405,7 @@ static void scx_ops_bypass(bool bypass)
 		WARN_ON_ONCE(scx_ops_bypass_depth <= 0);
 		if (scx_ops_bypass_depth != 1)
 			goto unlock;
+		scx_add_event(SCX_EV_BYPASS_ACTIVATE, 1);
 	} else {
 		scx_ops_bypass_depth--;
 		WARN_ON_ONCE(scx_ops_bypass_depth < 0);
@@ -4995,6 +5001,7 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
 	scx_dump_event(s, &events, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
 	scx_dump_event(s, &events, SCX_EV_DISPATCH_KEEP_LAST);
 	scx_dump_event(s, &events, SCX_EV_ENQ_SKIP_EXITING);
+	scx_dump_event(s, &events, SCX_EV_BYPASS_ACTIVATE);
 
 	if (seq_buf_has_overflowed(&s) && dump_len >= sizeof(trunc_marker))
 		memcpy(ei->dump + dump_len - sizeof(trunc_marker),
@@ -7131,6 +7138,7 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_SELECT_CPU_FALLBACK);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_DISPATCH_KEEP_LAST);
+		scx_agg_event(&e_sys, e_cpu, SCX_EV_BYPASS_ACTIVATE);
 	}
 
 	/*
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 07/11] sched_ext: Add an event, SCX_EV_BYPASS_DISPATCH
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
                   ` (5 preceding siblings ...)
  2025-01-31  7:09 ` [PATCH v3 06/11] sched_ext: Add an event, SCX_EV_BYPASS_ACTIVATE Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-02-02 17:33   ` Tejun Heo
  2025-01-31  7:09 ` [PATCH v3 08/11] sched_ext: Add an event, SCX_EV_BYPASS_DURATION Changwoo Min
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Add a core event, SCX_EV_BYPASS_DISPATCH, which represents how many
tasks have been dispatched in the bypass mode.

__scx_add_event() is used since the caller holds an rq lock,
so the preemption has already been disabled.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 kernel/sched/ext.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 07d54b52e971..236cdb0071eb 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -1468,6 +1468,11 @@ struct scx_event_stats {
 	 */
 	u64		SCX_EV_ENQ_SKIP_EXITING;
 
+	/*
+	 * The number of tasks dispatched in the bypassing mode.
+	 */
+	u64		SCX_EV_BYPASS_DISPATCH;
+
 	/*
 	 * The number of times the bypassing mode has been activated.
 	 */
@@ -2869,11 +2874,17 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
 	}
 
 	/* if there already are tasks to run, nothing to do */
-	if (rq->scx.local_dsq.nr)
+	if (rq->scx.local_dsq.nr) {
+		if (scx_rq_bypassing(rq))
+			__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
 		goto has_tasks;
+	}
 
-	if (consume_global_dsq(rq))
+	if (consume_global_dsq(rq)) {
+		if (scx_rq_bypassing(rq))
+			__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
 		goto has_tasks;
+	}
 
 	if (!SCX_HAS_OP(dispatch) || scx_rq_bypassing(rq) || !scx_rq_online(rq))
 		goto no_tasks;
@@ -2899,10 +2910,16 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
 			rq->scx.flags |= SCX_RQ_BAL_KEEP;
 			goto has_tasks;
 		}
-		if (rq->scx.local_dsq.nr)
+		if (rq->scx.local_dsq.nr) {
+			if (scx_rq_bypassing(rq))
+				__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
 			goto has_tasks;
-		if (consume_global_dsq(rq))
+		}
+		if (consume_global_dsq(rq)) {
+			if (scx_rq_bypassing(rq))
+				__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
 			goto has_tasks;
+		}
 
 		/*
 		 * ops.dispatch() can trap us in this loop by repeatedly
@@ -5001,6 +5018,7 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
 	scx_dump_event(s, &events, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
 	scx_dump_event(s, &events, SCX_EV_DISPATCH_KEEP_LAST);
 	scx_dump_event(s, &events, SCX_EV_ENQ_SKIP_EXITING);
+	scx_dump_event(s, &events, SCX_EV_BYPASS_DISPATCH);
 	scx_dump_event(s, &events, SCX_EV_BYPASS_ACTIVATE);
 
 	if (seq_buf_has_overflowed(&s) && dump_len >= sizeof(trunc_marker))
@@ -7138,6 +7156,7 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_SELECT_CPU_FALLBACK);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_DISPATCH_KEEP_LAST);
+		scx_agg_event(&e_sys, e_cpu, SCX_EV_BYPASS_DISPATCH);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_BYPASS_ACTIVATE);
 	}
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 08/11] sched_ext: Add an event, SCX_EV_BYPASS_DURATION
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
                   ` (6 preceding siblings ...)
  2025-01-31  7:09 ` [PATCH v3 07/11] sched_ext: Add an event, SCX_EV_BYPASS_DISPATCH Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-02-02 17:35   ` Tejun Heo
  2025-01-31  7:09 ` [PATCH v3 09/11] sched_ext: Add scx_bpf_events() and scx_read_event() for BPF schedulers Changwoo Min
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Add a core event, SCX_EV_BYPASS_DURATION, which represents the
total duration of bypass modes in nanoseconds.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 kernel/sched/ext.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 236cdb0071eb..b4871409bd1c 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -1468,6 +1468,11 @@ struct scx_event_stats {
 	 */
 	u64		SCX_EV_ENQ_SKIP_EXITING;
 
+	/*
+	 * The total duration of bypass modes in nanoseconds.
+	 */
+	u64		SCX_EV_BYPASS_DURATION;
+
 	/*
 	 * The number of tasks dispatched in the bypassing mode.
 	 */
@@ -1529,6 +1534,12 @@ static DEFINE_PER_CPU(struct scx_event_stats, event_stats_cpu);
 } while (0)
 
 
+/*
+ * The last time the bypass mode started.
+ * This is used to measure SCX_EV_BYPASS_DURATION.
+ */
+static unsigned long scx_bypass_timestamp;
+
 static void scx_bpf_events(struct scx_event_stats *events, size_t events__sz);
 
 static enum scx_ops_enable_state scx_ops_enable_state(void)
@@ -4422,12 +4433,15 @@ static void scx_ops_bypass(bool bypass)
 		WARN_ON_ONCE(scx_ops_bypass_depth <= 0);
 		if (scx_ops_bypass_depth != 1)
 			goto unlock;
+		scx_bypass_timestamp = ktime_get_ns();
 		scx_add_event(SCX_EV_BYPASS_ACTIVATE, 1);
 	} else {
 		scx_ops_bypass_depth--;
 		WARN_ON_ONCE(scx_ops_bypass_depth < 0);
 		if (scx_ops_bypass_depth != 0)
 			goto unlock;
+		scx_add_event(SCX_EV_BYPASS_DURATION,
+			      ktime_get_ns() - scx_bypass_timestamp);
 	}
 
 	atomic_inc(&scx_ops_breather_depth);
@@ -5018,6 +5032,7 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
 	scx_dump_event(s, &events, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
 	scx_dump_event(s, &events, SCX_EV_DISPATCH_KEEP_LAST);
 	scx_dump_event(s, &events, SCX_EV_ENQ_SKIP_EXITING);
+	scx_dump_event(s, &events, SCX_EV_BYPASS_DURATION);
 	scx_dump_event(s, &events, SCX_EV_BYPASS_DISPATCH);
 	scx_dump_event(s, &events, SCX_EV_BYPASS_ACTIVATE);
 
@@ -7156,6 +7171,7 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_SELECT_CPU_FALLBACK);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_DISPATCH_KEEP_LAST);
+		scx_agg_event(&e_sys, e_cpu, SCX_EV_BYPASS_DURATION);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_BYPASS_DISPATCH);
 		scx_agg_event(&e_sys, e_cpu, SCX_EV_BYPASS_ACTIVATE);
 	}
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 09/11] sched_ext: Add scx_bpf_events() and scx_read_event() for BPF schedulers
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
                   ` (7 preceding siblings ...)
  2025-01-31  7:09 ` [PATCH v3 08/11] sched_ext: Add an event, SCX_EV_BYPASS_DURATION Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-01-31  7:09 ` [PATCH v3 10/11] sched_ext: Print core event count in scx_central scheduler Changwoo Min
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

scx_bpf_events() is added to the header files so the BPF scheduler
can use it. Also, scx_read_event() is added to read an event type in a
compatible way.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 tools/sched_ext/include/scx/common.bpf.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
index f254a39b86a5..705540003024 100644
--- a/tools/sched_ext/include/scx/common.bpf.h
+++ b/tools/sched_ext/include/scx/common.bpf.h
@@ -78,6 +78,10 @@ struct rq *scx_bpf_cpu_rq(s32 cpu) __ksym;
 struct cgroup *scx_bpf_task_cgroup(struct task_struct *p) __ksym __weak;
 u64 scx_bpf_now(void) __ksym __weak;
 
+void scx_bpf_events(struct scx_event_stats *events, size_t events__sz) __ksym __weak;
+#define scx_read_event(e, name)							\
+	(bpf_core_field_exists((e)->name) ? (e)->name : 0)
+
 /*
  * Use the following as @it__iter when calling scx_bpf_dsq_move[_vtime]() from
  * within bpf_for_each() loops.
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 10/11] sched_ext: Print core event count in scx_central scheduler
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
                   ` (8 preceding siblings ...)
  2025-01-31  7:09 ` [PATCH v3 09/11] sched_ext: Add scx_bpf_events() and scx_read_event() for BPF schedulers Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-01-31  7:09 ` [PATCH v3 11/11] sched_ext: Print core event count in scx_qmap scheduler Changwoo Min
  2025-02-02 17:37 ` [PATCH v3 00/11] sched_ext: Implement core event counters Tejun Heo
  11 siblings, 0 replies; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Modify the scx_central scheduler to print the core event counter
every second.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 tools/sched_ext/scx_central.bpf.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/tools/sched_ext/scx_central.bpf.c b/tools/sched_ext/scx_central.bpf.c
index 50bc1737c167..376c14d5dd0d 100644
--- a/tools/sched_ext/scx_central.bpf.c
+++ b/tools/sched_ext/scx_central.bpf.c
@@ -256,6 +256,7 @@ static int central_timerfn(void *map, int *key, struct bpf_timer *timer)
 	u64 now = scx_bpf_now();
 	u64 nr_to_kick = nr_queued;
 	s32 i, curr_cpu;
+	struct scx_event_stats events;
 
 	curr_cpu = bpf_get_smp_processor_id();
 	if (timer_pinned && (curr_cpu != central_cpu)) {
@@ -291,6 +292,26 @@ static int central_timerfn(void *map, int *key, struct bpf_timer *timer)
 
 	bpf_timer_start(timer, TIMER_INTERVAL_NS, BPF_F_TIMER_CPU_PIN);
 	__sync_fetch_and_add(&nr_timers, 1);
+
+	/* print event counters every second */
+	if (nr_timers % 1000 == 0) {
+		scx_bpf_events(&events, sizeof(events));
+
+		bpf_printk("%35s: %llu\n", "SCX_EV_SELECT_CPU_FALLBACK",
+			   scx_read_event(&events, SCX_EV_SELECT_CPU_FALLBACK));
+		bpf_printk("%35s: %llu\n", "SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE",
+			   scx_read_event(&events, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE));
+		bpf_printk("%35s: %llu\n", "SCX_EV_DISPATCH_KEEP_LAST",
+			   scx_read_event(&events, SCX_EV_DISPATCH_KEEP_LAST));
+		bpf_printk("%35s: %llu\n", "SCX_EV_ENQ_SKIP_EXITING",
+			   scx_read_event(&events, SCX_EV_ENQ_SKIP_EXITING));
+		bpf_printk("%35s: %llu\n", "SCX_EV_BYPASS_DURATION",
+			   scx_read_event(&events, SCX_EV_BYPASS_DURATION));
+		bpf_printk("%35s: %llu\n", "SCX_EV_BYPASS_DISPATCH",
+			   scx_read_event(&events, SCX_EV_BYPASS_DISPATCH));
+		bpf_printk("%35s: %llu\n", "SCX_EV_BYPASS_ACTIVATE",
+			   scx_read_event(&events, SCX_EV_BYPASS_ACTIVATE));
+	}
 	return 0;
 }
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 11/11] sched_ext: Print core event count in scx_qmap scheduler
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
                   ` (9 preceding siblings ...)
  2025-01-31  7:09 ` [PATCH v3 10/11] sched_ext: Print core event count in scx_central scheduler Changwoo Min
@ 2025-01-31  7:09 ` Changwoo Min
  2025-02-02 17:37 ` [PATCH v3 00/11] sched_ext: Implement core event counters Tejun Heo
  11 siblings, 0 replies; 21+ messages in thread
From: Changwoo Min @ 2025-01-31  7:09 UTC (permalink / raw)
  To: tj, void, arighi; +Cc: kernel-dev, linux-kernel, Changwoo Min

Modify the scx_qmap scheduler to print the core event counter
every second.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 tools/sched_ext/scx_qmap.bpf.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/tools/sched_ext/scx_qmap.bpf.c b/tools/sched_ext/scx_qmap.bpf.c
index 3a20bb0c014a..5edb79742e37 100644
--- a/tools/sched_ext/scx_qmap.bpf.c
+++ b/tools/sched_ext/scx_qmap.bpf.c
@@ -763,6 +763,8 @@ static void dump_shared_dsq(void)
 
 static int monitor_timerfn(void *map, int *key, struct bpf_timer *timer)
 {
+	struct scx_event_stats events;
+
 	bpf_rcu_read_lock();
 	dispatch_highpri(true);
 	bpf_rcu_read_unlock();
@@ -772,6 +774,23 @@ static int monitor_timerfn(void *map, int *key, struct bpf_timer *timer)
 	if (print_shared_dsq)
 		dump_shared_dsq();
 
+	scx_bpf_events(&events, sizeof(events));
+
+	bpf_printk("%35s: %llu\n", "SCX_EV_SELECT_CPU_FALLBACK",
+		   scx_read_event(&events, SCX_EV_SELECT_CPU_FALLBACK));
+	bpf_printk("%35s: %llu\n", "SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE",
+		   scx_read_event(&events, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE));
+	bpf_printk("%35s: %llu\n", "SCX_EV_DISPATCH_KEEP_LAST",
+		   scx_read_event(&events, SCX_EV_DISPATCH_KEEP_LAST));
+	bpf_printk("%35s: %llu\n", "SCX_EV_ENQ_SKIP_EXITING",
+		   scx_read_event(&events, SCX_EV_ENQ_SKIP_EXITING));
+	bpf_printk("%35s: %llu\n", "SCX_EV_BYPASS_DURATION",
+		   scx_read_event(&events, SCX_EV_BYPASS_DURATION));
+	bpf_printk("%35s: %llu\n", "SCX_EV_BYPASS_DISPATCH",
+		   scx_read_event(&events, SCX_EV_BYPASS_DISPATCH));
+	bpf_printk("%35s: %llu\n", "SCX_EV_BYPASS_ACTIVATE",
+		   scx_read_event(&events, SCX_EV_BYPASS_ACTIVATE));
+
 	bpf_timer_start(timer, ONE_SEC_IN_NS, 0);
 	return 0;
 }
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 05/11] sched_ext: Add an event, SCX_EV_ENQ_SKIP_EXITING
  2025-01-31  7:09 ` [PATCH v3 05/11] sched_ext: Add an event, SCX_EV_ENQ_SKIP_EXITING Changwoo Min
@ 2025-02-02 17:20   ` Tejun Heo
  2025-02-03 15:46     ` Changwoo Min
  0 siblings, 1 reply; 21+ messages in thread
From: Tejun Heo @ 2025-02-02 17:20 UTC (permalink / raw)
  To: Changwoo Min; +Cc: void, arighi, kernel-dev, linux-kernel

On Fri, Jan 31, 2025 at 04:09:32PM +0900, Changwoo Min wrote:
> Add a core event, SCX_EV_ENQ_SKIP_EXITING, which represents how many
> times a task is enqueued to a local DSQ when exiting if
> SCX_OPS_ENQ_EXITING is not set.
> 
> __scx_add_event() is used since the caller holds an rq lock,
> so the preemption has already been disabled.
> 
> Signed-off-by: Changwoo Min <changwoo@igalia.com>
> ---
>  kernel/sched/ext.c | 11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index 7147f730850b..37f86a84ac5d 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -1461,6 +1461,12 @@ struct scx_event_stats {
>  	 * continued to run because there were no other tasks on the CPU.
>  	 */
>  	u64		SCX_EV_DISPATCH_KEEP_LAST;
> +
> +	/*
> +	 * If SCX_OPS_ENQ_EXITING is not set, the number of times that a task
> +	 * is dispatched to a local DSQ when exiting.
> +	 */
> +	u64		SCX_EV_ENQ_SKIP_EXITING;
>  };
>  
>  /*
> @@ -2068,8 +2074,10 @@ static void do_enqueue_task(struct rq *rq, struct task_struct *p, u64 enq_flags,
>  
>  	/* see %SCX_OPS_ENQ_EXITING */
>  	if (!static_branch_unlikely(&scx_ops_enq_exiting) &&
> -	    unlikely(p->flags & PF_EXITING))
> +	    unlikely(p->flags & PF_EXITING)) {
> +		__scx_add_event(SCX_EV_ENQ_SKIP_EXITING, 1);
>  		goto local;
> +	}
>  
>  	if (!SCX_HAS_OP(enqueue))
>  		goto global;
> @@ -4986,6 +4994,7 @@ static void scx_dump_state(struct scx_exit_info *ei, size_t dump_len)
>  	scx_dump_event(s, &events, SCX_EV_SELECT_CPU_FALLBACK);
>  	scx_dump_event(s, &events, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE);
>  	scx_dump_event(s, &events, SCX_EV_DISPATCH_KEEP_LAST);
> +	scx_dump_event(s, &events, SCX_EV_ENQ_SKIP_EXITING);
>  
>  	if (seq_buf_has_overflowed(&s) && dump_len >= sizeof(trunc_marker))
>  		memcpy(ei->dump + dump_len - sizeof(trunc_marker),

Missing agg call?

-- 
tejun

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 04/11] sched_ext: Add an event, SCX_EV_DISPATCH_KEEP_LAST
  2025-01-31  7:09 ` [PATCH v3 04/11] sched_ext: Add an event, SCX_EV_DISPATCH_KEEP_LAST Changwoo Min
@ 2025-02-02 17:24   ` Tejun Heo
  0 siblings, 0 replies; 21+ messages in thread
From: Tejun Heo @ 2025-02-02 17:24 UTC (permalink / raw)
  To: Changwoo Min; +Cc: void, arighi, kernel-dev, linux-kernel

On Fri, Jan 31, 2025 at 04:09:31PM +0900, Changwoo Min wrote:
> Add a core event, SCX_EV_DISPATCH_KEEP_LAST, which represents how many
> times a task is continued to run without ops.enqueue() when
> SCX_OPS_ENQ_LAST is not set.
> 
> __scx_add_event() is used since the caller holds an rq lock,
> so the preemption has already been disabled.
> 
> Signed-off-by: Changwoo Min <changwoo@igalia.com>

Applied 1-4 to sched_ext/for-6.15.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 07/11] sched_ext: Add an event, SCX_EV_BYPASS_DISPATCH
  2025-01-31  7:09 ` [PATCH v3 07/11] sched_ext: Add an event, SCX_EV_BYPASS_DISPATCH Changwoo Min
@ 2025-02-02 17:33   ` Tejun Heo
  2025-02-03 15:51     ` Changwoo Min
  0 siblings, 1 reply; 21+ messages in thread
From: Tejun Heo @ 2025-02-02 17:33 UTC (permalink / raw)
  To: Changwoo Min; +Cc: void, arighi, kernel-dev, linux-kernel

Hello,

On Fri, Jan 31, 2025 at 04:09:34PM +0900, Changwoo Min wrote:
...
> @@ -2869,11 +2874,17 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
>  	}
>  
>  	/* if there already are tasks to run, nothing to do */
> -	if (rq->scx.local_dsq.nr)
> +	if (rq->scx.local_dsq.nr) {
> +		if (scx_rq_bypassing(rq))
> +			__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
>  		goto has_tasks;
> +	}
>  
> -	if (consume_global_dsq(rq))
> +	if (consume_global_dsq(rq)) {
> +		if (scx_rq_bypassing(rq))
> +			__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);

Hmm... Wouldn't it be easier to count it from select_task_rq_scx() and
do_enqueue_task()? The latter already has scx_rq_bypassing() condition and
the former one can easily cache bypassing test result and use that in the
else block.

> @@ -2899,10 +2910,16 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
>  			rq->scx.flags |= SCX_RQ_BAL_KEEP;
>  			goto has_tasks;
>  		}
> -		if (rq->scx.local_dsq.nr)
> +		if (rq->scx.local_dsq.nr) {
> +			if (scx_rq_bypassing(rq))
> +				__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
>  			goto has_tasks;
> -		if (consume_global_dsq(rq))
> +		}
> +		if (consume_global_dsq(rq)) {
> +			if (scx_rq_bypassing(rq))
> +				__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
>  			goto has_tasks;
> +		}

The above can happen while bypass mode is being turned on but once on
control doesn't even reach here, right?

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 02/11] sched_ext: Add an event, SCX_EV_SELECT_CPU_FALLBACK
  2025-01-31  7:09 ` [PATCH v3 02/11] sched_ext: Add an event, SCX_EV_SELECT_CPU_FALLBACK Changwoo Min
@ 2025-02-02 17:34   ` Tejun Heo
  0 siblings, 0 replies; 21+ messages in thread
From: Tejun Heo @ 2025-02-02 17:34 UTC (permalink / raw)
  To: Changwoo Min; +Cc: void, arighi, kernel-dev, linux-kernel

On Fri, Jan 31, 2025 at 04:09:29PM +0900, Changwoo Min wrote:
...
> @@ -2170,6 +2175,11 @@ static void enqueue_task_scx(struct rq *rq, struct task_struct *p, int enq_flags
>  	do_enqueue_task(rq, p, enq_flags, sticky_cpu);
>  out:
>  	rq->scx.flags &= ~SCX_RQ_IN_WAKEUP;
> +
> +	if ((enq_flags & SCX_ENQ_CPU_SELECTED) &&
> +	    (cpu_of(rq) != p->scx.selected_cpu)) {
> +		__scx_add_event(SCX_EV_SELECT_CPU_FALLBACK, 1);
> +	}
>  }

I made minor edits to the above block while applying:

	if ((enq_flags & SCX_ENQ_CPU_SELECTED) &&
	    unlikely(cpu_of(rq) != p->scx.selected_cpu))
		__scx_add_event(SCX_EV_SELECT_CPU_FALLBACK, 1);

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 08/11] sched_ext: Add an event, SCX_EV_BYPASS_DURATION
  2025-01-31  7:09 ` [PATCH v3 08/11] sched_ext: Add an event, SCX_EV_BYPASS_DURATION Changwoo Min
@ 2025-02-02 17:35   ` Tejun Heo
  2025-02-03 15:48     ` Changwoo Min
  0 siblings, 1 reply; 21+ messages in thread
From: Tejun Heo @ 2025-02-02 17:35 UTC (permalink / raw)
  To: Changwoo Min; +Cc: void, arighi, kernel-dev, linux-kernel

On Fri, Jan 31, 2025 at 04:09:35PM +0900, Changwoo Min wrote:
> +/*
> + * The last time the bypass mode started.
> + * This is used to measure SCX_EV_BYPASS_DURATION.
> + */
> +static unsigned long scx_bypass_timestamp;

Move it inside the function?

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 00/11] sched_ext: Implement core event counters
  2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
                   ` (10 preceding siblings ...)
  2025-01-31  7:09 ` [PATCH v3 11/11] sched_ext: Print core event count in scx_qmap scheduler Changwoo Min
@ 2025-02-02 17:37 ` Tejun Heo
  11 siblings, 0 replies; 21+ messages in thread
From: Tejun Heo @ 2025-02-02 17:37 UTC (permalink / raw)
  To: Changwoo Min; +Cc: void, arighi, kernel-dev, linux-kernel

On Fri, Jan 31, 2025 at 04:09:27PM +0900, Changwoo Min wrote:
> The sched_ext core often has to override the BPF scheduler decisions,
> and some events could be interesting but not easily visible.

Applied 1-4. Will wait for refresh on the rest.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 05/11] sched_ext: Add an event, SCX_EV_ENQ_SKIP_EXITING
  2025-02-02 17:20   ` Tejun Heo
@ 2025-02-03 15:46     ` Changwoo Min
  0 siblings, 0 replies; 21+ messages in thread
From: Changwoo Min @ 2025-02-03 15:46 UTC (permalink / raw)
  To: Tejun Heo; +Cc: void, arighi, kernel-dev, linux-kernel

Hello,

On 25. 2. 3. 02:20, Tejun Heo wrote:
> On Fri, Jan 31, 2025 at 04:09:32PM +0900, Changwoo Min wrote:
> Missing agg call?
Ah, you are right. Will fix it.

Regards,
Changwoo Min


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 08/11] sched_ext: Add an event, SCX_EV_BYPASS_DURATION
  2025-02-02 17:35   ` Tejun Heo
@ 2025-02-03 15:48     ` Changwoo Min
  0 siblings, 0 replies; 21+ messages in thread
From: Changwoo Min @ 2025-02-03 15:48 UTC (permalink / raw)
  To: Tejun Heo; +Cc: void, arighi, kernel-dev, linux-kernel

Hello,

On 25. 2. 3. 02:35, Tejun Heo wrote:
> On Fri, Jan 31, 2025 at 04:09:35PM +0900, Changwoo Min wrote:
>> +/*
>> + * The last time the bypass mode started.
>> + * This is used to measure SCX_EV_BYPASS_DURATION.
>> + */
>> +static unsigned long scx_bypass_timestamp;
> 
> Move it inside the function?

That will look cleaner. I will move it inside scx_ops_bypass().

Regards,
Changwoo Min

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 07/11] sched_ext: Add an event, SCX_EV_BYPASS_DISPATCH
  2025-02-02 17:33   ` Tejun Heo
@ 2025-02-03 15:51     ` Changwoo Min
  0 siblings, 0 replies; 21+ messages in thread
From: Changwoo Min @ 2025-02-03 15:51 UTC (permalink / raw)
  To: Tejun Heo; +Cc: void, arighi, kernel-dev, linux-kernel

Hello,

On 25. 2. 3. 02:33, Tejun Heo wrote:
> Hello,
> 
> On Fri, Jan 31, 2025 at 04:09:34PM +0900, Changwoo Min wrote:
> ...
>> @@ -2869,11 +2874,17 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
>>   	}
>>   
>>   	/* if there already are tasks to run, nothing to do */
>> -	if (rq->scx.local_dsq.nr)
>> +	if (rq->scx.local_dsq.nr) {
>> +		if (scx_rq_bypassing(rq))
>> +			__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
>>   		goto has_tasks;
>> +	}
>>   
>> -	if (consume_global_dsq(rq))
>> +	if (consume_global_dsq(rq)) {
>> +		if (scx_rq_bypassing(rq))
>> +			__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
> 
> Hmm... Wouldn't it be easier to count it from select_task_rq_scx() and
> do_enqueue_task()? The latter already has scx_rq_bypassing() condition and
> the former one can easily cache bypassing test result and use that in the
> else block.

That makes sense. I will change the code as you suggested.

> 
>> @@ -2899,10 +2910,16 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
>>   			rq->scx.flags |= SCX_RQ_BAL_KEEP;
>>   			goto has_tasks;
>>   		}
>> -		if (rq->scx.local_dsq.nr)
>> +		if (rq->scx.local_dsq.nr) {
>> +			if (scx_rq_bypassing(rq))
>> +				__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
>>   			goto has_tasks;
>> -		if (consume_global_dsq(rq))
>> +		}
>> +		if (consume_global_dsq(rq)) {
>> +			if (scx_rq_bypassing(rq))
>> +				__scx_add_event(SCX_EV_BYPASS_DISPATCH, 1);
>>   			goto has_tasks;
>> +		}
> 
> The above can happen while bypass mode is being turned on but once on
> control doesn't even reach here, right?

You are right. I will clean this up.

Regards,
Changwoo Min

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2025-02-03 15:51 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-31  7:09 [PATCH v3 00/11] sched_ext: Implement core event counters Changwoo Min
2025-01-31  7:09 ` [PATCH v3 01/11] sched_ext: Implement event counter infrastructure Changwoo Min
2025-01-31  7:09 ` [PATCH v3 02/11] sched_ext: Add an event, SCX_EV_SELECT_CPU_FALLBACK Changwoo Min
2025-02-02 17:34   ` Tejun Heo
2025-01-31  7:09 ` [PATCH v3 03/11] sched_ext: Add an event, SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE Changwoo Min
2025-01-31  7:09 ` [PATCH v3 04/11] sched_ext: Add an event, SCX_EV_DISPATCH_KEEP_LAST Changwoo Min
2025-02-02 17:24   ` Tejun Heo
2025-01-31  7:09 ` [PATCH v3 05/11] sched_ext: Add an event, SCX_EV_ENQ_SKIP_EXITING Changwoo Min
2025-02-02 17:20   ` Tejun Heo
2025-02-03 15:46     ` Changwoo Min
2025-01-31  7:09 ` [PATCH v3 06/11] sched_ext: Add an event, SCX_EV_BYPASS_ACTIVATE Changwoo Min
2025-01-31  7:09 ` [PATCH v3 07/11] sched_ext: Add an event, SCX_EV_BYPASS_DISPATCH Changwoo Min
2025-02-02 17:33   ` Tejun Heo
2025-02-03 15:51     ` Changwoo Min
2025-01-31  7:09 ` [PATCH v3 08/11] sched_ext: Add an event, SCX_EV_BYPASS_DURATION Changwoo Min
2025-02-02 17:35   ` Tejun Heo
2025-02-03 15:48     ` Changwoo Min
2025-01-31  7:09 ` [PATCH v3 09/11] sched_ext: Add scx_bpf_events() and scx_read_event() for BPF schedulers Changwoo Min
2025-01-31  7:09 ` [PATCH v3 10/11] sched_ext: Print core event count in scx_central scheduler Changwoo Min
2025-01-31  7:09 ` [PATCH v3 11/11] sched_ext: Print core event count in scx_qmap scheduler Changwoo Min
2025-02-02 17:37 ` [PATCH v3 00/11] sched_ext: Implement core event counters Tejun Heo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox