include/uapi/linux/sched.h | 3 +++ kernel/sched/deadline.c | 19 ++++++++++++++++--- kernel/sched/sched.h | 2 +- kernel/sched/syscalls.c | 16 +++++++++++----- 4 files changed, 31 insertions(+), 9 deletions(-)
The SCHED_DEADLINE scheduler allows reading the statically configured
run-time, deadline, and period parameters through the sched_getattr()
system call. However, there is no immediate way to access, from user space,
the current parameters used within the scheduler: the instantaneous runtime
left in the current cycle, as well as the current absolute deadline.
The `flags' sched_getattr() parameter, so far mandated to contain zero,
now supports the SCHED_GETATTR_FLAG_DL_DYNAMIC=1 flag, to request
retrieval of the leftover runtime and absolute deadline, converted to a
CLOCK_MONOTONIC reference, instead of the statically configured parameters.
This feature is useful for adaptive SCHED_DEADLINE tasks that need to
modify their behavior depending on whether or not there is enough runtime
left in the current period, and/or what is the current absolute deadline.
Notes:
- before returning the instantaneous parameters, the runtime is updated;
- the abs deadline is returned shifted from rq_clock() to ktime_get_ns(),
in CLOCK_MONOTONIC reference; this causes multiple invocations from the
same period to return values that may differ for a few ns (showing some
small drift), albeit the deadline doesn't move, in rq_clock() reference;
- the abs deadline value returned to user-space, as unsigned 64-bit value,
can represent nearly 585 years since boot time;
- setting flags=0 provides the old behavior (retrieve static parameters).
See also the notes from discussion held at OSPM 2025 on the topic
"Making user space aware of current deadline-scheduler parameters".
Signed-off-by: Tommaso Cucinotta <tommaso.cucinotta@santannapisa.it>
---
include/uapi/linux/sched.h | 3 +++
kernel/sched/deadline.c | 19 ++++++++++++++++---
kernel/sched/sched.h | 2 +-
kernel/sched/syscalls.c | 16 +++++++++++-----
4 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/include/uapi/linux/sched.h b/include/uapi/linux/sched.h
index 359a14cc..52b69ce8 100644
--- a/include/uapi/linux/sched.h
+++ b/include/uapi/linux/sched.h
@@ -146,4 +146,7 @@ struct clone_args {
SCHED_FLAG_KEEP_ALL | \
SCHED_FLAG_UTIL_CLAMP)
+/* Only for sched_getattr() own flag param, if task is SCHED_DEADLINE */
+#define SCHED_GETATTR_FLAG_DL_DYNAMIC 0x01
+
#endif /* _UAPI_LINUX_SCHED_H */
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 5b64bc62..b1c7c988 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -3328,13 +3328,26 @@ void __setparam_dl(struct task_struct *p, const struct sched_attr *attr)
dl_se->dl_density = to_ratio(dl_se->dl_deadline, dl_se->dl_runtime);
}
-void __getparam_dl(struct task_struct *p, struct sched_attr *attr)
+void __getparam_dl(struct task_struct *p, struct sched_attr *attr, unsigned int flags)
{
struct sched_dl_entity *dl_se = &p->dl;
+ struct rq *rq = task_rq(p);
+ u64 adj_deadline;
attr->sched_priority = p->rt_priority;
- attr->sched_runtime = dl_se->dl_runtime;
- attr->sched_deadline = dl_se->dl_deadline;
+ if (flags & SCHED_GETATTR_FLAG_DL_DYNAMIC) {
+ guard(raw_spinlock_irq)(&rq->__lock);
+ update_rq_clock(rq);
+ if (task_current(rq, p))
+ update_curr_dl(rq);
+
+ attr->sched_runtime = dl_se->runtime;
+ adj_deadline = dl_se->deadline - rq_clock(rq) + ktime_get_ns();
+ attr->sched_deadline = adj_deadline;
+ } else {
+ attr->sched_runtime = dl_se->dl_runtime;
+ attr->sched_deadline = dl_se->dl_deadline;
+ }
attr->sched_period = dl_se->dl_period;
attr->sched_flags &= ~SCHED_DL_FLAGS;
attr->sched_flags |= dl_se->flags;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index b5367c51..42ddfccb 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -353,7 +353,7 @@ extern int sched_dl_global_validate(void);
extern void sched_dl_do_global(void);
extern int sched_dl_overflow(struct task_struct *p, int policy, const struct sched_attr *attr);
extern void __setparam_dl(struct task_struct *p, const struct sched_attr *attr);
-extern void __getparam_dl(struct task_struct *p, struct sched_attr *attr);
+extern void __getparam_dl(struct task_struct *p, struct sched_attr *attr, unsigned int flags);
extern bool __checkparam_dl(const struct sched_attr *attr);
extern bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr);
extern int dl_cpuset_cpumask_can_shrink(const struct cpumask *cur, const struct cpumask *trial);
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index 77ae87f3..d7eac588 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -928,10 +928,10 @@ static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *a
return -E2BIG;
}
-static void get_params(struct task_struct *p, struct sched_attr *attr)
+static void get_params(struct task_struct *p, struct sched_attr *attr, unsigned int flags)
{
if (task_has_dl_policy(p)) {
- __getparam_dl(p, attr);
+ __getparam_dl(p, attr, flags);
} else if (task_has_rt_policy(p)) {
attr->sched_priority = p->rt_priority;
} else {
@@ -997,7 +997,7 @@ SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,
return -ESRCH;
if (attr.sched_flags & SCHED_FLAG_KEEP_PARAMS)
- get_params(p, &attr);
+ get_params(p, &attr, 0);
return sched_setattr(p, &attr);
}
@@ -1082,7 +1082,7 @@ SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
int retval;
if (unlikely(!uattr || pid < 0 || usize > PAGE_SIZE ||
- usize < SCHED_ATTR_SIZE_VER0 || flags))
+ usize < SCHED_ATTR_SIZE_VER0))
return -EINVAL;
scoped_guard (rcu) {
@@ -1090,6 +1090,12 @@ SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
if (!p)
return -ESRCH;
+ if (flags) {
+ if (!task_has_dl_policy(p) ||
+ flags != SCHED_GETATTR_FLAG_DL_DYNAMIC)
+ return -EINVAL;
+ }
+
retval = security_task_getscheduler(p);
if (retval)
return retval;
@@ -1097,7 +1103,7 @@ SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
kattr.sched_policy = p->policy;
if (p->sched_reset_on_fork)
kattr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
- get_params(p, &kattr);
+ get_params(p, &kattr, flags);
kattr.sched_flags &= SCHED_FLAG_ALL;
#ifdef CONFIG_UCLAMP_TASK
--
2.45.2
Hi Tommaso, On Fri, 12 Sep 2025 07:38:29 +0200, Tommaso Cucinotta <tommaso.cucinotta@gmail.com> wrote: > The SCHED_DEADLINE scheduler allows reading the statically configured > run-time, deadline, and period parameters through the sched_getattr() > system call. However, there is no immediate way to access, from user space, > the current parameters used within the scheduler: the instantaneous runtime > left in the current cycle, as well as the current absolute deadline. > > The `flags' sched_getattr() parameter, so far mandated to contain zero, > now supports the SCHED_GETATTR_FLAG_DL_DYNAMIC=1 flag, to request > retrieval of the leftover runtime and absolute deadline, converted to a > CLOCK_MONOTONIC reference, instead of the statically configured parameters. > > This feature is useful for adaptive SCHED_DEADLINE tasks that need to > modify their behavior depending on whether or not there is enough runtime > left in the current period, and/or what is the current absolute deadline. > > Notes: > - before returning the instantaneous parameters, the runtime is updated; > - the abs deadline is returned shifted from rq_clock() to ktime_get_ns(), > in CLOCK_MONOTONIC reference; this causes multiple invocations from the > same period to return values that may differ for a few ns (showing some > small drift), albeit the deadline doesn't move, in rq_clock() reference; > - the abs deadline value returned to user-space, as unsigned 64-bit value, > can represent nearly 585 years since boot time; > - setting flags=0 provides the old behavior (retrieve static parameters). > > See also the notes from discussion held at OSPM 2025 on the topic > "Making user space aware of current deadline-scheduler parameters". > > Signed-off-by: Tommaso Cucinotta <tommaso.cucinotta@santannapisa.it> > ... I tested your patch and I can confirm I could retrieve the remaining runtime and absolute deadline values via sched_gettattr() as you mentioned in your cover letter. I'm involved in a project where the deadline scheduler is used in critical realtime applications, which are monitored in order to let the system react in case of misbehaviours, for instance if the applications overrun their WCET or miss their expected deadlines. On top of your reasons explained at OSPM 2025, I think this patch could be also useful in regards of monitoring as it would let userspace retrieve a more accurate runtime value compared to the typical estimation calculated via the clock_gettime(CLOCK_THREAD_CPUTIME_ID). To my understanding, the runtime_left retrieved with sched_gettattr() is also more representative of the actual task remaining budget when the runtime is scaled in dl_scaled_delta_exec() to calculate the time invariant task utilization [1] for energy-aware scheduling [2]. Moreover, this patch would allow the application to determine deadline misses. Tested-by: Matteo Martelli <matteo.martelli@codethink.co.uk> Best regards, Matteo Martelli [1]: https://www.kernel.org/doc/html/v6.17/scheduler/sched-capacity.html#frequency-invariance [2]: https://www.kernel.org/doc/html/v6.17/scheduler/sched-deadline.html#energy-aware-scheduling
© 2016 - 2026 Red Hat, Inc.