sched/fair: Add flag to indicate why we picked the CPU

Add a flag to the trace event that indicates why we picked a particular
CPU. This is very useful information/statistic that can be used to
analyse the effectiveness of the scheduler.

Change-Id: Ic9462fef751f9442ae504c09fbf4418e08f018b0
Signed-off-by: Olav Haugan <ohaugan@codeaurora.org>
This commit is contained in:
Olav Haugan 2016-08-15 15:52:50 -07:00 committed by Syed Rameez Mustafa
parent 67e0df6e33
commit fbc251af5a
2 changed files with 52 additions and 15 deletions

View file

@ -116,9 +116,9 @@ TRACE_EVENT(sched_enq_deq_task,
TRACE_EVENT(sched_task_load,
TP_PROTO(struct task_struct *p, bool boost, int reason,
bool sync, bool need_idle, bool fast_path, int best_cpu),
bool sync, bool need_idle, u32 flags, int best_cpu),
TP_ARGS(p, boost, reason, sync, need_idle, fast_path, best_cpu),
TP_ARGS(p, boost, reason, sync, need_idle, flags, best_cpu),
TP_STRUCT__entry(
__array( char, comm, TASK_COMM_LEN )
@ -128,7 +128,7 @@ TRACE_EVENT(sched_task_load,
__field( int, reason )
__field( bool, sync )
__field( bool, need_idle )
__field( bool, fast_path )
__field( u32, flags )
__field( int, best_cpu )
__field( u64, latency )
),
@ -141,17 +141,17 @@ TRACE_EVENT(sched_task_load,
__entry->reason = reason;
__entry->sync = sync;
__entry->need_idle = need_idle;
__entry->fast_path = fast_path;
__entry->flags = flags;
__entry->best_cpu = best_cpu;
__entry->latency = p->state == TASK_WAKING ?
sched_ktime_clock() -
p->ravg.mark_start : 0;
),
TP_printk("%d (%s): demand=%u boost=%d reason=%d sync=%d need_idle=%d fast_path=%d best_cpu=%d latency=%llu",
TP_printk("%d (%s): demand=%u boost=%d reason=%d sync=%d need_idle=%d flags=%x best_cpu=%d latency=%llu",
__entry->pid, __entry->comm, __entry->demand,
__entry->boost, __entry->reason, __entry->sync,
__entry->need_idle, __entry->fast_path,
__entry->need_idle, __entry->flags,
__entry->best_cpu, __entry->latency)
);

View file

@ -2579,6 +2579,23 @@ static u32 __compute_runnable_contrib(u64 n)
#ifdef CONFIG_SCHED_HMP
/* CPU selection flag */
#define SBC_FLAG_PREV_CPU 0x1
#define SBC_FLAG_BEST_CAP_CPU 0x2
#define SBC_FLAG_CPU_COST 0x4
#define SBC_FLAG_MIN_COST 0x8
#define SBC_FLAG_IDLE_LEAST_LOADED 0x10
#define SBC_FLAG_IDLE_CSTATE 0x20
#define SBC_FLAG_COST_CSTATE_TIE_BREAKER 0x40
#define SBC_FLAG_COST_CSTATE_PREV_CPU_TIE_BREAKER 0x80
#define SBC_FLAG_CSTATE_LOAD 0x100
#define SBC_FLAG_BEST_SIBLING 0x200
/* Cluster selection flag */
#define SBC_FLAG_COLOC_CLUSTER 0x10000
#define SBC_FLAG_WAKER_CLUSTER 0x20000
#define SBC_FLAG_BACKUP_CLUSTER 0x40000
struct cpu_select_env {
struct task_struct *p;
struct related_thread_group *rtg;
@ -2593,6 +2610,8 @@ struct cpu_select_env {
DECLARE_BITMAP(backup_list, NR_CPUS);
u64 task_load;
u64 cpu_load;
u32 sbc_best_flag;
u32 sbc_best_cluster_flag;
};
struct cluster_cpu_stats {
@ -2687,6 +2706,7 @@ select_least_power_cluster(struct cpu_select_env *env)
if (env->rtg) {
env->task_load = scale_load_to_cpu(task_load(env->p),
cluster_first_cpu(env->rtg->preferred_cluster));
env->sbc_best_cluster_flag |= SBC_FLAG_COLOC_CLUSTER;
return env->rtg->preferred_cluster;
}
@ -2765,6 +2785,7 @@ struct cpu_select_env *env, struct cluster_cpu_stats *stats)
update_spare_capacity(stats, env, i, next->capacity,
cpu_load_sync(i, env->sync));
}
env->sbc_best_cluster_flag = SBC_FLAG_BACKUP_CLUSTER;
}
}
@ -2836,6 +2857,7 @@ static void __update_cluster_stats(int cpu, struct cluster_cpu_stats *stats,
stats->best_cpu_cstate = cpu_cstate;
stats->best_load = env->cpu_load;
stats->best_cpu = cpu;
env->sbc_best_flag = SBC_FLAG_CPU_COST;
return;
}
@ -2848,12 +2870,14 @@ static void __update_cluster_stats(int cpu, struct cluster_cpu_stats *stats,
stats->best_cpu_cstate = cpu_cstate;
stats->best_load = env->cpu_load;
stats->best_cpu = cpu;
env->sbc_best_flag = SBC_FLAG_COST_CSTATE_TIE_BREAKER;
return;
}
/* C-state is the same. Use prev CPU to break the tie */
if (cpu == prev_cpu) {
stats->best_cpu = cpu;
env->sbc_best_flag = SBC_FLAG_COST_CSTATE_PREV_CPU_TIE_BREAKER;
return;
}
@ -2862,6 +2886,7 @@ static void __update_cluster_stats(int cpu, struct cluster_cpu_stats *stats,
(cpu_cstate > 0 && env->cpu_load > stats->best_load))) {
stats->best_load = env->cpu_load;
stats->best_cpu = cpu;
env->sbc_best_flag = SBC_FLAG_CSTATE_LOAD;
}
}
#else /* CONFIG_SCHED_HMP_CSTATE_AWARE */
@ -2892,6 +2917,7 @@ static void __update_cluster_stats(int cpu, struct cluster_cpu_stats *stats,
stats->min_cost = cpu_cost;
stats->min_load = env->cpu_load;
stats->best_cpu = cpu;
env->sbc_best_flag = SBC_FLAG_MIN_COST;
}
}
}
@ -3049,8 +3075,8 @@ static int select_best_cpu(struct task_struct *p, int target, int reason,
{
struct sched_cluster *cluster, *pref_cluster = NULL;
struct cluster_cpu_stats stats;
bool fast_path = false;
struct related_thread_group *grp;
unsigned int sbc_flag = 0;
struct cpu_select_env env = {
.p = p,
@ -3062,6 +3088,8 @@ static int select_best_cpu(struct task_struct *p, int target, int reason,
.prev_cpu = target,
.ignore_prev_cpu = 0,
.rtg = NULL,
.sbc_best_flag = 0,
.sbc_best_cluster_flag = 0,
};
bitmap_copy(env.candidate_list, all_cluster_ids, NR_CPUS);
@ -3086,8 +3114,10 @@ static int select_best_cpu(struct task_struct *p, int target, int reason,
env.need_waker_cluster = 1;
bitmap_zero(env.candidate_list, NR_CPUS);
__set_bit(cluster->id, env.candidate_list);
env.sbc_best_cluster_flag = SBC_FLAG_WAKER_CLUSTER;
} else if (bias_to_prev_cpu(&env, &stats)) {
fast_path = true;
sbc_flag = SBC_FLAG_PREV_CPU;
goto out;
}
}
@ -3111,15 +3141,20 @@ retry:
} while ((cluster = next_best_cluster(cluster, &env, &stats)));
if (env.need_idle) {
if (stats.best_idle_cpu >= 0)
if (stats.best_idle_cpu >= 0) {
target = stats.best_idle_cpu;
else if (stats.least_loaded_cpu >= 0)
sbc_flag |= SBC_FLAG_IDLE_CSTATE;
} else if (stats.least_loaded_cpu >= 0) {
target = stats.least_loaded_cpu;
sbc_flag |= SBC_FLAG_IDLE_LEAST_LOADED;
}
} else if (stats.best_cpu >= 0) {
if (stats.best_cpu != task_cpu(p) &&
stats.min_cost == stats.best_sibling_cpu_cost)
stats.min_cost == stats.best_sibling_cpu_cost) {
stats.best_cpu = stats.best_sibling_cpu;
sbc_flag |= SBC_FLAG_BEST_SIBLING;
}
sbc_flag |= env.sbc_best_flag;
target = stats.best_cpu;
} else {
if (env.rtg) {
@ -3128,15 +3163,17 @@ retry:
}
find_backup_cluster(&env, &stats);
if (stats.best_capacity_cpu >= 0)
if (stats.best_capacity_cpu >= 0) {
target = stats.best_capacity_cpu;
sbc_flag |= SBC_FLAG_BEST_CAP_CPU;
}
}
p->last_cpu_selected_ts = sched_ktime_clock();
sbc_flag |= env.sbc_best_cluster_flag;
out:
rcu_read_unlock();
trace_sched_task_load(p, sched_boost(), env.reason, env.sync,
env.need_idle, fast_path, target);
env.need_idle, sbc_flag, target);
return target;
}