diff mbox series

[v6,10/16] sched/core: Add uclamp_util_with()

Message ID 20190115101513.2822-11-patrick.bellasi@arm.com (mailing list archive)
State Not Applicable, archived
Headers show
Series Add utilization clamping support | expand

Commit Message

Patrick Bellasi Jan. 15, 2019, 10:15 a.m. UTC
Currently uclamp_util() allows to clamp a specified utilization
considering the clamp values requested by RUNNABLE tasks in a CPU.
Sometimes however, it could be interesting to verify how clamp values
will change when a task is going to be running on a given CPU.
For example, the Energy Aware Scheduler (EAS) is interested in
evaluating and comparing the energy impact of different scheduling
decisions.

Add uclamp_util_with() which allows to clamp a given utilization by
considering the possible impact on CPU clamp values of a specified task.

Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
---
 kernel/sched/core.c  |  4 ++--
 kernel/sched/sched.h | 21 ++++++++++++++++++++-
 2 files changed, 22 insertions(+), 3 deletions(-)

Comments

Peter Zijlstra Jan. 23, 2019, 1:33 p.m. UTC | #1
On Tue, Jan 15, 2019 at 10:15:07AM +0000, Patrick Bellasi wrote:
> +static __always_inline
> +unsigned int uclamp_util_with(struct rq *rq, unsigned int util,
> +			      struct task_struct *p)
>  {
>  	unsigned int min_util = READ_ONCE(rq->uclamp[UCLAMP_MIN].value);
>  	unsigned int max_util = READ_ONCE(rq->uclamp[UCLAMP_MAX].value);
>  
> +	if (p) {
> +		min_util = max(min_util, uclamp_effective_value(p, UCLAMP_MIN));
> +		max_util = max(max_util, uclamp_effective_value(p, UCLAMP_MAX));
> +	}
> +

Like I think you mentioned earlier; this doesn't look right at all.

Should that not be something like:

	lo = READ_ONCE(rq->uclamp[UCLAMP_MIN].value);
	hi = READ_ONCE(rq->uclamp[UCLAMP_MAX].value);

	min_util = clamp(uclamp_effective(p, UCLAMP_MIN), lo, hi);
	max_util = clamp(uclamp_effective(p, UCLAMP_MAX), lo, hi);
Patrick Bellasi Jan. 23, 2019, 2:51 p.m. UTC | #2
On 23-Jan 14:33, Peter Zijlstra wrote:
> On Tue, Jan 15, 2019 at 10:15:07AM +0000, Patrick Bellasi wrote:
> > +static __always_inline
> > +unsigned int uclamp_util_with(struct rq *rq, unsigned int util,
> > +			      struct task_struct *p)
> >  {
> >  	unsigned int min_util = READ_ONCE(rq->uclamp[UCLAMP_MIN].value);
> >  	unsigned int max_util = READ_ONCE(rq->uclamp[UCLAMP_MAX].value);
> >  
> > +	if (p) {
> > +		min_util = max(min_util, uclamp_effective_value(p, UCLAMP_MIN));
> > +		max_util = max(max_util, uclamp_effective_value(p, UCLAMP_MAX));
> > +	}
> > +
> 
> Like I think you mentioned earlier; this doesn't look right at all.

What we wanna do here is to compute what _will_ be the clamp values of
a CPU if we enqueue *p on it.

The code above starts from the current CPU clamp value and mimics what
uclamp will do in case we move the task there... which is always a max
aggregation.

> Should that not be something like:
> 
> 	lo = READ_ONCE(rq->uclamp[UCLAMP_MIN].value);
> 	hi = READ_ONCE(rq->uclamp[UCLAMP_MAX].value);
> 
> 	min_util = clamp(uclamp_effective(p, UCLAMP_MIN), lo, hi);
> 	max_util = clamp(uclamp_effective(p, UCLAMP_MAX), lo, hi);

Here you end up with a restriction of the task clamp (effective)
clamps values considering the CPU clamps... which is different.

Why do you think we should do that?... perhaps I'm missing something.
Peter Zijlstra Jan. 23, 2019, 7:22 p.m. UTC | #3
On Wed, Jan 23, 2019 at 02:51:06PM +0000, Patrick Bellasi wrote:
> On 23-Jan 14:33, Peter Zijlstra wrote:
> > On Tue, Jan 15, 2019 at 10:15:07AM +0000, Patrick Bellasi wrote:
> > > +static __always_inline
> > > +unsigned int uclamp_util_with(struct rq *rq, unsigned int util,
> > > +			      struct task_struct *p)
> > >  {
> > >  	unsigned int min_util = READ_ONCE(rq->uclamp[UCLAMP_MIN].value);
> > >  	unsigned int max_util = READ_ONCE(rq->uclamp[UCLAMP_MAX].value);
> > >  
> > > +	if (p) {
> > > +		min_util = max(min_util, uclamp_effective_value(p, UCLAMP_MIN));
> > > +		max_util = max(max_util, uclamp_effective_value(p, UCLAMP_MAX));
> > > +	}
> > > +
> > 
> > Like I think you mentioned earlier; this doesn't look right at all.
> 
> What we wanna do here is to compute what _will_ be the clamp values of
> a CPU if we enqueue *p on it.
> 
> The code above starts from the current CPU clamp value and mimics what
> uclamp will do in case we move the task there... which is always a max
> aggregation.

Ah, then I misunderstood the purpose of this function.

> > Should that not be something like:
> > 
> > 	lo = READ_ONCE(rq->uclamp[UCLAMP_MIN].value);
> > 	hi = READ_ONCE(rq->uclamp[UCLAMP_MAX].value);
> > 
> > 	min_util = clamp(uclamp_effective(p, UCLAMP_MIN), lo, hi);
> > 	max_util = clamp(uclamp_effective(p, UCLAMP_MAX), lo, hi);
> 
> Here you end up with a restriction of the task clamp (effective)
> clamps values considering the CPU clamps... which is different.
> 
> Why do you think we should do that?... perhaps I'm missing something.

I was left with the impression from patch 7 that we don't compose clamps
right and throught that was what this code was supposed to do.

I'll have another look at this patch.
diff mbox series

Patch

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 1ed01f381641..b41db1190d28 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -904,8 +904,8 @@  static inline unsigned int uclamp_effective_bucket_id(struct task_struct *p,
 	return bucket_id;
 }
 
-static unsigned int uclamp_effective_value(struct task_struct *p,
-					   unsigned int clamp_id)
+unsigned int uclamp_effective_value(struct task_struct *p,
+				    unsigned int clamp_id)
 {
 	unsigned int clamp_value, bucket_id;
 
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 95d62a2a0b44..b7ce3023d023 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -2268,11 +2268,20 @@  static inline unsigned int uclamp_none(int clamp_id)
 }
 
 #ifdef CONFIG_UCLAMP_TASK
-static inline unsigned int uclamp_util(struct rq *rq, unsigned int util)
+unsigned int uclamp_effective_value(struct task_struct *p, unsigned int clamp_id);
+
+static __always_inline
+unsigned int uclamp_util_with(struct rq *rq, unsigned int util,
+			      struct task_struct *p)
 {
 	unsigned int min_util = READ_ONCE(rq->uclamp[UCLAMP_MIN].value);
 	unsigned int max_util = READ_ONCE(rq->uclamp[UCLAMP_MAX].value);
 
+	if (p) {
+		min_util = max(min_util, uclamp_effective_value(p, UCLAMP_MIN));
+		max_util = max(max_util, uclamp_effective_value(p, UCLAMP_MAX));
+	}
+
 	/*
 	 * Since CPU's {min,max}_util clamps are MAX aggregated considering
 	 * RUNNABLE tasks with _different_ clamps, we can end up with an
@@ -2283,7 +2292,17 @@  static inline unsigned int uclamp_util(struct rq *rq, unsigned int util)
 
 	return clamp(util, min_util, max_util);
 }
+
+static inline unsigned int uclamp_util(struct rq *rq, unsigned int util)
+{
+	return uclamp_util_with(rq, util, NULL);
+}
 #else /* CONFIG_UCLAMP_TASK */
+static inline unsigned int uclamp_util_with(struct rq *rq, unsigned int util,
+					    struct task_struct *p)
+{
+	return util;
+}
 static inline unsigned int uclamp_util(struct rq *rq, unsigned int util)
 {
 	return util;