* [PATCH V4 0/6] Scheduler time slice extension
@ 2025-05-13 21:45 Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 1/6] Sched: " Prakash Sangappa
` (6 more replies)
0 siblings, 7 replies; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-13 21:45 UTC (permalink / raw)
To: linux-kernel
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy, kprateek.nayak
A user thread can get preempted in the middle of executing a critical
section in user space while holding locks, which can have undesirable affect
on performance. Having a way for the thread to request additional execution
time on cpu, so that it can complete the critical section will be useful in
such scenario. The request can be made by setting a bit in mapped memory,
such that the kernel can also access to check and grant extra execution time
on the cpu.
There have been couple of proposals[1][2] for such a feature, which attempt
to address the above scenario by granting one extra tick of execution time.
In patch thread [1] posted by Steven Rostedt, there is ample discussion about
need for this feature.
However, the concern has been that this can lead to abuse. One extra tick can
be a long time(about a millisec or more). Peter Zijlstra in response posted a
prototype solution[5], which grants 50us execution time extension only.
This is achieved with the help of a timer started on that cpu at the time of
granting extra execution time. When the timer fires the thread will be
preempted, if still running.
This patchset implements above solution as suggested, with use of restartable
sequences(rseq) structure for API. Refer [3][4] for further discussions.
v1:
https://lore.kernel.org/all/20250215005414.224409-1-prakash.sangappa@oracle.com/
v2:
https://lore.kernel.org/all/20250418193410.2010058-1-prakash.sangappa@oracle.com/
- Based on discussions in [3], expecting user application to call sched_yield()
to yield the cpu at the end of the critical section may not be advisable as
pointed out by Linus.
So added a check in return path from a system call to reschedule if time
slice extension was granted to the thread. The check could as well be in
syscall enter path from user mode.
This would allow application thread to call any system call to yield the cpu.
Which system call should be suggested? getppid(2) works.
Do we still need the change in sched_yield() to reschedule when the thread
has current->rseq_sched_delay set?
- Added patch to introduce a sysctl tunable parameter to specify duration of
the time slice extension in micro seconds(us), called 'sched_preempt_delay_us'.
Can take a value in the range 0 to 100. Default is set to 50us.
Setting this tunable to 0 disables the scheduler time slice extension feature.
v3:
https://lore.kernel.org/all/20250502015955.3146733-1-prakash.sangappa@oracle.com
- Addressing review comments by Sebastian and Prateek.
* Rename rseq_sched_delay -> sched_time_delay. Move its place in
struct task_struct near other bits so it fits in existing word.
* Use IS_ENABLED(CONFIG_RSEQ) instead of #ifdef to access
'sched_time_delay'.
* removed rseq_delay_resched_tick() call from hrtick_clear().
* Introduced a patch to add a tracepoint in exit_to_user_mode_loop(),
suggested by Sebastian.
* Added comments to describe RSEQ_CS_FLAG_DELAY_RESCHED flag.
v4:
- Changed default sched delay extension time to 30us
- Added patch to indicate to userspace if the thread got preempted in
the extended cpu time granted. Uses another bit in rseq cs flags for it.
This should help the application to check and avoid having to call a
system call to yield cpu, especially sched_yield() as pointed out
by Steven Rostedt.
- Moved tracepoint call towards end of exit_to_user_mode_loop().
- Added a pr_warn() message when the 'sched_preempt_delay_us' tunable is
set higher then the default value of 30us.
- Patch to add an API to query if sched time extension feature is supported.
A new flag to sys_rseq flags argument called 'RSEQ_FLAG_QUERY_CS_FLAGS',
is added, as suggested by Mathieu Desnoyers.
Returns bitmask of all the supported rseq cs flags, in rseq->flags field.
Prakash Sangappa (6):
Sched: Scheduler time slice extension
Sched: Indicate if thread got rescheduled
Sched: Tunable to specify duration of time slice extension
Sched: Add scheduler stat for cpu time slice extension
Sched: Add tracepoint for sched time slice extension
Add API to query supported rseq cs flags
include/linux/entry-common.h | 11 ++--
include/linux/sched.h | 23 +++++++++
include/trace/events/sched.h | 28 +++++++++++
include/uapi/linux/rseq.h | 19 +++++++
kernel/entry/common.c | 27 ++++++++--
kernel/rseq.c | 97 ++++++++++++++++++++++++++++++++++++
kernel/sched/core.c | 50 +++++++++++++++++++
kernel/sched/debug.c | 1 +
kernel/sched/syscalls.c | 5 ++
9 files changed, 253 insertions(+), 8 deletions(-)
--
2.43.5
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH V4 1/6] Sched: Scheduler time slice extension
2025-05-13 21:45 [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
@ 2025-05-13 21:45 ` Prakash Sangappa
2025-05-14 10:58 ` Madadi Vineeth Reddy
2025-05-23 20:06 ` Mathieu Desnoyers
2025-05-13 21:45 ` [PATCH V4 2/6] Sched: Indicate if thread got rescheduled Prakash Sangappa
` (5 subsequent siblings)
6 siblings, 2 replies; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-13 21:45 UTC (permalink / raw)
To: linux-kernel
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy, kprateek.nayak
Add support for a thread to request extending its execution time slice on
the cpu. The extra cpu time granted would help in allowing the thread to
complete executing the critical section and drop any locks without getting
preempted. The thread would request this cpu time extension, by setting a
bit in the restartable sequences(rseq) structure registered with the kernel.
Kernel will grant a 30us extension on the cpu, when it sees the bit set.
With the help of a timer, kernel force preempts the thread if it is still
running on the cpu when the 30us timer expires. The thread should yield
the cpu by making a system call after completing the critical section.
Suggested-by: Peter Ziljstra <peterz@infradead.org>
Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
---
include/linux/entry-common.h | 11 +++++--
include/linux/sched.h | 16 +++++++++++
include/uapi/linux/rseq.h | 7 +++++
kernel/entry/common.c | 19 ++++++++----
kernel/rseq.c | 56 ++++++++++++++++++++++++++++++++++++
kernel/sched/core.c | 14 +++++++++
kernel/sched/syscalls.c | 5 ++++
7 files changed, 120 insertions(+), 8 deletions(-)
diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
index fc61d0205c97..cec343f95210 100644
--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -303,7 +303,8 @@ void arch_do_signal_or_restart(struct pt_regs *regs);
* exit_to_user_mode_loop - do any pending work before leaving to user space
*/
unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
- unsigned long ti_work);
+ unsigned long ti_work,
+ bool irq);
/**
* exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
@@ -315,7 +316,8 @@ unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
* EXIT_TO_USER_MODE_WORK are set
* 4) check that interrupts are still disabled
*/
-static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
+static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs,
+ bool irq)
{
unsigned long ti_work;
@@ -326,7 +328,10 @@ static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
ti_work = read_thread_flags();
if (unlikely(ti_work & EXIT_TO_USER_MODE_WORK))
- ti_work = exit_to_user_mode_loop(regs, ti_work);
+ ti_work = exit_to_user_mode_loop(regs, ti_work, irq);
+
+ if (irq)
+ rseq_delay_resched_fini();
arch_exit_to_user_mode_prepare(regs, ti_work);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c08fd199be4e..14bf0508bfca 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -339,6 +339,7 @@ extern int __must_check io_schedule_prepare(void);
extern void io_schedule_finish(int token);
extern long io_schedule_timeout(long timeout);
extern void io_schedule(void);
+extern void hrtick_local_start(u64 delay);
/* wrapper function to trace from this header file */
DECLARE_TRACEPOINT(sched_set_state_tp);
@@ -1044,6 +1045,7 @@ struct task_struct {
/* delay due to memory thrashing */
unsigned in_thrashing:1;
#endif
+ unsigned sched_time_delay:1;
#ifdef CONFIG_PREEMPT_RT
struct netdev_xmit net_xmit;
#endif
@@ -2249,6 +2251,20 @@ static inline bool owner_on_cpu(struct task_struct *owner)
unsigned long sched_cpu_util(int cpu);
#endif /* CONFIG_SMP */
+#ifdef CONFIG_RSEQ
+
+extern bool rseq_delay_resched(void);
+extern void rseq_delay_resched_fini(void);
+extern void rseq_delay_resched_tick(void);
+
+#else
+
+static inline bool rseq_delay_resched(void) { return false; }
+static inline void rseq_delay_resched_fini(void) { }
+static inline void rseq_delay_resched_tick(void) { }
+
+#endif
+
#ifdef CONFIG_SCHED_CORE
extern void sched_core_free(struct task_struct *tsk);
extern void sched_core_fork(struct task_struct *p);
diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h
index c233aae5eac9..25fc636b17d5 100644
--- a/include/uapi/linux/rseq.h
+++ b/include/uapi/linux/rseq.h
@@ -26,6 +26,7 @@ enum rseq_cs_flags_bit {
RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0,
RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1,
RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2,
+ RSEQ_CS_FLAG_DELAY_RESCHED_BIT = 3,
};
enum rseq_cs_flags {
@@ -35,6 +36,8 @@ enum rseq_cs_flags {
(1U << RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT),
RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE =
(1U << RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT),
+ RSEQ_CS_FLAG_DELAY_RESCHED =
+ (1U << RSEQ_CS_FLAG_DELAY_RESCHED_BIT),
};
/*
@@ -128,6 +131,10 @@ struct rseq {
* - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE
* Inhibit instruction sequence block restart on migration for
* this thread.
+ * - RSEQ_CS_FLAG_DELAY_RESCHED
+ * Request by user thread to delay preemption. With use
+ * of a timer, kernel grants extra cpu time upto 30us for this
+ * thread before being rescheduled.
*/
__u32 flags;
diff --git a/kernel/entry/common.c b/kernel/entry/common.c
index 20154572ede9..b26adccb32df 100644
--- a/kernel/entry/common.c
+++ b/kernel/entry/common.c
@@ -88,7 +88,8 @@ void __weak arch_do_signal_or_restart(struct pt_regs *regs) { }
* @ti_work: TIF work flags as read by the caller
*/
__always_inline unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
- unsigned long ti_work)
+ unsigned long ti_work,
+ bool irq)
{
/*
* Before returning to user space ensure that all pending work
@@ -98,8 +99,12 @@ __always_inline unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
local_irq_enable_exit_to_user(ti_work);
- if (ti_work & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY))
- schedule();
+ if (ti_work & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY)) {
+ if (irq && rseq_delay_resched())
+ clear_tsk_need_resched(current);
+ else
+ schedule();
+ }
if (ti_work & _TIF_UPROBE)
uprobe_notify_resume(regs);
@@ -184,6 +189,10 @@ static void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
CT_WARN_ON(ct_state() != CT_STATE_KERNEL);
+ /* reschedule if sched delay was granted */
+ if (IS_ENABLED(CONFIG_RSEQ) && current->sched_time_delay)
+ set_tsk_need_resched(current);
+
if (IS_ENABLED(CONFIG_PROVE_LOCKING)) {
if (WARN(irqs_disabled(), "syscall %lu left IRQs disabled", nr))
local_irq_enable();
@@ -204,7 +213,7 @@ static __always_inline void __syscall_exit_to_user_mode_work(struct pt_regs *reg
{
syscall_exit_to_user_mode_prepare(regs);
local_irq_disable_exit_to_user();
- exit_to_user_mode_prepare(regs);
+ exit_to_user_mode_prepare(regs, false);
}
void syscall_exit_to_user_mode_work(struct pt_regs *regs)
@@ -228,7 +237,7 @@ noinstr void irqentry_enter_from_user_mode(struct pt_regs *regs)
noinstr void irqentry_exit_to_user_mode(struct pt_regs *regs)
{
instrumentation_begin();
- exit_to_user_mode_prepare(regs);
+ exit_to_user_mode_prepare(regs, true);
instrumentation_end();
exit_to_user_mode();
}
diff --git a/kernel/rseq.c b/kernel/rseq.c
index b7a1ec327e81..dba44ca9f624 100644
--- a/kernel/rseq.c
+++ b/kernel/rseq.c
@@ -448,6 +448,62 @@ void __rseq_handle_notify_resume(struct ksignal *ksig, struct pt_regs *regs)
force_sigsegv(sig);
}
+bool rseq_delay_resched(void)
+{
+ struct task_struct *t = current;
+ u32 flags;
+
+ if (!IS_ENABLED(CONFIG_SCHED_HRTICK))
+ return false;
+
+ if (!t->rseq)
+ return false;
+
+ if (t->sched_time_delay)
+ return false;
+
+ if (copy_from_user_nofault(&flags, &t->rseq->flags, sizeof(flags)))
+ return false;
+
+ if (!(flags & RSEQ_CS_FLAG_DELAY_RESCHED))
+ return false;
+
+ flags &= ~RSEQ_CS_FLAG_DELAY_RESCHED;
+ if (copy_to_user_nofault(&t->rseq->flags, &flags, sizeof(flags)))
+ return false;
+
+ t->sched_time_delay = 1;
+
+ return true;
+}
+
+void rseq_delay_resched_fini(void)
+{
+#ifdef CONFIG_SCHED_HRTICK
+ extern void hrtick_local_start(u64 delay);
+ struct task_struct *t = current;
+ /*
+ * IRQs off, guaranteed to return to userspace, start timer on this CPU
+ * to limit the resched-overdraft.
+ *
+ * If your critical section is longer than 30 us you get to keep the
+ * pieces.
+ */
+ if (t->sched_time_delay)
+ hrtick_local_start(30 * NSEC_PER_USEC);
+#endif
+}
+
+void rseq_delay_resched_tick(void)
+{
+#ifdef CONFIG_SCHED_HRTICK
+ struct task_struct *t = current;
+
+ if (t->sched_time_delay)
+ set_tsk_need_resched(t);
+#endif
+}
+
#ifdef CONFIG_DEBUG_RSEQ
/*
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 4de24eefe661..8c8960245ec0 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -844,6 +844,8 @@ static enum hrtimer_restart hrtick(struct hrtimer *timer)
WARN_ON_ONCE(cpu_of(rq) != smp_processor_id());
+ rseq_delay_resched_tick();
+
rq_lock(rq, &rf);
update_rq_clock(rq);
rq->donor->sched_class->task_tick(rq, rq->curr, 1);
@@ -917,6 +919,16 @@ void hrtick_start(struct rq *rq, u64 delay)
#endif /* CONFIG_SMP */
+void hrtick_local_start(u64 delay)
+{
+ struct rq *rq = this_rq();
+ struct rq_flags rf;
+
+ rq_lock(rq, &rf);
+ hrtick_start(rq, delay);
+ rq_unlock(rq, &rf);
+}
+
static void hrtick_rq_init(struct rq *rq)
{
#ifdef CONFIG_SMP
@@ -6722,6 +6734,8 @@ static void __sched notrace __schedule(int sched_mode)
picked:
clear_tsk_need_resched(prev);
clear_preempt_need_resched();
+ if (IS_ENABLED(CONFIG_RSEQ))
+ prev->sched_time_delay = 0;
rq->last_seen_need_resched_ns = 0;
is_switch = prev != next;
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index cd38f4e9899d..1b2b64fe0fb1 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -1378,6 +1378,11 @@ static void do_sched_yield(void)
*/
SYSCALL_DEFINE0(sched_yield)
{
+ if (IS_ENABLED(CONFIG_RSEQ) && current->sched_time_delay) {
+ schedule();
+ return 0;
+ }
+
do_sched_yield();
return 0;
}
--
2.43.5
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH V4 2/6] Sched: Indicate if thread got rescheduled
2025-05-13 21:45 [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 1/6] Sched: " Prakash Sangappa
@ 2025-05-13 21:45 ` Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 3/6] Sched: Tunable to specify duration of time slice extension Prakash Sangappa
` (4 subsequent siblings)
6 siblings, 0 replies; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-13 21:45 UTC (permalink / raw)
To: linux-kernel
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy, kprateek.nayak
Use a bit in rseq flags to indicate if the thread got rescheduled
after the cpu time extension was graned. The user thread can check this
flag before calling sched_yield() to yield the cpu.
Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
---
include/linux/sched.h | 2 ++
include/uapi/linux/rseq.h | 10 ++++++++++
kernel/rseq.c | 20 ++++++++++++++++++++
kernel/sched/core.c | 3 +--
4 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 14bf0508bfca..71e6c8221c1e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2256,12 +2256,14 @@ unsigned long sched_cpu_util(int cpu);
extern bool rseq_delay_resched(void);
extern void rseq_delay_resched_fini(void);
extern void rseq_delay_resched_tick(void);
+extern void rseq_delay_schedule(void);
#else
static inline bool rseq_delay_resched(void) { return false; }
static inline void rseq_delay_resched_fini(void) { }
static inline void rseq_delay_resched_tick(void) { }
+static inline void rseq_delay_schedule(void) { }
#endif
diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h
index 25fc636b17d5..f4813d931387 100644
--- a/include/uapi/linux/rseq.h
+++ b/include/uapi/linux/rseq.h
@@ -27,6 +27,7 @@ enum rseq_cs_flags_bit {
RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1,
RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2,
RSEQ_CS_FLAG_DELAY_RESCHED_BIT = 3,
+ RSEQ_CS_FLAG_RESCHEDULED_BIT = 4,
};
enum rseq_cs_flags {
@@ -38,6 +39,9 @@ enum rseq_cs_flags {
(1U << RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT),
RSEQ_CS_FLAG_DELAY_RESCHED =
(1U << RSEQ_CS_FLAG_DELAY_RESCHED_BIT),
+ RSEQ_CS_FLAG_RESCHEDULED =
+ (1U << RSEQ_CS_FLAG_RESCHEDULED_BIT),
+
};
/*
@@ -135,6 +139,12 @@ struct rseq {
* Request by user thread to delay preemption. With use
* of a timer, kernel grants extra cpu time upto 30us for this
* thread before being rescheduled.
+ * - RSEQ_CS_FLAG_RESCHEDULED
+ * Set by kernel if the thread was rescheduled in the extra time
+ * granted due to request RSEQ_CS_DELAY_RESCHED. This bit is
+ * checked by the thread before calling sched_yield() to yield
+ * cpu. User thread sets this bit to 0, when setting
+ * RSEQ_CS_DELAY_RESCHED to request preemption delay.
*/
__u32 flags;
diff --git a/kernel/rseq.c b/kernel/rseq.c
index dba44ca9f624..9355654e9b38 100644
--- a/kernel/rseq.c
+++ b/kernel/rseq.c
@@ -504,6 +504,26 @@ void rseq_delay_resched_tick(void)
#endif
}
+void rseq_delay_schedule(void)
+{
+#ifdef CONFIG_SCHED_HRTICK
+ struct task_struct *t = current;
+ u32 flags;
+
+ if (t->sched_time_delay) {
+ t->sched_time_delay = 0;
+ if (!t->rseq)
+ return;
+ if (copy_from_user_nofault(&flags, &t->rseq->flags,
+ sizeof(flags)))
+ return;
+ flags |= RSEQ_CS_FLAG_RESCHEDULED;
+ copy_to_user_nofault(&t->rseq->flags, &flags,
+ sizeof(flags));
+ }
+#endif
+}
+
#ifdef CONFIG_DEBUG_RSEQ
/*
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 8c8960245ec0..86583fb72914 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -6734,8 +6734,7 @@ static void __sched notrace __schedule(int sched_mode)
picked:
clear_tsk_need_resched(prev);
clear_preempt_need_resched();
- if (IS_ENABLED(CONFIG_RSEQ))
- prev->sched_time_delay = 0;
+ rseq_delay_schedule();
rq->last_seen_need_resched_ns = 0;
is_switch = prev != next;
--
2.43.5
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH V4 3/6] Sched: Tunable to specify duration of time slice extension
2025-05-13 21:45 [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 1/6] Sched: " Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 2/6] Sched: Indicate if thread got rescheduled Prakash Sangappa
@ 2025-05-13 21:45 ` Prakash Sangappa
2025-05-14 11:21 ` kernel test robot
2025-05-13 21:45 ` [PATCH V4 4/6] Sched: Add scheduler stat for cpu " Prakash Sangappa
` (3 subsequent siblings)
6 siblings, 1 reply; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-13 21:45 UTC (permalink / raw)
To: linux-kernel
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy, kprateek.nayak
Add a tunable to specify duration of scheduler time slice extension.
The default will be set to 30us and the max value that can be specified
is 100us. Setting it to 0, disables scheduler time slice extension.
Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
---
include/linux/sched.h | 3 +++
include/uapi/linux/rseq.h | 5 +++--
kernel/rseq.c | 7 +++++--
kernel/sched/core.c | 32 ++++++++++++++++++++++++++++++++
4 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 71e6c8221c1e..c279232ca6a2 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -407,6 +407,9 @@ static inline void sched_domains_mutex_lock(void) { }
static inline void sched_domains_mutex_unlock(void) { }
#endif
+/* Scheduler time slice extension */
+extern unsigned int sysctl_sched_preempt_delay_us;
+
struct sched_param {
int sched_priority;
};
diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h
index f4813d931387..015534f064af 100644
--- a/include/uapi/linux/rseq.h
+++ b/include/uapi/linux/rseq.h
@@ -137,8 +137,9 @@ struct rseq {
* this thread.
* - RSEQ_CS_FLAG_DELAY_RESCHED
* Request by user thread to delay preemption. With use
- * of a timer, kernel grants extra cpu time upto 30us for this
- * thread before being rescheduled.
+ * of a timer, kernel grants extra cpu time upto the tunable
+ * 'sched_preempt_delay_us' value for this thread before it gets
+ * rescheduled.
* - RSEQ_CS_FLAG_RESCHEDULED
* Set by kernel if the thread was rescheduled in the extra time
* granted due to request RSEQ_CS_DELAY_RESCHED. This bit is
diff --git a/kernel/rseq.c b/kernel/rseq.c
index 9355654e9b38..44d0f3ae0cd3 100644
--- a/kernel/rseq.c
+++ b/kernel/rseq.c
@@ -456,6 +456,8 @@ bool rseq_delay_resched(void)
if (!IS_ENABLED(CONFIG_SCHED_HRTICK))
return false;
+ if (!sysctl_sched_preempt_delay_us)
+ return false;
if (!t->rseq)
return false;
@@ -489,8 +491,9 @@ void rseq_delay_resched_fini(void)
* If your critical section is longer than 30 us you get to keep the
* pieces.
*/
- if (t->sched_time_delay)
- hrtick_local_start(30 * NSEC_PER_USEC);
+ if (sysctl_sched_preempt_delay_us && t->sched_time_delay)
+ hrtick_local_start(sysctl_sched_preempt_delay_us *
+ NSEC_PER_USEC);
#endif
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 86583fb72914..31928cbcd907 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -148,6 +148,15 @@ __read_mostly int sysctl_resched_latency_warn_once = 1;
*/
__read_mostly unsigned int sysctl_sched_nr_migrate = SCHED_NR_MIGRATE_BREAK;
+/*
+ * Scheduler time slice extension, duration in microsecs.
+ * Max value allowed 100us, default is 30us.
+ * If set to 0, scheduler time slice extension is disabled.
+ */
+#define SCHED_PREEMPT_DELAY_DEFAULT_US 30
+__read_mostly unsigned int sysctl_sched_preempt_delay_us =
+ SCHED_PREEMPT_DELAY_DEFAULT_US;
+
__read_mostly int scheduler_running;
#ifdef CONFIG_SCHED_CORE
@@ -4664,6 +4673,20 @@ static int sysctl_schedstats(const struct ctl_table *table, int write, void *buf
#endif /* CONFIG_PROC_SYSCTL */
#endif /* CONFIG_SCHEDSTATS */
+static int sysctl_sched_preempt_delay(const struct ctl_table *table, int write,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ int err;
+
+ err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+ if (err < 0)
+ return err;
+ if (sysctl_sched_preempt_delay_us > SCHED_PREEMPT_DELAY_DEFAULT_US)
+ pr_warn("Sched preemption delay time set higher then default value %d us\n",
+ SCHED_PREEMPT_DELAY_DEFAULT_US);
+ return err;
+}
+
#ifdef CONFIG_SYSCTL
static const struct ctl_table sched_core_sysctls[] = {
#ifdef CONFIG_SCHEDSTATS
@@ -4711,6 +4734,15 @@ static const struct ctl_table sched_core_sysctls[] = {
.extra2 = SYSCTL_FOUR,
},
#endif /* CONFIG_NUMA_BALANCING */
+ {
+ .procname = "sched_preempt_delay_us",
+ .data = &sysctl_sched_preempt_delay_us,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = sysctl_sched_preempt_delay,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE_HUNDRED,
+ },
};
static int __init sched_core_sysctl_init(void)
{
--
2.43.5
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH V4 4/6] Sched: Add scheduler stat for cpu time slice extension
2025-05-13 21:45 [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
` (2 preceding siblings ...)
2025-05-13 21:45 ` [PATCH V4 3/6] Sched: Tunable to specify duration of time slice extension Prakash Sangappa
@ 2025-05-13 21:45 ` Prakash Sangappa
2025-05-14 12:37 ` Madadi Vineeth Reddy
2025-05-13 21:45 ` [PATCH V4 5/6] Sched: Add tracepoint for sched " Prakash Sangappa
` (2 subsequent siblings)
6 siblings, 1 reply; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-13 21:45 UTC (permalink / raw)
To: linux-kernel
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy, kprateek.nayak
Add scheduler stat to record number of times the thread was granted
cpu time slice extension.
Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
---
include/linux/sched.h | 2 ++
kernel/rseq.c | 1 +
kernel/sched/core.c | 5 +++++
kernel/sched/debug.c | 1 +
4 files changed, 9 insertions(+)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c279232ca6a2..8cf756e80ae9 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -340,6 +340,7 @@ extern void io_schedule_finish(int token);
extern long io_schedule_timeout(long timeout);
extern void io_schedule(void);
extern void hrtick_local_start(u64 delay);
+extern void update_stat_preempt_delayed(struct task_struct *t);
/* wrapper function to trace from this header file */
DECLARE_TRACEPOINT(sched_set_state_tp);
@@ -563,6 +564,7 @@ struct sched_statistics {
u64 nr_wakeups_affine_attempts;
u64 nr_wakeups_passive;
u64 nr_wakeups_idle;
+ u64 nr_preempt_delay_granted;
#ifdef CONFIG_SCHED_CORE
u64 core_forceidle_sum;
diff --git a/kernel/rseq.c b/kernel/rseq.c
index 44d0f3ae0cd3..c4bc52f8ba9c 100644
--- a/kernel/rseq.c
+++ b/kernel/rseq.c
@@ -475,6 +475,7 @@ bool rseq_delay_resched(void)
return false;
t->sched_time_delay = 1;
+ update_stat_preempt_delayed(t);
return true;
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 31928cbcd907..880368756b48 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -938,6 +938,11 @@ void hrtick_local_start(u64 delay)
rq_unlock(rq, &rf);
}
+void update_stat_preempt_delayed(struct task_struct *t)
+{
+ schedstat_inc(t->stats.nr_preempt_delay_granted);
+}
+
static void hrtick_rq_init(struct rq *rq)
{
#ifdef CONFIG_SMP
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 4cba21f5d24d..6b753f56c312 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -1216,6 +1216,7 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
P_SCHEDSTAT(nr_wakeups_affine_attempts);
P_SCHEDSTAT(nr_wakeups_passive);
P_SCHEDSTAT(nr_wakeups_idle);
+ P_SCHEDSTAT(nr_preempt_delay_granted);
avg_atom = p->se.sum_exec_runtime;
if (nr_switches)
--
2.43.5
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH V4 5/6] Sched: Add tracepoint for sched time slice extension
2025-05-13 21:45 [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
` (3 preceding siblings ...)
2025-05-13 21:45 ` [PATCH V4 4/6] Sched: Add scheduler stat for cpu " Prakash Sangappa
@ 2025-05-13 21:45 ` Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 6/6] Add API to query supported rseq cs flags Prakash Sangappa
2025-05-20 21:01 ` [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
6 siblings, 0 replies; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-13 21:45 UTC (permalink / raw)
To: linux-kernel
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy, kprateek.nayak
Trace thread's preemption getting delayed. Which can occur if
the running thread requested extra time on cpu. Also, indicate
the NEED_RESCHED flag, that is set on the thread, getting cleared.
Suggested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
---
include/trace/events/sched.h | 28 ++++++++++++++++++++++++++++
kernel/entry/common.c | 12 ++++++++++--
2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 8994e97d86c1..4aa04044b14a 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -296,6 +296,34 @@ TRACE_EVENT(sched_migrate_task,
__entry->orig_cpu, __entry->dest_cpu)
);
+/*
+ * Tracepoint for delayed resched requested by task:
+ */
+TRACE_EVENT(sched_delay_resched,
+
+ TP_PROTO(struct task_struct *p, unsigned int resched_flg),
+
+ TP_ARGS(p, resched_flg),
+
+ TP_STRUCT__entry(
+ __array( char, comm, TASK_COMM_LEN )
+ __field( pid_t, pid )
+ __field( int, cpu )
+ __field( int, flg )
+ ),
+
+ TP_fast_assign(
+ memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
+ __entry->pid = p->pid;
+ __entry->cpu = task_cpu(p);
+ __entry->flg = resched_flg;
+ ),
+
+ TP_printk("comm=%s pid=%d cpu=%d resched_flg_cleared=0x%x",
+ __entry->comm, __entry->pid, __entry->cpu, __entry->flg)
+
+);
+
DECLARE_EVENT_CLASS(sched_process_template,
TP_PROTO(struct task_struct *p),
diff --git a/kernel/entry/common.c b/kernel/entry/common.c
index b26adccb32df..cd0f076920fd 100644
--- a/kernel/entry/common.c
+++ b/kernel/entry/common.c
@@ -12,6 +12,7 @@
#include "common.h"
+#include <trace/events/sched.h>
#define CREATE_TRACE_POINTS
#include <trace/events/syscalls.h>
@@ -91,6 +92,7 @@ __always_inline unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
unsigned long ti_work,
bool irq)
{
+ unsigned long ti_work_cleared = 0;
/*
* Before returning to user space ensure that all pending work
* items have been completed.
@@ -100,10 +102,12 @@ __always_inline unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
local_irq_enable_exit_to_user(ti_work);
if (ti_work & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY)) {
- if (irq && rseq_delay_resched())
+ if (irq && rseq_delay_resched()) {
clear_tsk_need_resched(current);
- else
+ ti_work_cleared = ti_work;
+ } else {
schedule();
+ }
}
if (ti_work & _TIF_UPROBE)
@@ -134,6 +138,10 @@ __always_inline unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
ti_work = read_thread_flags();
}
+ if (ti_work_cleared)
+ trace_sched_delay_resched(current, ti_work_cleared &
+ (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY));
+
/* Return the latest work state for arch_exit_to_user_mode() */
return ti_work;
}
--
2.43.5
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH V4 6/6] Add API to query supported rseq cs flags
2025-05-13 21:45 [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
` (4 preceding siblings ...)
2025-05-13 21:45 ` [PATCH V4 5/6] Sched: Add tracepoint for sched " Prakash Sangappa
@ 2025-05-13 21:45 ` Prakash Sangappa
2025-05-23 19:57 ` Mathieu Desnoyers
2025-05-20 21:01 ` [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
6 siblings, 1 reply; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-13 21:45 UTC (permalink / raw)
To: linux-kernel
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy, kprateek.nayak
For the API, add a new flag to sys_rseq 'flags' argument called
RSEQ_FLAG_QUERY_CS_FLAGS.
When this flag is passed it returns a bit mask of all the supported
rseq cs flags in the user provided rseq struct's 'flags' member.
Suggested-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
---
include/uapi/linux/rseq.h | 1 +
kernel/rseq.c | 17 +++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h
index 015534f064af..44baea9dd10a 100644
--- a/include/uapi/linux/rseq.h
+++ b/include/uapi/linux/rseq.h
@@ -20,6 +20,7 @@ enum rseq_cpu_id_state {
enum rseq_flags {
RSEQ_FLAG_UNREGISTER = (1 << 0),
+ RSEQ_FLAG_QUERY_CS_FLAGS = (1 << 1),
};
enum rseq_cs_flags_bit {
diff --git a/kernel/rseq.c b/kernel/rseq.c
index c4bc52f8ba9c..997f7ca722ca 100644
--- a/kernel/rseq.c
+++ b/kernel/rseq.c
@@ -576,6 +576,23 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
return 0;
}
+ /*
+ * return supported rseq_cs flags
+ * It is an or of all the rseq_cs_flags;
+ */
+ if (flags & RSEQ_FLAG_QUERY_CS_FLAGS) {
+ u32 rseq_csflags = RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT |
+ RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL |
+ RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE |
+ RSEQ_CS_FLAG_DELAY_RESCHED |
+ RSEQ_CS_FLAG_RESCHEDULED;
+ if (!rseq)
+ return -EINVAL;
+ if (copy_to_user(&rseq->flags, &rseq_csflags, sizeof(u32)))
+ return -EFAULT;
+ return 0;
+ }
+
if (unlikely(flags))
return -EINVAL;
--
2.43.5
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 1/6] Sched: Scheduler time slice extension
2025-05-13 21:45 ` [PATCH V4 1/6] Sched: " Prakash Sangappa
@ 2025-05-14 10:58 ` Madadi Vineeth Reddy
2025-05-14 23:12 ` Prakash Sangappa
2025-05-23 20:06 ` Mathieu Desnoyers
1 sibling, 1 reply; 20+ messages in thread
From: Madadi Vineeth Reddy @ 2025-05-14 10:58 UTC (permalink / raw)
To: Prakash Sangappa
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy,
kprateek.nayak, linux-kernel, Madadi Vineeth Reddy
Hi Prakash,
On 14/05/25 03:15, Prakash Sangappa wrote:
> Add support for a thread to request extending its execution time slice on
> the cpu. The extra cpu time granted would help in allowing the thread to
> complete executing the critical section and drop any locks without getting
> preempted. The thread would request this cpu time extension, by setting a
> bit in the restartable sequences(rseq) structure registered with the kernel.
>
> Kernel will grant a 30us extension on the cpu, when it sees the bit set.
> With the help of a timer, kernel force preempts the thread if it is still
> running on the cpu when the 30us timer expires. The thread should yield
> the cpu by making a system call after completing the critical section.
>
> Suggested-by: Peter Ziljstra <peterz@infradead.org>
> Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
> ---
> include/linux/entry-common.h | 11 +++++--
> include/linux/sched.h | 16 +++++++++++
> include/uapi/linux/rseq.h | 7 +++++
> kernel/entry/common.c | 19 ++++++++----
> kernel/rseq.c | 56 ++++++++++++++++++++++++++++++++++++
> kernel/sched/core.c | 14 +++++++++
> kernel/sched/syscalls.c | 5 ++++
> 7 files changed, 120 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
> index fc61d0205c97..cec343f95210 100644
> --- a/include/linux/entry-common.h
> +++ b/include/linux/entry-common.h
> @@ -303,7 +303,8 @@ void arch_do_signal_or_restart(struct pt_regs *regs);
> * exit_to_user_mode_loop - do any pending work before leaving to user space
> */
> unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
> - unsigned long ti_work);
> + unsigned long ti_work,
> + bool irq);
>
> /**
> * exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
> @@ -315,7 +316,8 @@ unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
> * EXIT_TO_USER_MODE_WORK are set
> * 4) check that interrupts are still disabled
> */
> -static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
> +static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs,
> + bool irq)
> {
> unsigned long ti_work;
>
> @@ -326,7 +328,10 @@ static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
>
> ti_work = read_thread_flags();
> if (unlikely(ti_work & EXIT_TO_USER_MODE_WORK))
> - ti_work = exit_to_user_mode_loop(regs, ti_work);
> + ti_work = exit_to_user_mode_loop(regs, ti_work, irq);
> +
> + if (irq)
> + rseq_delay_resched_fini();
>
> arch_exit_to_user_mode_prepare(regs, ti_work);
>
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index c08fd199be4e..14bf0508bfca 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -339,6 +339,7 @@ extern int __must_check io_schedule_prepare(void);
> extern void io_schedule_finish(int token);
> extern long io_schedule_timeout(long timeout);
> extern void io_schedule(void);
> +extern void hrtick_local_start(u64 delay);
>
> /* wrapper function to trace from this header file */
> DECLARE_TRACEPOINT(sched_set_state_tp);
> @@ -1044,6 +1045,7 @@ struct task_struct {
> /* delay due to memory thrashing */
> unsigned in_thrashing:1;
> #endif
> + unsigned sched_time_delay:1;
Can this be placed in #ifdef CONFIG_RSEQ?
> #ifdef CONFIG_PREEMPT_RT
> struct netdev_xmit net_xmit;
> #endif
[..snip..]
> diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
> index cd38f4e9899d..1b2b64fe0fb1 100644
> --- a/kernel/sched/syscalls.c
> +++ b/kernel/sched/syscalls.c
> @@ -1378,6 +1378,11 @@ static void do_sched_yield(void)
> */
> SYSCALL_DEFINE0(sched_yield)
> {
> + if (IS_ENABLED(CONFIG_RSEQ) && current->sched_time_delay) {
> + schedule();
> + return 0;
> + }
> +
> do_sched_yield();
> return 0;
> }
As mentioned in previous versions, does this not change the semantics for
sched_yield()? Why is this necessary to immediately call schedule() and skip
going through do_sched_yield()?
For a task if a delay is granted on CPU A, but the task migrates to CPU B before
the IRQ-return hook, the timer never fires and the thread might overrun its bonus?
Any thoughts on this?
Thanks,
Madadi Vineeth Reddy
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 3/6] Sched: Tunable to specify duration of time slice extension
2025-05-13 21:45 ` [PATCH V4 3/6] Sched: Tunable to specify duration of time slice extension Prakash Sangappa
@ 2025-05-14 11:21 ` kernel test robot
0 siblings, 0 replies; 20+ messages in thread
From: kernel test robot @ 2025-05-14 11:21 UTC (permalink / raw)
To: Prakash Sangappa, linux-kernel
Cc: oe-kbuild-all, rostedt, mathieu.desnoyers, tglx, bigeasy, kprateek.nayak
Hi Prakash,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tip/sched/core]
[also build test WARNING on peterz-queue/sched/core linus/master v6.15-rc6]
[cannot apply to tip/core/entry next-20250513]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Prakash-Sangappa/Sched-Scheduler-time-slice-extension/20250514-054844
base: tip/sched/core
patch link: https://lore.kernel.org/r/20250513214554.4160454-4-prakash.sangappa%40oracle.com
patch subject: [PATCH V4 3/6] Sched: Tunable to specify duration of time slice extension
config: arm-randconfig-003-20250514 (https://download.01.org/0day-ci/archive/20250514/202505142126.0irJYJgE-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 7.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250514/202505142126.0irJYJgE-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505142126.0irJYJgE-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> kernel/sched/core.c:4682:12: warning: 'sysctl_sched_preempt_delay' defined but not used [-Wunused-function]
static int sysctl_sched_preempt_delay(const struct ctl_table *table, int write,
^~~~~~~~~~~~~~~~~~~~~~~~~~
vim +/sysctl_sched_preempt_delay +4682 kernel/sched/core.c
4681
> 4682 static int sysctl_sched_preempt_delay(const struct ctl_table *table, int write,
4683 void *buffer, size_t *lenp, loff_t *ppos)
4684 {
4685 int err;
4686
4687 err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
4688 if (err < 0)
4689 return err;
4690 if (sysctl_sched_preempt_delay_us > SCHED_PREEMPT_DELAY_DEFAULT_US)
4691 pr_warn("Sched preemption delay time set higher then default value %d us\n",
4692 SCHED_PREEMPT_DELAY_DEFAULT_US);
4693 return err;
4694 }
4695
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 4/6] Sched: Add scheduler stat for cpu time slice extension
2025-05-13 21:45 ` [PATCH V4 4/6] Sched: Add scheduler stat for cpu " Prakash Sangappa
@ 2025-05-14 12:37 ` Madadi Vineeth Reddy
2025-05-14 23:01 ` Prakash Sangappa
0 siblings, 1 reply; 20+ messages in thread
From: Madadi Vineeth Reddy @ 2025-05-14 12:37 UTC (permalink / raw)
To: Prakash Sangappa
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy,
kprateek.nayak, linux-kernel, Madadi Vineeth Reddy
On 14/05/25 03:15, Prakash Sangappa wrote:
> Add scheduler stat to record number of times the thread was granted
> cpu time slice extension.
>
> Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
> ---
> include/linux/sched.h | 2 ++
> kernel/rseq.c | 1 +
> kernel/sched/core.c | 5 +++++
> kernel/sched/debug.c | 1 +
> 4 files changed, 9 insertions(+)
>
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index c279232ca6a2..8cf756e80ae9 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -340,6 +340,7 @@ extern void io_schedule_finish(int token);
> extern long io_schedule_timeout(long timeout);
> extern void io_schedule(void);
> extern void hrtick_local_start(u64 delay);
> +extern void update_stat_preempt_delayed(struct task_struct *t);
>
> /* wrapper function to trace from this header file */
> DECLARE_TRACEPOINT(sched_set_state_tp);
> @@ -563,6 +564,7 @@ struct sched_statistics {
> u64 nr_wakeups_affine_attempts;
> u64 nr_wakeups_passive;
> u64 nr_wakeups_idle;
> + u64 nr_preempt_delay_granted;
>
> #ifdef CONFIG_SCHED_CORE
> u64 core_forceidle_sum;
> diff --git a/kernel/rseq.c b/kernel/rseq.c
> index 44d0f3ae0cd3..c4bc52f8ba9c 100644
> --- a/kernel/rseq.c
> +++ b/kernel/rseq.c
> @@ -475,6 +475,7 @@ bool rseq_delay_resched(void)
> return false;
>
> t->sched_time_delay = 1;
> + update_stat_preempt_delayed(t);
>
> return true;
> }
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 31928cbcd907..880368756b48 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -938,6 +938,11 @@ void hrtick_local_start(u64 delay)
> rq_unlock(rq, &rf);
> }
>
> +void update_stat_preempt_delayed(struct task_struct *t)
> +{
> + schedstat_inc(t->stats.nr_preempt_delay_granted);
I think schedstat documentation also needs to be updated
and may be bump the version number.
Thanks,
Madadi Vineeth Reddy
> +}
> +
> static void hrtick_rq_init(struct rq *rq)
> {
> #ifdef CONFIG_SMP
> diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
> index 4cba21f5d24d..6b753f56c312 100644
> --- a/kernel/sched/debug.c
> +++ b/kernel/sched/debug.c
> @@ -1216,6 +1216,7 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
> P_SCHEDSTAT(nr_wakeups_affine_attempts);
> P_SCHEDSTAT(nr_wakeups_passive);
> P_SCHEDSTAT(nr_wakeups_idle);
> + P_SCHEDSTAT(nr_preempt_delay_granted);
>
> avg_atom = p->se.sum_exec_runtime;
> if (nr_switches)
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 4/6] Sched: Add scheduler stat for cpu time slice extension
2025-05-14 12:37 ` Madadi Vineeth Reddy
@ 2025-05-14 23:01 ` Prakash Sangappa
0 siblings, 0 replies; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-14 23:01 UTC (permalink / raw)
To: Madadi Vineeth Reddy
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy,
kprateek.nayak, linux-kernel
> On May 14, 2025, at 5:37 AM, Madadi Vineeth Reddy <vineethr@linux.ibm.com> wrote:
>
> On 14/05/25 03:15, Prakash Sangappa wrote:
>> Add scheduler stat to record number of times the thread was granted
>> cpu time slice extension.
>>
>> Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
>> ---
>> include/linux/sched.h | 2 ++
>> kernel/rseq.c | 1 +
>> kernel/sched/core.c | 5 +++++
>> kernel/sched/debug.c | 1 +
>> 4 files changed, 9 insertions(+)
>>
>> diff --git a/include/linux/sched.h b/include/linux/sched.h
>> index c279232ca6a2..8cf756e80ae9 100644
>> --- a/include/linux/sched.h
>> +++ b/include/linux/sched.h
>> @@ -340,6 +340,7 @@ extern void io_schedule_finish(int token);
>> extern long io_schedule_timeout(long timeout);
>> extern void io_schedule(void);
>> extern void hrtick_local_start(u64 delay);
>> +extern void update_stat_preempt_delayed(struct task_struct *t);
>>
>> /* wrapper function to trace from this header file */
>> DECLARE_TRACEPOINT(sched_set_state_tp);
>> @@ -563,6 +564,7 @@ struct sched_statistics {
>> u64 nr_wakeups_affine_attempts;
>> u64 nr_wakeups_passive;
>> u64 nr_wakeups_idle;
>> + u64 nr_preempt_delay_granted;
>>
>> #ifdef CONFIG_SCHED_CORE
>> u64 core_forceidle_sum;
>> diff --git a/kernel/rseq.c b/kernel/rseq.c
>> index 44d0f3ae0cd3..c4bc52f8ba9c 100644
>> --- a/kernel/rseq.c
>> +++ b/kernel/rseq.c
>> @@ -475,6 +475,7 @@ bool rseq_delay_resched(void)
>> return false;
>>
>> t->sched_time_delay = 1;
>> + update_stat_preempt_delayed(t);
>>
>> return true;
>> }
>> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
>> index 31928cbcd907..880368756b48 100644
>> --- a/kernel/sched/core.c
>> +++ b/kernel/sched/core.c
>> @@ -938,6 +938,11 @@ void hrtick_local_start(u64 delay)
>> rq_unlock(rq, &rf);
>> }
>>
>> +void update_stat_preempt_delayed(struct task_struct *t)
>> +{
>> + schedstat_inc(t->stats.nr_preempt_delay_granted);
>
> I think schedstat documentation also needs to be updated
> and may be bump the version number.
Will update documentation.
-Prakash
>
> Thanks,
> Madadi Vineeth Reddy
>
>> +}
>> +
>> static void hrtick_rq_init(struct rq *rq)
>> {
>> #ifdef CONFIG_SMP
>> diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
>> index 4cba21f5d24d..6b753f56c312 100644
>> --- a/kernel/sched/debug.c
>> +++ b/kernel/sched/debug.c
>> @@ -1216,6 +1216,7 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
>> P_SCHEDSTAT(nr_wakeups_affine_attempts);
>> P_SCHEDSTAT(nr_wakeups_passive);
>> P_SCHEDSTAT(nr_wakeups_idle);
>> + P_SCHEDSTAT(nr_preempt_delay_granted);
>>
>> avg_atom = p->se.sum_exec_runtime;
>> if (nr_switches)
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 1/6] Sched: Scheduler time slice extension
2025-05-14 10:58 ` Madadi Vineeth Reddy
@ 2025-05-14 23:12 ` Prakash Sangappa
2025-05-15 9:01 ` Steven Rostedt
0 siblings, 1 reply; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-14 23:12 UTC (permalink / raw)
To: Madadi Vineeth Reddy
Cc: peterz, rostedt, mathieu.desnoyers, tglx, bigeasy,
kprateek.nayak, linux-kernel
> On May 14, 2025, at 3:58 AM, Madadi Vineeth Reddy <vineethr@linux.ibm.com> wrote:
>
> Hi Prakash,
>
> On 14/05/25 03:15, Prakash Sangappa wrote:
>> Add support for a thread to request extending its execution time slice on
>> the cpu. The extra cpu time granted would help in allowing the thread to
>> complete executing the critical section and drop any locks without getting
>> preempted. The thread would request this cpu time extension, by setting a
>> bit in the restartable sequences(rseq) structure registered with the kernel.
>>
>> Kernel will grant a 30us extension on the cpu, when it sees the bit set.
>> With the help of a timer, kernel force preempts the thread if it is still
>> running on the cpu when the 30us timer expires. The thread should yield
>> the cpu by making a system call after completing the critical section.
>>
>> Suggested-by: Peter Ziljstra <peterz@infradead.org>
>> Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
>> ---
>> include/linux/entry-common.h | 11 +++++--
>> include/linux/sched.h | 16 +++++++++++
>> include/uapi/linux/rseq.h | 7 +++++
>> kernel/entry/common.c | 19 ++++++++----
>> kernel/rseq.c | 56 ++++++++++++++++++++++++++++++++++++
>> kernel/sched/core.c | 14 +++++++++
>> kernel/sched/syscalls.c | 5 ++++
>> 7 files changed, 120 insertions(+), 8 deletions(-)
>>
>> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
>> index fc61d0205c97..cec343f95210 100644
>> --- a/include/linux/entry-common.h
>> +++ b/include/linux/entry-common.h
>> @@ -303,7 +303,8 @@ void arch_do_signal_or_restart(struct pt_regs *regs);
>> * exit_to_user_mode_loop - do any pending work before leaving to user space
>> */
>> unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
>> - unsigned long ti_work);
>> + unsigned long ti_work,
>> + bool irq);
>>
>> /**
>> * exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
>> @@ -315,7 +316,8 @@ unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
>> * EXIT_TO_USER_MODE_WORK are set
>> * 4) check that interrupts are still disabled
>> */
>> -static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
>> +static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs,
>> + bool irq)
>> {
>> unsigned long ti_work;
>>
>> @@ -326,7 +328,10 @@ static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
>>
>> ti_work = read_thread_flags();
>> if (unlikely(ti_work & EXIT_TO_USER_MODE_WORK))
>> - ti_work = exit_to_user_mode_loop(regs, ti_work);
>> + ti_work = exit_to_user_mode_loop(regs, ti_work, irq);
>> +
>> + if (irq)
>> + rseq_delay_resched_fini();
>>
>> arch_exit_to_user_mode_prepare(regs, ti_work);
>>
>> diff --git a/include/linux/sched.h b/include/linux/sched.h
>> index c08fd199be4e..14bf0508bfca 100644
>> --- a/include/linux/sched.h
>> +++ b/include/linux/sched.h
>> @@ -339,6 +339,7 @@ extern int __must_check io_schedule_prepare(void);
>> extern void io_schedule_finish(int token);
>> extern long io_schedule_timeout(long timeout);
>> extern void io_schedule(void);
>> +extern void hrtick_local_start(u64 delay);
>>
>> /* wrapper function to trace from this header file */
>> DECLARE_TRACEPOINT(sched_set_state_tp);
>> @@ -1044,6 +1045,7 @@ struct task_struct {
>> /* delay due to memory thrashing */
>> unsigned in_thrashing:1;
>> #endif
>> + unsigned sched_time_delay:1;
>
> Can this be placed in #ifdef CONFIG_RSEQ?
>
>> #ifdef CONFIG_PREEMPT_RT
>> struct netdev_xmit net_xmit;
>> #endif
>
> [..snip..]
>
>> diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
>> index cd38f4e9899d..1b2b64fe0fb1 100644
>> --- a/kernel/sched/syscalls.c
>> +++ b/kernel/sched/syscalls.c
>> @@ -1378,6 +1378,11 @@ static void do_sched_yield(void)
>> */
>> SYSCALL_DEFINE0(sched_yield)
>> {
>> + if (IS_ENABLED(CONFIG_RSEQ) && current->sched_time_delay) {
>> + schedule();
>> + return 0;
>> + }
>> +
>> do_sched_yield();
>> return 0;
>> }
>
> As mentioned in previous versions, does this not change the semantics for
> sched_yield()? Why is this necessary to immediately call schedule() and skip
> going through do_sched_yield()?
Expectation is that the user thread/application yield the cpu once it is done executing
any critical section in the extra time granted. Question was which system
call should it call, and yield seems appropriate. It could call any system call actually.
Since thread is just yielding the cpu it should retain its position in the queue. So it does
not have to go thru do_sched_yield() as that would put the task at and of the queue.
In this context, I suppose it does change the semantics.
Hoping Steven or Peter will comment on it.
>
> For a task if a delay is granted on CPU A, but the task migrates to CPU B before
> the IRQ-return hook, the timer never fires and the thread might overrun its bonus?
> Any thoughts on this?
If a task gets migrated, it will be put on the run queue of CPU B, then it is like the task
got rescheduled. When CPU B picks up the task it will get a new time slice? So
not sure how can it overrun the extra cpu time granted.
Thanks for you comments.
-Prakash
>
> Thanks,
> Madadi Vineeth Reddy
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 1/6] Sched: Scheduler time slice extension
2025-05-14 23:12 ` Prakash Sangappa
@ 2025-05-15 9:01 ` Steven Rostedt
2025-05-20 16:52 ` Prakash Sangappa
0 siblings, 1 reply; 20+ messages in thread
From: Steven Rostedt @ 2025-05-15 9:01 UTC (permalink / raw)
To: Prakash Sangappa
Cc: Madadi Vineeth Reddy, peterz, mathieu.desnoyers, tglx, bigeasy,
kprateek.nayak, linux-kernel
On Wed, 14 May 2025 23:12:26 +0000
Prakash Sangappa <prakash.sangappa@oracle.com> wrote:
> > As mentioned in previous versions, does this not change the semantics for
> > sched_yield()? Why is this necessary to immediately call schedule() and skip
> > going through do_sched_yield()?
>
> Expectation is that the user thread/application yield the cpu once it is done executing
> any critical section in the extra time granted. Question was which system
> call should it call, and yield seems appropriate. It could call any system call actually.
>
> Since thread is just yielding the cpu it should retain its position in the queue. So it does
> not have to go thru do_sched_yield() as that would put the task at and of the queue.
If it was granted an extension, from the POV of user space, it actually
shouldn't keep it's place in the queue, because it's place is currently
"promoted" and according to the scheduler, it shouldn't be running in
the first place. But in the kernel, we are just dealing with
implementation details. Going back to user space should cause it to be
scheduled out otherwise it shouldn't be extended in the first place.
-- Steve
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 1/6] Sched: Scheduler time slice extension
2025-05-15 9:01 ` Steven Rostedt
@ 2025-05-20 16:52 ` Prakash Sangappa
2025-05-20 20:20 ` Steven Rostedt
0 siblings, 1 reply; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-20 16:52 UTC (permalink / raw)
To: Steven Rostedt
Cc: Madadi Vineeth Reddy, peterz, mathieu.desnoyers, tglx, bigeasy,
kprateek.nayak, linux-kernel
> On May 15, 2025, at 2:01 AM, Steven Rostedt <rostedt@goodmis.org> wrote:
>
> On Wed, 14 May 2025 23:12:26 +0000
> Prakash Sangappa <prakash.sangappa@oracle.com> wrote:
>
>>> As mentioned in previous versions, does this not change the semantics for
>>> sched_yield()? Why is this necessary to immediately call schedule() and skip
>>> going through do_sched_yield()?
>>
>> Expectation is that the user thread/application yield the cpu once it is done executing
>> any critical section in the extra time granted. Question was which system
>> call should it call, and yield seems appropriate. It could call any system call actually.
>>
>> Since thread is just yielding the cpu it should retain its position in the queue. So it does
>> not have to go thru do_sched_yield() as that would put the task at and of the queue.
>
> If it was granted an extension, from the POV of user space, it actually
> shouldn't keep it's place in the queue, because it's place is currently
> "promoted" and according to the scheduler, it shouldn't be running in
> the first place. But in the kernel, we are just dealing with
> implementation details. Going back to user space should cause it to be
> scheduled out otherwise it shouldn't be extended in the first place.
But the thread has to make the sched_yied() call. The behavior of which
will be different if called in the extended time vs not. Assume this is ok.
-Prakash
>
> -- Steve
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 1/6] Sched: Scheduler time slice extension
2025-05-20 16:52 ` Prakash Sangappa
@ 2025-05-20 20:20 ` Steven Rostedt
0 siblings, 0 replies; 20+ messages in thread
From: Steven Rostedt @ 2025-05-20 20:20 UTC (permalink / raw)
To: Prakash Sangappa
Cc: Madadi Vineeth Reddy, peterz, mathieu.desnoyers, tglx, bigeasy,
kprateek.nayak, linux-kernel
On Tue, 20 May 2025 16:52:20 +0000
Prakash Sangappa <prakash.sangappa@oracle.com> wrote:
> But the thread has to make the sched_yied() call. The behavior of which
> will be different if called in the extended time vs not. Assume this is ok.
I assume it is ;-)
That's because the only time user space should ever call sched_yield() in
an extended time slice is because it wants to tell the kernel it doesn't
need it anymore. If that's not the case, that means one it's using the
extended time slice and calling sched_yield() for some other reason, which
doesn't make any sense.
-- Steve
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 0/6] Scheduler time slice extension
2025-05-13 21:45 [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
` (5 preceding siblings ...)
2025-05-13 21:45 ` [PATCH V4 6/6] Add API to query supported rseq cs flags Prakash Sangappa
@ 2025-05-20 21:01 ` Prakash Sangappa
6 siblings, 0 replies; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-20 21:01 UTC (permalink / raw)
To: Prakash Sangappa
Cc: linux-kernel, peterz, rostedt, mathieu.desnoyers, tglx, bigeasy,
kprateek.nayak
> On May 13, 2025, at 2:45 PM, Prakash Sangappa <prakash.sangappa@oracle.com> wrote:
>
> A user thread can get preempted in the middle of executing a critical
> section in user space while holding locks, which can have undesirable affect
> on performance. Having a way for the thread to request additional execution
> time on cpu, so that it can complete the critical section will be useful in
> such scenario. The request can be made by setting a bit in mapped memory,
> such that the kernel can also access to check and grant extra execution time
> on the cpu.
>
> There have been couple of proposals[1][2] for such a feature, which attempt
> to address the above scenario by granting one extra tick of execution time.
> In patch thread [1] posted by Steven Rostedt, there is ample discussion about
> need for this feature.
>
> However, the concern has been that this can lead to abuse. One extra tick can
> be a long time(about a millisec or more). Peter Zijlstra in response posted a
> prototype solution[5], which grants 50us execution time extension only.
> This is achieved with the help of a timer started on that cpu at the time of
> granting extra execution time. When the timer fires the thread will be
> preempted, if still running.
>
> This patchset implements above solution as suggested, with use of restartable
> sequences(rseq) structure for API. Refer [3][4] for further discussions.
>
> v1:
> https://lore.kernel.org/all/20250215005414.224409-1-prakash.sangappa@oracle.com/
>
> v2:
> https://lore.kernel.org/all/20250418193410.2010058-1-prakash.sangappa@oracle.com/
> - Based on discussions in [3], expecting user application to call sched_yield()
> to yield the cpu at the end of the critical section may not be advisable as
> pointed out by Linus.
>
> So added a check in return path from a system call to reschedule if time
> slice extension was granted to the thread. The check could as well be in
> syscall enter path from user mode.
> This would allow application thread to call any system call to yield the cpu.
> Which system call should be suggested? getppid(2) works.
>
> Do we still need the change in sched_yield() to reschedule when the thread
> has current->rseq_sched_delay set?
>
> - Added patch to introduce a sysctl tunable parameter to specify duration of
> the time slice extension in micro seconds(us), called 'sched_preempt_delay_us'.
> Can take a value in the range 0 to 100. Default is set to 50us.
> Setting this tunable to 0 disables the scheduler time slice extension feature.
>
> v3:
> https://lore.kernel.org/all/20250502015955.3146733-1-prakash.sangappa@oracle.com
> - Addressing review comments by Sebastian and Prateek.
> * Rename rseq_sched_delay -> sched_time_delay. Move its place in
> struct task_struct near other bits so it fits in existing word.
> * Use IS_ENABLED(CONFIG_RSEQ) instead of #ifdef to access
> 'sched_time_delay'.
> * removed rseq_delay_resched_tick() call from hrtick_clear().
> * Introduced a patch to add a tracepoint in exit_to_user_mode_loop(),
> suggested by Sebastian.
> * Added comments to describe RSEQ_CS_FLAG_DELAY_RESCHED flag.
>
> v4:
> - Changed default sched delay extension time to 30us
> - Added patch to indicate to userspace if the thread got preempted in
> the extended cpu time granted. Uses another bit in rseq cs flags for it.
> This should help the application to check and avoid having to call a
> system call to yield cpu, especially sched_yield() as pointed out
> by Steven Rostedt.
> - Moved tracepoint call towards end of exit_to_user_mode_loop().
> - Added a pr_warn() message when the 'sched_preempt_delay_us' tunable is
> set higher then the default value of 30us.
> - Patch to add an API to query if sched time extension feature is supported.
> A new flag to sys_rseq flags argument called 'RSEQ_FLAG_QUERY_CS_FLAGS',
> is added, as suggested by Mathieu Desnoyers.
> Returns bitmask of all the supported rseq cs flags, in rseq->flags field.
>
I had missed the references in the cover letter. Including here
[1] https://lore.kernel.org/lkml/20231025054219.1acaa3dd@gandalf.local.home/
[2] https://lore.kernel.org/lkml/1395767870-28053-1-git-send-email-khalid.aziz@oracle.com/
[3] https://lore.kernel.org/all/20250131225837.972218232@goodmis.org/
[4] https://lore.kernel.org/all/20241113000126.967713-1-prakash.sangappa@oracle.com/
[5] https://lore.kernel.org/lkml/20231030132949.GA38123@noisy.programming.kicks-ass.net/
[6] https://lore.kernel.org/all/1631147036-13597-1-git-send-email-prakash.sangappa@oracle.com/
> Prakash Sangappa (6):
> Sched: Scheduler time slice extension
> Sched: Indicate if thread got rescheduled
> Sched: Tunable to specify duration of time slice extension
> Sched: Add scheduler stat for cpu time slice extension
> Sched: Add tracepoint for sched time slice extension
> Add API to query supported rseq cs flags
>
> include/linux/entry-common.h | 11 ++--
> include/linux/sched.h | 23 +++++++++
> include/trace/events/sched.h | 28 +++++++++++
> include/uapi/linux/rseq.h | 19 +++++++
> kernel/entry/common.c | 27 ++++++++--
> kernel/rseq.c | 97 ++++++++++++++++++++++++++++++++++++
> kernel/sched/core.c | 50 +++++++++++++++++++
> kernel/sched/debug.c | 1 +
> kernel/sched/syscalls.c | 5 ++
> 9 files changed, 253 insertions(+), 8 deletions(-)
>
> --
> 2.43.5
>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 6/6] Add API to query supported rseq cs flags
2025-05-13 21:45 ` [PATCH V4 6/6] Add API to query supported rseq cs flags Prakash Sangappa
@ 2025-05-23 19:57 ` Mathieu Desnoyers
2025-05-23 20:03 ` Prakash Sangappa
0 siblings, 1 reply; 20+ messages in thread
From: Mathieu Desnoyers @ 2025-05-23 19:57 UTC (permalink / raw)
To: Prakash Sangappa, linux-kernel
Cc: peterz, rostedt, tglx, bigeasy, kprateek.nayak
On 2025-05-13 17:45, Prakash Sangappa wrote:
> For the API, add a new flag to sys_rseq 'flags' argument called
> RSEQ_FLAG_QUERY_CS_FLAGS.
>
> When this flag is passed it returns a bit mask of all the supported
> rseq cs flags in the user provided rseq struct's 'flags' member.
>
> Suggested-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
> ---
> include/uapi/linux/rseq.h | 1 +
> kernel/rseq.c | 17 +++++++++++++++++
> 2 files changed, 18 insertions(+)
>
> diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h
> index 015534f064af..44baea9dd10a 100644
> --- a/include/uapi/linux/rseq.h
> +++ b/include/uapi/linux/rseq.h
> @@ -20,6 +20,7 @@ enum rseq_cpu_id_state {
>
> enum rseq_flags {
> RSEQ_FLAG_UNREGISTER = (1 << 0),
> + RSEQ_FLAG_QUERY_CS_FLAGS = (1 << 1),
> };
>
> enum rseq_cs_flags_bit {
> diff --git a/kernel/rseq.c b/kernel/rseq.c
> index c4bc52f8ba9c..997f7ca722ca 100644
> --- a/kernel/rseq.c
> +++ b/kernel/rseq.c
> @@ -576,6 +576,23 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
> return 0;
> }
>
> + /*
> + * return supported rseq_cs flags
> + * It is an or of all the rseq_cs_flags;
> + */
> + if (flags & RSEQ_FLAG_QUERY_CS_FLAGS) {
> + u32 rseq_csflags = RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT |
> + RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL |
> + RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE |
Those 3 flags (above) are already or'd by RSEQ_CS_NO_RESTART_FLAGS,
and they are all deprecated. See rseq_warn_flags().
So I would not return them within the set of supported
rseq flags.
Thanks,
Mathieu
> + RSEQ_CS_FLAG_DELAY_RESCHED |
> + RSEQ_CS_FLAG_RESCHEDULED;
> + if (!rseq)
> + return -EINVAL;
> + if (copy_to_user(&rseq->flags, &rseq_csflags, sizeof(u32)))
> + return -EFAULT;
> + return 0;
> + }
> +
> if (unlikely(flags))
> return -EINVAL;
>
--
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 6/6] Add API to query supported rseq cs flags
2025-05-23 19:57 ` Mathieu Desnoyers
@ 2025-05-23 20:03 ` Prakash Sangappa
0 siblings, 0 replies; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-23 20:03 UTC (permalink / raw)
To: Mathieu Desnoyers
Cc: linux-kernel, peterz, rostedt, tglx, bigeasy, kprateek.nayak
> On May 23, 2025, at 12:57 PM, Mathieu Desnoyers <mathieu.desnoyers@efficios.com> wrote:
>
> On 2025-05-13 17:45, Prakash Sangappa wrote:
>> For the API, add a new flag to sys_rseq 'flags' argument called
>> RSEQ_FLAG_QUERY_CS_FLAGS.
>> When this flag is passed it returns a bit mask of all the supported
>> rseq cs flags in the user provided rseq struct's 'flags' member.
>> Suggested-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
>> Signed-off-by: Prakash Sangappa <prakash.sangappa@oracle.com>
>> ---
>> include/uapi/linux/rseq.h | 1 +
>> kernel/rseq.c | 17 +++++++++++++++++
>> 2 files changed, 18 insertions(+)
>> diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h
>> index 015534f064af..44baea9dd10a 100644
>> --- a/include/uapi/linux/rseq.h
>> +++ b/include/uapi/linux/rseq.h
>> @@ -20,6 +20,7 @@ enum rseq_cpu_id_state {
>> enum rseq_flags {
>> RSEQ_FLAG_UNREGISTER = (1 << 0),
>> + RSEQ_FLAG_QUERY_CS_FLAGS = (1 << 1),
>> };
>> enum rseq_cs_flags_bit {
>> diff --git a/kernel/rseq.c b/kernel/rseq.c
>> index c4bc52f8ba9c..997f7ca722ca 100644
>> --- a/kernel/rseq.c
>> +++ b/kernel/rseq.c
>> @@ -576,6 +576,23 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
>> return 0;
>> }
>> + /*
>> + * return supported rseq_cs flags
>> + * It is an or of all the rseq_cs_flags;
>> + */
>> + if (flags & RSEQ_FLAG_QUERY_CS_FLAGS) {
>> + u32 rseq_csflags = RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT |
>> + RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL |
>> + RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE |
>
> Those 3 flags (above) are already or'd by RSEQ_CS_NO_RESTART_FLAGS,
> and they are all deprecated. See rseq_warn_flags().
>
> So I would not return them within the set of supported
> rseq flags.
WIll remove those from the supported flags.
Thanks
-Prakash.
>
> Thanks,
>
> Mathieu
>
>
>
>> + RSEQ_CS_FLAG_DELAY_RESCHED |
>> + RSEQ_CS_FLAG_RESCHEDULED;
>> + if (!rseq)
>> + return -EINVAL;
>> + if (copy_to_user(&rseq->flags, &rseq_csflags, sizeof(u32)))
>> + return -EFAULT;
>> + return 0;
>> + }
>> +
>> if (unlikely(flags))
>> return -EINVAL;
>>
>
>
> --
> Mathieu Desnoyers
> EfficiOS Inc.
> https://www.efficios.com
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 1/6] Sched: Scheduler time slice extension
2025-05-13 21:45 ` [PATCH V4 1/6] Sched: " Prakash Sangappa
2025-05-14 10:58 ` Madadi Vineeth Reddy
@ 2025-05-23 20:06 ` Mathieu Desnoyers
2025-05-23 20:34 ` Prakash Sangappa
1 sibling, 1 reply; 20+ messages in thread
From: Mathieu Desnoyers @ 2025-05-23 20:06 UTC (permalink / raw)
To: Prakash Sangappa, linux-kernel
Cc: peterz, rostedt, tglx, bigeasy, kprateek.nayak
On 2025-05-13 17:45, Prakash Sangappa wrote:
[...]
> diff --git a/kernel/rseq.c b/kernel/rseq.c
> index b7a1ec327e81..dba44ca9f624 100644
> --- a/kernel/rseq.c
> +++ b/kernel/rseq.c
> @@ -448,6 +448,62 @@ void __rseq_handle_notify_resume(struct ksignal *ksig, struct pt_regs *regs)
> force_sigsegv(sig);
> }
>
> +bool rseq_delay_resched(void)
> +{
> + struct task_struct *t = current;
> + u32 flags;
> +
> + if (!IS_ENABLED(CONFIG_SCHED_HRTICK))
> + return false;
> +
> + if (!t->rseq)
> + return false;
> +
> + if (t->sched_time_delay)
> + return false;
> +
> + if (copy_from_user_nofault(&flags, &t->rseq->flags, sizeof(flags)))
> + return false;
This considers rseq->flags, but not rseq->rseq_cs->flags. Am I missing
something ?
Thanks,
Mathieu
> +
> + if (!(flags & RSEQ_CS_FLAG_DELAY_RESCHED))
> + return false;
> +
> + flags &= ~RSEQ_CS_FLAG_DELAY_RESCHED;
> + if (copy_to_user_nofault(&t->rseq->flags, &flags, sizeof(flags)))
> + return false;
> +
> + t->sched_time_delay = 1;
> +
> + return true;
> +}
> +
--
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH V4 1/6] Sched: Scheduler time slice extension
2025-05-23 20:06 ` Mathieu Desnoyers
@ 2025-05-23 20:34 ` Prakash Sangappa
0 siblings, 0 replies; 20+ messages in thread
From: Prakash Sangappa @ 2025-05-23 20:34 UTC (permalink / raw)
To: Mathieu Desnoyers
Cc: linux-kernel, peterz, rostedt, tglx, bigeasy, kprateek.nayak
> On May 23, 2025, at 1:06 PM, Mathieu Desnoyers <mathieu.desnoyers@efficios.com> wrote:
>
> On 2025-05-13 17:45, Prakash Sangappa wrote:
> [...]
>> diff --git a/kernel/rseq.c b/kernel/rseq.c
>> index b7a1ec327e81..dba44ca9f624 100644
>> --- a/kernel/rseq.c
>> +++ b/kernel/rseq.c
>> @@ -448,6 +448,62 @@ void __rseq_handle_notify_resume(struct ksignal *ksig, struct pt_regs *regs)
>> force_sigsegv(sig);
>> }
>> +bool rseq_delay_resched(void)
>> +{
>> + struct task_struct *t = current;
>> + u32 flags;
>> +
>> + if (!IS_ENABLED(CONFIG_SCHED_HRTICK))
>> + return false;
>> +
>> + if (!t->rseq)
>> + return false;
>> +
>> + if (t->sched_time_delay)
>> + return false;
>> +
>> + if (copy_from_user_nofault(&flags, &t->rseq->flags, sizeof(flags)))
>> + return false;
>
> This considers rseq->flags, but not rseq->rseq_cs->flags. Am I missing
> something ?
To use sched time delay feature, rseq->rseq_cs need not be set.
Mainly the rseq->flags member is where the flag(RSEQ_CS_FLAG_DELAY_RESCHED)
to request delaying preemption is set.
In that case should the flag be named ‘RSEQ_FLAG_DELAY_RESCHED’?
Although the enum is called or rseq_cs_flags. Description in structure rseq
will need to be updated.
-Prakash
>
> Thanks,
>
> Mathieu
>
>> +
>> + if (!(flags & RSEQ_CS_FLAG_DELAY_RESCHED))
>> + return false;
>> +
>> + flags &= ~RSEQ_CS_FLAG_DELAY_RESCHED;
>> + if (copy_to_user_nofault(&t->rseq->flags, &flags, sizeof(flags)))
>> + return false;
>> +
>> + t->sched_time_delay = 1;
>> +
>> + return true;
>> +}
>> +
>
>
> --
> Mathieu Desnoyers
> EfficiOS Inc.
> https://www.efficios.com
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2025-05-23 20:34 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-13 21:45 [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 1/6] Sched: " Prakash Sangappa
2025-05-14 10:58 ` Madadi Vineeth Reddy
2025-05-14 23:12 ` Prakash Sangappa
2025-05-15 9:01 ` Steven Rostedt
2025-05-20 16:52 ` Prakash Sangappa
2025-05-20 20:20 ` Steven Rostedt
2025-05-23 20:06 ` Mathieu Desnoyers
2025-05-23 20:34 ` Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 2/6] Sched: Indicate if thread got rescheduled Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 3/6] Sched: Tunable to specify duration of time slice extension Prakash Sangappa
2025-05-14 11:21 ` kernel test robot
2025-05-13 21:45 ` [PATCH V4 4/6] Sched: Add scheduler stat for cpu " Prakash Sangappa
2025-05-14 12:37 ` Madadi Vineeth Reddy
2025-05-14 23:01 ` Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 5/6] Sched: Add tracepoint for sched " Prakash Sangappa
2025-05-13 21:45 ` [PATCH V4 6/6] Add API to query supported rseq cs flags Prakash Sangappa
2025-05-23 19:57 ` Mathieu Desnoyers
2025-05-23 20:03 ` Prakash Sangappa
2025-05-20 21:01 ` [PATCH V4 0/6] Scheduler time slice extension Prakash Sangappa
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®