调度器14—CPU拓扑结构和调度域建立-2-相关调试

一、拓扑相关调试

基于msm-5.4

1. sched_debug 开关

前提需要使能 CONFIG_SCHED_DEBUG,此时会导出一个 /sys/kernel/debug/sched_debug 文件,它会控制全局变量 sched_debug_enabled 的值,后者在 kernel/sched/topology.c 中唯一使用。

定义端:

late_initcall //sched/debug.c
    sched_init_debug //sched/debug.c
        debugfs_create_bool("sched_debug", 0644, NULL, &sched_debug_enabled); //这个类似函数 /sys/kernel/debug/sched_debug

使用端:

static int __init sched_debug_setup(char *str) //topology.c
{
    sched_debug_enabled = true;

    return 0;
}
early_param("sched_debug", sched_debug_setup);

static inline bool sched_debug(void)
{
    return sched_debug_enabled;
}

sched_domain_debug(*sd, cpu) //topology.c
    if (!sched_debug_enabled)
        return;
    printk(KERN_DEBUG "CPU%d attaching sched-domain(s):\n", cpu);

pd_init(cpu) //topology.c
    if (sched_debug())
        pr_info("%s: no EM found for CPU%d\n", __func__, cpu);

perf_domain_debug //topology.c
    if(sched_debug())
        printk(KERN_DEBUG "root_domain %*pbl:", cpumask_pr_args(cpu_map));
        printk(KERN_CONT " pd%d:{ cpus=%*pbl nr_cstate=%d }", ...);

partition_sched_domains_locked //topology.c
    sched_energy_set(bool has_eas) //topology.c 使能或关闭EAS都有打印
        if (sched_debug())
            pr_info("%s: stopping EAS\n", __func__);
            static_branch_disable_cpuslocked(&sched_energy_present);
        if (sched_debug())
            pr_info("%s: starting EAS\n", __func__);
            static_branch_enable_cpuslocked(&sched_energy_present);

只要 echo 1 > /sys/kernel/debug/sched_debug 使能了 sched_debug_enabled,会有一个 debug 等级的打印, 默认是关闭的。如:

[43337.992111] (4)[28299:kworker/4:2] domain-0: span=0-3 level=MC
[43337.992116] (4)[28299:kworker/4:2]  groups: 0:{ span=0 cap=748 }, 1:{ span=1 cap=586 }, 2:{ span=2 cap=784 }, 3:{ span=3 cap=752 }
[43337.992132] (4)[28299:kworker/4:2]  domain-1: span=0-4 level=DIE
[43337.992137] (4)[28299:kworker/4:2]   groups: 0:{ span=0-3 cap=2870 }, 4:{ span=4 cap=1023 }
[43337.992147] (4)[28299:kworker/4:2]CPU1 attaching sched-domain(s):
[43337.992151] (4)[28299:kworker/4:2] domain-0: span=0-3 level=MC
[43337.992206] (4)[28299:kworker/4:2]  groups: 1:{ span=1 cap=586 }, 2:{ span=2 cap=784 }, 3:{ span=3 cap=752 }, 0:{ span=0 cap=748 }
[43337.992221] (4)[28299:kworker/4:2]  domain-1: span=0-4 level=DIE
[43337.992225] (4)[28299:kworker/4:2]   groups: 0:{ span=0-3 cap=2870 }, 4:{ span=4 cap=1023 }
[43337.992238] (4)[28299:kworker/4:2]CPU2 attaching sched-domain(s):
[43337.992243] (4)[28299:kworker/4:2] domain-0: span=0-3 level=MC
[43337.992250] (4)[28299:kworker/4:2]  groups: 2:{ span=2 cap=784 }, 3:{ span=3 cap=752 }, 0:{ span=0 cap=748 }, 1:{ span=1 cap=586 }
[43337.992267] (4)[28299:kworker/4:2]  domain-1: span=0-4 level=DIE
[43337.992272] (4)[28299:kworker/4:2]   groups: 0:{ span=0-3 cap=2870 }, 4:{ span=4 cap=1023 }
[43337.992282] (4)[28299:kworker/4:2]CPU3 attaching sched-domain(s):
[43337.992285] (4)[28299:kworker/4:2] domain-0: span=0-3 level=MC
[43337.992290] (4)[28299:kworker/4:2]  groups: 3:{ span=3 cap=752 }, 0:{ span=0 cap=748 }, 1:{ span=1 cap=586 }, 2:{ span=2 cap=784 }
[43337.992305] (4)[28299:kworker/4:2]  domain-1: span=0-4 level=DIE
[43337.992310] (4)[28299:kworker/4:2]   groups: 0:{ span=0-3 cap=2870 }, 4:{ span=4 cap=1023 }
[43337.992326] (4)[28299:kworker/4:2]CPU4 attaching sched-domain(s):
[43337.992329] (4)[28299:kworker/4:2] domain-0: span=0-4 level=DIE
[43337.992334] (4)[28299:kworker/4:2]  groups: 4:{ span=4 cap=1023 }, 0:{ span=0-3 cap=2870 }
[43337.992391] (4)[28299:kworker/4:2]root_domain 0-4: pd4:{ cpus=4-7 nr_cstate=1 } pd0:{ cpus=0-3 nr_cstate=1 }
[43337.992398] (4)[28299:kworker/4:2]sched_energy_set: starting EAS

 

