blob: 9dc83f398bd3e19d9f92a12d084100d5b5efda19 [file]
/* Tracking cpu nohz residency */
#include "linsched.h"
#include <stdio.h>
#define MAX_DOMAINS 10
struct nohz_data {
u64 nohz_time;
u64 last_change;
int num_nohz_cpus;
};
/*
* nohz_data[cpu][0] is the data for the individual cpu, and then it
* goes up the sched_domain tree for 1..
*/
static struct nohz_data nohz_data[NR_CPUS][MAX_DOMAINS];
struct nohz;
extern struct nohz nohz;
static void do_track_nohz_sd_residency(int cpu, int level, int nr_cpus,
int cpu_delta)
{
struct nohz_data *data = &nohz_data[cpu][level];
BUG_ON(level >= MAX_DOMAINS);
if (data->num_nohz_cpus == nr_cpus) {
data->nohz_time += current_time - data->last_change;
}
data->last_change = current_time;
data->num_nohz_cpus += cpu_delta;
}
void track_nohz_residency(int cpu)
{
struct sched_domain *sd;
int cpu_delta;
int nohz_active = !cpu_online(cpu) ||
!!cpumask_test_cpu(cpu, nohz.idle_cpus_mask);
int i = 1;
cpu_delta = nohz_active - nohz_data[cpu][0].num_nohz_cpus;
do_track_nohz_sd_residency(cpu, 0, 1, cpu_delta);
for_each_domain(cpu, sd) {
do_track_nohz_sd_residency(cpumask_first(sched_domain_span(sd)),
i, sd->span_weight, cpu_delta);
i++;
}
}
static void print_cpu(int cpu)
{
int i;
struct sched_domain *sd;
track_nohz_residency(cpu);
printf("cpu%3d: %7.4f%% ", cpu, nohz_data[cpu][0].nohz_time * 100.0 / current_time);
i = 1;
for_each_domain(cpu, sd) {
if (cpu != cpumask_first(sched_domain_span(sd)))
break;
printf("%7.4f%% ",
nohz_data[cpu][i].nohz_time * 100.0 / current_time);
i++;
}
printf("\n");
}
void print_nohz_residency(void)
{
struct cpumask to_print;
struct sched_domain *sd;
int cpu;
printf("Time spent with tick disabled over %llu ms:\n",
current_time / NSEC_PER_MSEC);
cpumask_copy(&to_print, cpu_possible_mask);
cpu = cpumask_first(&to_print);
/* headings */
printf("%7s ", "level:");
for_each_domain(cpu, sd) {
printf("%8s ", sd->name);
}
printf("%8s ", "SYSTEM");
printf("\n");
/* print the nohz info in sched_domain hierarchy order */
while(cpu < nr_cpu_ids) {
print_cpu(cpu);
cpumask_clear_cpu(cpu, &to_print);
if (nr_cpu_ids == 1)
break;
sd = cpu_rq(cpu)->sd;
while(sd) {
cpu = cpumask_first_and(sched_domain_span(sd),
&to_print);
if (cpu < nr_cpu_ids)
break;
sd = sd->parent;
}
}
if (!cpumask_empty(&to_print)) {
printf("currently offline cpus:\n");
while(!cpumask_empty(&to_print)) {
cpu = cpumask_first(&to_print);
print_cpu(cpu);
cpumask_clear_cpu(cpu, &to_print);
}
}
}