rq->uclamp.value[clamp_id] = max_value;
}
+static inline int uclamp_task_group_id(struct task_struct *p, int clamp_id)
+{
+ struct uclamp_se *uc_se;
+ int clamp_value;
+ int group_id;
+
+ /* Taks currently accounted into a clamp group */
+ if (uclamp_task_affects(p, clamp_id))
+ return p->uclamp_group_id[clamp_id];
+
+ /* Task specific clamp value */
+ uc_se = &p->uclamp[clamp_id];
+ clamp_value = uc_se->value;
+ group_id = uc_se->group_id;
+
+#ifdef CONFIG_UCLAMP_TASK_GROUP
+ /* Use TG's clamp value to limit task specific values */
+ uc_se = &task_group(p)->uclamp[clamp_id];
+ if (group_id == UCLAMP_NOT_VALID ||
+ clamp_value > uc_se->effective.value) {
+ group_id = uc_se->effective.group_id;
+ }
+#endif
+
+ return group_id;
+}
+
+static inline int uclamp_group_value(int clamp_id, int group_id)
+{
+ struct uclamp_map *uc_map = &uclamp_maps[clamp_id][0];
+
+ if (group_id == UCLAMP_NOT_VALID)
+ return uclamp_none(clamp_id);
+
+ return uc_map[group_id].value;
+}
+
+static inline int uclamp_task_value(struct task_struct *p, int clamp_id)
+{
+ int group_id = uclamp_task_group_id(p, clamp_id);
+
+ return uclamp_group_value(clamp_id, group_id);
+}
+
/**
* uclamp_cpu_get_id(): increase reference count for a clamp group on a CPU
* @p: the task being enqueued on a CPU
* @rq: the CPU's rq where the clamp group has to be reference counted
* @clamp_id: the utilization clamp (e.g. min or max utilization) to reference
*
- * Once a task is enqueued on a CPU's RQ, the clamp group currently defined by
- * the task's uclamp.group_id is reference counted on that CPU.
+ * Once a task is enqueued on a CPU's RQ, the most restrictive clamp group,
+ * among the task specific and that of the task's cgroup one, is reference
+ * counted on that CPU.
+ *
+ * Since the CPUs reference counted clamp group can be either that of the task
+ * or of its cgroup, we keep track of the reference counted clamp group by
+ * storing its index (group_id) into the task's task_struct::uclamp_group_id.
+ * This group index will then be used at task's dequeue time to release the
+ * correct refcount.
*/
static inline void uclamp_cpu_get_id(struct task_struct *p,
struct rq *rq, int clamp_id)
int group_id;
/* No task specific clamp values: nothing to do */
- group_id = p->uclamp[clamp_id].group_id;
+ group_id = uclamp_task_group_id(p, clamp_id);
if (group_id == UCLAMP_NOT_VALID)
return;
+ clamp_value = uclamp_group_value(clamp_id, group_id);
/* Reference count the task into its current group_id */
uc_grp = &rq->uclamp.group[clamp_id][0];
uc_grp[group_id].tasks += 1;
+ /* Track the effective clamp group */
+ p->uclamp_group_id[clamp_id] = group_id;
+
/* Force clamp update on idle exit */
uc_cpu = &rq->uclamp;
- clamp_value = p->uclamp[clamp_id].value;
if (unlikely(uc_cpu->flags & UCLAMP_FLAG_IDLE)) {
/*
* This function is called for both UCLAMP_MIN (before) and
int group_id;
/* No task specific clamp values: nothing to do */
- group_id = p->uclamp[clamp_id].group_id;
+ group_id = p->uclamp_group_id[clamp_id];
if (group_id == UCLAMP_NOT_VALID)
return;
#endif
uc_grp[group_id].tasks -= 1;
+ /* Flag the task as not affecting any clamp index */
+ p->uclamp_group_id[clamp_id] = UCLAMP_NOT_VALID;
+
/* If this is not the last task, no updates are required */
if (uc_grp[group_id].tasks > 0)
return;
#endif
#ifdef CONFIG_UCLAMP_TASK
+ memset(&p->uclamp_group_id, UCLAMP_NOT_VALID,
+ sizeof(p->uclamp_group_id));
p->uclamp[UCLAMP_MIN].value = 0;
p->uclamp[UCLAMP_MIN].group_id = UCLAMP_NOT_VALID;
p->uclamp[UCLAMP_MAX].value = SCHED_CAPACITY_SCALE;
attr.sched_nice = task_nice(p);
#ifdef CONFIG_UCLAMP_TASK
- attr.sched_util_min = p->uclamp[UCLAMP_MIN].value;
- attr.sched_util_max = p->uclamp[UCLAMP_MAX].value;
+ attr.sched_util_min = uclamp_task_value(p, UCLAMP_MIN);
+ attr.sched_util_max = uclamp_task_value(p, UCLAMP_MAX);
#endif
rcu_read_unlock();
* groups we consider their current value.
*/
uc_se = &css_tg(css)->uclamp[clamp_id];
- if (css != top_css)
+ if (css != top_css) {
value = uc_se->value;
+ group_id = uc_se->effective.group_id;
+ }
+
/*
* Skip the whole subtrees if the current effective clamp is
* alredy matching the TG's clamp value.