2. /proc/sys/kernel/sched_domain

这是一个目录,用来导出 sd 的信息,目录结构如下:

8295:/proc/sys/kernel/sched_domain # ls
cpu0  cpu1  cpu2  cpu3  cpu4  cpu5  cpu6  cpu7
8295:/proc/sys/kernel/sched_domain # ls cpu0
domain0  domain1
8295:/proc/sys/kernel/sched_domain # ls cpu0/do
domain0/  domain1/
8295:/proc/sys/kernel/sched_domain # ls cpu0/domain0/
busy_factor  cache_nice_tries  flags  imbalance_pct  max_interval  max_newidle_lb_cost  min_interval  name

文件导出代码:

//kernel/sched/debug.c

static struct ctl_table sd_ctl_dir[] = {
    {
        .procname    = "sched_domain",
        .mode        = 0555,
    },
    {}
};

static struct ctl_table sd_ctl_root[] = {
    {
        .procname    = "kernel",
        .mode        = 0555,
        .child        = sd_ctl_dir,
    },
    {}
};

static void set_table_entry(struct ctl_table *entry,
        const char *procname, void *data, int maxlen,
        umode_t mode, proc_handler *proc_handler)
{
    entry->procname = procname;
    entry->data = data;
    entry->maxlen = maxlen;
    entry->mode = mode;
    entry->proc_handler = proc_handler;
}

static struct ctl_table *sd_alloc_ctl_domain_table(struct sched_domain *sd)
{
    struct ctl_table *table = kcalloc(9, sizeof(struct ctl_table), GFP_KERNEL);;

    if (table == NULL)
        return NULL;

    set_table_entry(&table[0], "min_interval",      &sd->min_interval,        sizeof(long), 0644, proc_doulongvec_minmax);
    set_table_entry(&table[1], "max_interval",      &sd->max_interval,        sizeof(long), 0644, proc_doulongvec_minmax);
    set_table_entry(&table[2], "busy_factor",      &sd->busy_factor,        sizeof(int),  0644, proc_dointvec_minmax);
    set_table_entry(&table[3], "imbalance_pct",      &sd->imbalance_pct,        sizeof(int),  0644, proc_dointvec_minmax);
    set_table_entry(&table[4], "cache_nice_tries",      &sd->cache_nice_tries,    sizeof(int),  0644, proc_dointvec_minmax);
    set_table_entry(&table[5], "flags",          &sd->flags,            sizeof(int),  0444, proc_dointvec_minmax); //是10进制打印的
    set_table_entry(&table[6], "max_newidle_lb_cost", &sd->max_newidle_lb_cost, sizeof(long), 0644, proc_doulongvec_minmax);
    set_table_entry(&table[7], "name",          sd->name,           CORENAME_MAX_SIZE, 0444, proc_dostring);
    /* &table[8] is terminator */

    return table;
}

static struct ctl_table *sd_alloc_ctl_cpu_table(int cpu)
{
    struct ctl_table *entry, *table;
    struct sched_domain *sd;
    int domain_num = 0, i;
    char buf[32];

    for_each_domain(cpu, sd)
        domain_num++;
    entry = table = kcalloc(domain_num + 1, sizeof(struct ctl_table), GFP_KERNEL);
    if (table == NULL)
        return NULL;

    i = 0;
    for_each_domain(cpu, sd) {
        snprintf(buf, 32, "domain%d", i);
        entry->procname = kstrdup(buf, GFP_KERNEL);
        entry->mode = 0555;
        entry->child = sd_alloc_ctl_domain_table(sd);
        entry++;
        i++;
    }
    return table;
}

static cpumask_var_t        sd_sysctl_cpus;
static struct ctl_table_header    *sd_sysctl_header;

void register_sched_domain_sysctl(void)
{
    static struct ctl_table *cpu_entries;

    cpu_entries = kcalloc(num_possible_cpus() + 1, sizeof(struct ctl_table), GFP_KERNEL);
    cpu_idx = kcalloc(nr_cpu_ids, sizeof(struct ctl_table*), GFP_KERNEL);
    struct ctl_table *e = cpu_entries;
    for_each_possible_cpu(i) {
        cpu_idx[i] = e;
        e++;
    }

    for_each_cpu(i, sd_sysctl_cpus) {
        struct ctl_table *e = cpu_idx[i];

        if (e->child)
            sd_free_ctl_entry(&e->child);

        if (!e->procname) {
            snprintf(buf, 32, "cpu%d", i);
            e->procname = kstrdup(buf, GFP_KERNEL);
        }
        e->mode = 0555;
        e->child = sd_alloc_ctl_cpu_table(i); //建立关联
    }

    /* 一次性在sysctl下注册一个目录 */
    sd_sysctl_header = register_sysctl_table(sd_ctl_root);
}

 

posted on 2026-03-11 14:10  Hello-World3  阅读(6)  评论(0)    收藏  举报

导航