// SPDX-License-Identifier: GPL-2.0-only/* * kernel/sched/debug.c * * Print the CFS rbtree and other debugging details * * Copyright(C) 2007, Red Hat, Inc., Ingo Molnar */#include "sched.h" /* * This allows printing both to /proc/sched_debug and * to the console */#define SEQ_printf(m, x...) \ do { \ if (m) \ seq_printf(m, x); \ else \ pr_cont(x); \ } while (0) /* * Ease the printing of nsec fields: */static long long nsec_high(unsigned long long nsec){ if ((long long)nsec < 0) { nsec = -nsec; do_div(nsec, 1000000); return -nsec; } do_div(nsec, 1000000); return nsec;} static unsigned long nsec_low(unsigned long long nsec){ if ((long long)nsec < 0) nsec = -nsec; return do_div(nsec, 1000000);} #define SPLIT_NS(x) nsec_high(x), nsec_low(x) #define SCHED_FEAT(name, enabled) \ #name , static const char * const sched_feat_names[] = {#include "features.h"}; #undef SCHED_FEAT static int sched_feat_show(struct seq_file *m, void *v){ int i; for (i = 0; i < __SCHED_FEAT_NR; i++) { if (!(sysctl_sched_features & (1UL << i))) seq_puts(m, "NO_"); seq_printf(m, "%s ", sched_feat_names[i]); } seq_puts(m, "\n"); return 0;} #ifdef CONFIG_JUMP_LABEL #define jump_label_key__true STATIC_KEY_INIT_TRUE#define jump_label_key__false STATIC_KEY_INIT_FALSE #define SCHED_FEAT(name, enabled) \ jump_label_key__##enabled , struct static_key sched_feat_keys[__SCHED_FEAT_NR] = {#include "features.h"}; #undef SCHED_FEAT static void sched_feat_disable(int i){ static_key_disable_cpuslocked(&sched_feat_keys[i]);} static void sched_feat_enable(int i){ static_key_enable_cpuslocked(&sched_feat_keys[i]);}#elsestatic void sched_feat_disable(int i) { };static void sched_feat_enable(int i) { };#endif /* CONFIG_JUMP_LABEL */ static int sched_feat_set(char *cmp){ int i; int neg = 0; if (strncmp(cmp, "NO_", 3) == 0) { neg = 1; cmp += 3; } i = match_string(sched_feat_names, __SCHED_FEAT_NR, cmp); if (i < 0) return i; if (neg) { sysctl_sched_features &= ~(1UL << i); sched_feat_disable(i); } else { sysctl_sched_features |= (1UL << i); sched_feat_enable(i); } return 0;} static ssize_tsched_feat_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos){ char buf[64]; char *cmp; int ret; struct inode *inode; if (cnt > 63) cnt = 63; if (copy_from_user(&buf, ubuf, cnt)) return -EFAULT; buf[cnt] = 0; cmp = strstrip(buf); /* Ensure the static_key remains in a consistent state */ inode = file_inode(filp); cpus_read_lock(); inode_lock(inode); ret = sched_feat_set(cmp); inode_unlock(inode); cpus_read_unlock(); if (ret < 0) return ret; *ppos += cnt; return cnt;} static int sched_feat_open(struct inode *inode, struct file *filp){ return single_open(filp, sched_feat_show, NULL);} static const struct file_operations sched_feat_fops = { .open = sched_feat_open, .write = sched_feat_write, .read = seq_read, .llseek = seq_lseek, .release = single_release,}; #ifdef CONFIG_SMP static ssize_t sched_scaling_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos){ char buf[16]; if (cnt > 15) cnt = 15; if (copy_from_user(&buf, ubuf, cnt)) return -EFAULT; if (kstrtouint(buf, 10, &sysctl_sched_tunable_scaling)) return -EINVAL; if (sched_update_scaling()) return -EINVAL; *ppos += cnt; return cnt;} static int sched_scaling_show(struct seq_file *m, void *v){ seq_printf(m, "%d\n", sysctl_sched_tunable_scaling); return 0;} static int sched_scaling_open(struct inode *inode, struct file *filp){ return single_open(filp, sched_scaling_show, NULL);} static const struct file_operations sched_scaling_fops = { .open = sched_scaling_open, .write = sched_scaling_write, .read = seq_read, .llseek = seq_lseek, .release = single_release,}; #endif /* SMP */ #ifdef CONFIG_PREEMPT_DYNAMIC static ssize_t sched_dynamic_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos){ char buf[16]; int mode; if (cnt > 15) cnt = 15; if (copy_from_user(&buf, ubuf, cnt)) return -EFAULT; buf[cnt] = 0; mode = sched_dynamic_mode(strstrip(buf)); if (mode < 0) return mode; sched_dynamic_update(mode); *ppos += cnt; return cnt;} static int sched_dynamic_show(struct seq_file *m, void *v){ static const char * preempt_modes[] = { "none", "voluntary", "full" }; int i; for (i = 0; i < ARRAY_SIZE(preempt_modes); i++) { if (preempt_dynamic_mode == i) seq_puts(m, "("); seq_puts(m, preempt_modes[i]); if (preempt_dynamic_mode == i) seq_puts(m, ")"); seq_puts(m, " "); } seq_puts(m, "\n"); return 0;} static int sched_dynamic_open(struct inode *inode, struct file *filp){ return single_open(filp, sched_dynamic_show, NULL);} static const struct file_operations sched_dynamic_fops = { .open = sched_dynamic_open, .write = sched_dynamic_write, .read = seq_read, .llseek = seq_lseek, .release = single_release,}; #endif /* CONFIG_PREEMPT_DYNAMIC */ __read_mostly bool sched_debug_verbose; static const struct seq_operations sched_debug_sops; static int sched_debug_open(struct inode *inode, struct file *filp){ return seq_open(filp, &sched_debug_sops);} static const struct file_operations sched_debug_fops = { .open = sched_debug_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,}; static struct dentry *debugfs_sched; static __init int sched_init_debug(void){ struct dentry __maybe_unused *numa; debugfs_sched = debugfs_create_dir("sched", NULL); debugfs_create_file("features", 0644, debugfs_sched, NULL, &sched_feat_fops); debugfs_create_bool("verbose", 0644, debugfs_sched, &sched_debug_verbose);#ifdef CONFIG_PREEMPT_DYNAMIC debugfs_create_file("preempt", 0644, debugfs_sched, NULL, &sched_dynamic_fops);#endif debugfs_create_u32("latency_ns", 0644, debugfs_sched, &sysctl_sched_latency); debugfs_create_u32("min_granularity_ns", 0644, debugfs_sched, &sysctl_sched_min_granularity); debugfs_create_u32("wakeup_granularity_ns", 0644, debugfs_sched, &sysctl_sched_wakeup_granularity); debugfs_create_u32("latency_warn_ms", 0644, debugfs_sched, &sysctl_resched_latency_warn_ms); debugfs_create_u32("latency_warn_once", 0644, debugfs_sched, &sysctl_resched_latency_warn_once); #ifdef CONFIG_SMP debugfs_create_file("tunable_scaling", 0644, debugfs_sched, NULL, &sched_scaling_fops); debugfs_create_u32("migration_cost_ns", 0644, debugfs_sched, &sysctl_sched_migration_cost); debugfs_create_u32("nr_migrate", 0644, debugfs_sched, &sysctl_sched_nr_migrate); mutex_lock(&sched_domains_mutex); update_sched_domain_debugfs(); mutex_unlock(&sched_domains_mutex);#endif #ifdef CONFIG_NUMA_BALANCING numa = debugfs_create_dir("numa_balancing", debugfs_sched); debugfs_create_u32("scan_delay_ms", 0644, numa, &sysctl_numa_balancing_scan_delay); debugfs_create_u32("scan_period_min_ms", 0644, numa, &sysctl_numa_balancing_scan_period_min); debugfs_create_u32("scan_period_max_ms", 0644, numa, &sysctl_numa_balancing_scan_period_max); debugfs_create_u32("scan_size_mb", 0644, numa, &sysctl_numa_balancing_scan_size);#endif debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops); return 0;}late_initcall(sched_init_debug); #ifdef CONFIG_SMP static cpumask_var_t sd_sysctl_cpus;static struct dentry *sd_dentry; static int sd_flags_show(struct seq_file *m, void *v){ unsigned long flags = *(unsigned int *)m->private; int idx; for_each_set_bit(idx, &flags, __SD_FLAG_CNT) { seq_puts(m, sd_flag_debug[idx].name); seq_puts(m, " "); } seq_puts(m, "\n"); return 0;} static int sd_flags_open(struct inode *inode, struct file *file){ return single_open(file, sd_flags_show, inode->i_private);} static const struct file_operations sd_flags_fops = { .open = sd_flags_open, .read = seq_read, .llseek = seq_lseek, .release = single_release,}; static void register_sd(struct sched_domain *sd, struct dentry *parent){#define SDM(type, mode, member) \ debugfs_create_##type(#member, mode, parent, &sd->member) SDM(ulong, 0644, min_interval); SDM(ulong, 0644, max_interval); SDM(u64, 0644, max_newidle_lb_cost); SDM(u32, 0644, busy_factor); SDM(u32, 0644, imbalance_pct); SDM(u32, 0644, cache_nice_tries); SDM(str, 0444, name); #undef SDM debugfs_create_file("flags", 0444, parent, &sd->flags, &sd_flags_fops);} void update_sched_domain_debugfs(void){ int cpu, i; if (!cpumask_available(sd_sysctl_cpus)) { if (!alloc_cpumask_var(&sd_sysctl_cpus, GFP_KERNEL)) return; cpumask_copy(sd_sysctl_cpus, cpu_possible_mask); } if (!sd_dentry) sd_dentry = debugfs_create_dir("domains", debugfs_sched); for_each_cpu(cpu, sd_sysctl_cpus) { struct sched_domain *sd; struct dentry *d_cpu; char buf[32]; snprintf(buf, sizeof(buf), "cpu%d", cpu); debugfs_remove(debugfs_lookup(buf, sd_dentry)); d_cpu = debugfs_create_dir(buf, sd_dentry); i = 0; for_each_domain(cpu, sd) { struct dentry *d_sd; snprintf(buf, sizeof(buf), "domain%d", i); d_sd = debugfs_create_dir(buf, d_cpu); register_sd(sd, d_sd); i++; } __cpumask_clear_cpu(cpu, sd_sysctl_cpus); }} void dirty_sched_domain_sysctl(int cpu){ if (cpumask_available(sd_sysctl_cpus)) __cpumask_set_cpu(cpu, sd_sysctl_cpus);} #endif /* CONFIG_SMP */ #ifdef CONFIG_FAIR_GROUP_SCHEDstatic void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group *tg){ struct sched_entity *se = tg->se[cpu]; #define P(F) SEQ_printf(m, " .%-30s: %lld\n", #F, (long long)F)#define P_SCHEDSTAT(F) SEQ_printf(m, " .%-30s: %lld\n", #F, (long long)schedstat_val(F))#define PN(F) SEQ_printf(m, " .%-30s: %lld.%06ld\n", #F, SPLIT_NS((long long)F))#define PN_SCHEDSTAT(F) SEQ_printf(m, " .%-30s: %lld.%06ld\n", #F, SPLIT_NS((long long)schedstat_val(F))) if (!se) return; PN(se->exec_start); PN(se->vruntime); PN(se->sum_exec_runtime); if (schedstat_enabled()) { PN_SCHEDSTAT(se->statistics.wait_start); PN_SCHEDSTAT(se->statistics.sleep_start); PN_SCHEDSTAT(se->statistics.block_start); PN_SCHEDSTAT(se->statistics.sleep_max); PN_SCHEDSTAT(se->statistics.block_max); PN_SCHEDSTAT(se->statistics.exec_max); PN_SCHEDSTAT(se->statistics.slice_max); PN_SCHEDSTAT(se->statistics.wait_max); PN_SCHEDSTAT(se->statistics.wait_sum); P_SCHEDSTAT(se->statistics.wait_count); } P(se->load.weight);#ifdef CONFIG_SMP P(se->avg.load_avg); P(se->avg.util_avg); P(se->avg.runnable_avg);#endif #undef PN_SCHEDSTAT#undef PN#undef P_SCHEDSTAT#undef P}#endif #ifdef CONFIG_CGROUP_SCHEDstatic DEFINE_SPINLOCK(sched_debug_lock);static char group_path[PATH_MAX]; static void task_group_path(struct task_group *tg, char *path, int plen){ if (autogroup_path(tg, path, plen)) return; cgroup_path(tg->css.cgroup, path, plen);} /* * Only 1 SEQ_printf_task_group_path() caller can use the full length * group_path[] for cgroup path. Other simultaneous callers will have * to use a shorter stack buffer. A "..." suffix is appended at the end * of the stack buffer so that it will show up in case the output length * matches the given buffer size to indicate possible path name truncation. */#define SEQ_printf_task_group_path(m, tg, fmt...) \{ \ if (spin_trylock(&sched_debug_lock)) { \ task_group_path(tg, group_path, sizeof(group_path)); \ SEQ_printf(m, fmt, group_path); \ spin_unlock(&sched_debug_lock); \Lines 1–500 of 1059. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * kernel/sched/debug.c * * Print the CFS rbtree and other debugging details * * Copyright(C) 2007, Red Hat, Inc., Ingo Molnar */ #include "sched.h" /* * This allows printing both to /proc/sched_debug and * to the console */ #define SEQ_printf(m, x...) \ do { \ if (m) \ seq_printf(m, x); \ else \ pr_cont(x); \ } while (0) /* * Ease the printing of nsec fields: */ static long long nsec_high(unsigned long long nsec) { if ((long long)nsec < 0) { nsec = -nsec; do_div(nsec, 1000000); return -nsec; } do_div(nsec, 1000000); return nsec; } static unsigned long nsec_low(unsigned long long nsec) { if ((long long)nsec < 0) nsec = -nsec; return do_div(nsec, 1000000); } #define SPLIT_NS(x) nsec_high(x), nsec_low(x) #define SCHED_FEAT(name, enabled) \ #name , static const char * const sched_feat_names[] = { #include "features.h" }; #undef SCHED_FEAT static int sched_feat_show(struct seq_file *m, void *v) { int i; for (i = 0; i < __SCHED_FEAT_NR; i++) { if (!(sysctl_sched_features & (1UL << i))) seq_puts(m, "NO_"); seq_printf(m, "%s ", sched_feat_names[i]); } seq_puts(m, "\n"); return 0; } #ifdef CONFIG_JUMP_LABEL #define jump_label_key__true STATIC_KEY_INIT_TRUE #define jump_label_key__false STATIC_KEY_INIT_FALSE #define SCHED_FEAT(name, enabled) \ jump_label_key__##enabled , struct static_key sched_feat_keys[__SCHED_FEAT_NR] = { #include "features.h" }; #undef SCHED_FEAT static void sched_feat_disable(int i) { static_key_disable_cpuslocked(&sched_feat_keys[i]); } static void sched_feat_enable(int i) { static_key_enable_cpuslocked(&sched_feat_keys[i]); } #else static void sched_feat_disable(int i) { }; static void sched_feat_enable(int i) { }; #endif /* CONFIG_JUMP_LABEL */ static int sched_feat_set(char *cmp) { int i; int neg = 0; if (strncmp(cmp, "NO_", 3) == 0) { neg = 1; cmp += 3; } i = match_string(sched_feat_names, __SCHED_FEAT_NR, cmp); if (i < 0) return i; if (neg) { sysctl_sched_features &= ~(1UL << i); sched_feat_disable(i); } else { sysctl_sched_features |= (1UL << i); sched_feat_enable(i); } return 0; } static ssize_t sched_feat_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { char buf[64]; char *cmp; int ret; struct inode *inode; if (cnt > 63) cnt = 63; if (copy_from_user(&buf, ubuf, cnt)) return -EFAULT; buf[cnt] = 0; cmp = strstrip(buf); /* Ensure the static_key remains in a consistent state */ inode = file_inode(filp); cpus_read_lock(); inode_lock(inode); ret = sched_feat_set(cmp); inode_unlock(inode); cpus_read_unlock(); if (ret < 0) return ret; *ppos += cnt; return cnt; } static int sched_feat_open(struct inode *inode, struct file *filp) { return single_open(filp, sched_feat_show, NULL); } static const struct file_operations sched_feat_fops = { .open = sched_feat_open, .write = sched_feat_write, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; #ifdef CONFIG_SMP static ssize_t sched_scaling_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { char buf[16]; if (cnt > 15) cnt = 15; if (copy_from_user(&buf, ubuf, cnt)) return -EFAULT; if (kstrtouint(buf, 10, &sysctl_sched_tunable_scaling)) return -EINVAL; if (sched_update_scaling()) return -EINVAL; *ppos += cnt; return cnt; } static int sched_scaling_show(struct seq_file *m, void *v) { seq_printf(m, "%d\n", sysctl_sched_tunable_scaling); return 0; } static int sched_scaling_open(struct inode *inode, struct file *filp) { return single_open(filp, sched_scaling_show, NULL); } static const struct file_operations sched_scaling_fops = { .open = sched_scaling_open, .write = sched_scaling_write, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; #endif /* SMP */ #ifdef CONFIG_PREEMPT_DYNAMIC static ssize_t sched_dynamic_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { char buf[16]; int mode; if (cnt > 15) cnt = 15; if (copy_from_user(&buf, ubuf, cnt)) return -EFAULT; buf[cnt] = 0; mode = sched_dynamic_mode(strstrip(buf)); if (mode < 0) return mode; sched_dynamic_update(mode); *ppos += cnt; return cnt; } static int sched_dynamic_show(struct seq_file *m, void *v) { static const char * preempt_modes[] = { "none", "voluntary", "full" }; int i; for (i = 0; i < ARRAY_SIZE(preempt_modes); i++) { if (preempt_dynamic_mode == i) seq_puts(m, "("); seq_puts(m, preempt_modes[i]); if (preempt_dynamic_mode == i) seq_puts(m, ")"); seq_puts(m, " "); } seq_puts(m, "\n"); return 0; } static int sched_dynamic_open(struct inode *inode, struct file *filp) { return single_open(filp, sched_dynamic_show, NULL); } static const struct file_operations sched_dynamic_fops = { .open = sched_dynamic_open, .write = sched_dynamic_write, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; #endif /* CONFIG_PREEMPT_DYNAMIC */ __read_mostly bool sched_debug_verbose; static const struct seq_operations sched_debug_sops; static int sched_debug_open(struct inode *inode, struct file *filp) { return seq_open(filp, &sched_debug_sops); } static const struct file_operations sched_debug_fops = { .open = sched_debug_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; static struct dentry *debugfs_sched; static __init int sched_init_debug(void) { struct dentry __maybe_unused *numa; debugfs_sched = debugfs_create_dir("sched", NULL); debugfs_create_file("features", 0644, debugfs_sched, NULL, &sched_feat_fops); debugfs_create_bool("verbose", 0644, debugfs_sched, &sched_debug_verbose); #ifdef CONFIG_PREEMPT_DYNAMIC debugfs_create_file("preempt", 0644, debugfs_sched, NULL, &sched_dynamic_fops); #endif debugfs_create_u32("latency_ns", 0644, debugfs_sched, &sysctl_sched_latency); debugfs_create_u32("min_granularity_ns", 0644, debugfs_sched, &sysctl_sched_min_granularity); debugfs_create_u32("wakeup_granularity_ns", 0644, debugfs_sched, &sysctl_sched_wakeup_granularity); debugfs_create_u32("latency_warn_ms", 0644, debugfs_sched, &sysctl_resched_latency_warn_ms); debugfs_create_u32("latency_warn_once", 0644, debugfs_sched, &sysctl_resched_latency_warn_once); #ifdef CONFIG_SMP debugfs_create_file("tunable_scaling", 0644, debugfs_sched, NULL, &sched_scaling_fops); debugfs_create_u32("migration_cost_ns", 0644, debugfs_sched, &sysctl_sched_migration_cost); debugfs_create_u32("nr_migrate", 0644, debugfs_sched, &sysctl_sched_nr_migrate); mutex_lock(&sched_domains_mutex); update_sched_domain_debugfs(); mutex_unlock(&sched_domains_mutex); #endif #ifdef CONFIG_NUMA_BALANCING numa = debugfs_create_dir("numa_balancing", debugfs_sched); debugfs_create_u32("scan_delay_ms", 0644, numa, &sysctl_numa_balancing_scan_delay); debugfs_create_u32("scan_period_min_ms", 0644, numa, &sysctl_numa_balancing_scan_period_min); debugfs_create_u32("scan_period_max_ms", 0644, numa, &sysctl_numa_balancing_scan_period_max); debugfs_create_u32("scan_size_mb", 0644, numa, &sysctl_numa_balancing_scan_size); #endif debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops); return 0; } late_initcall(sched_init_debug); #ifdef CONFIG_SMP static cpumask_var_t sd_sysctl_cpus; static struct dentry *sd_dentry; static int sd_flags_show(struct seq_file *m, void *v) { unsigned long flags = *(unsigned int *)m->private; int idx; for_each_set_bit(idx, &flags, __SD_FLAG_CNT) { seq_puts(m, sd_flag_debug[idx].name); seq_puts(m, " "); } seq_puts(m, "\n"); return 0; } static int sd_flags_open(struct inode *inode, struct file *file) { return single_open(file, sd_flags_show, inode->i_private); } static const struct file_operations sd_flags_fops = { .open = sd_flags_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static void register_sd(struct sched_domain *sd, struct dentry *parent) { #define SDM(type, mode, member) \ debugfs_create_##type(#member, mode, parent, &sd->member) SDM(ulong, 0644, min_interval); SDM(ulong, 0644, max_interval); SDM(u64, 0644, max_newidle_lb_cost); SDM(u32, 0644, busy_factor); SDM(u32, 0644, imbalance_pct); SDM(u32, 0644, cache_nice_tries); SDM(str, 0444, name); #undef SDM debugfs_create_file("flags", 0444, parent, &sd->flags, &sd_flags_fops); } void update_sched_domain_debugfs(void) { int cpu, i; if (!cpumask_available(sd_sysctl_cpus)) { if (!alloc_cpumask_var(&sd_sysctl_cpus, GFP_KERNEL)) return; cpumask_copy(sd_sysctl_cpus, cpu_possible_mask); } if (!sd_dentry) sd_dentry = debugfs_create_dir("domains", debugfs_sched); for_each_cpu(cpu, sd_sysctl_cpus) { struct sched_domain *sd; struct dentry *d_cpu; char buf[32]; snprintf(buf, sizeof(buf), "cpu%d", cpu); debugfs_remove(debugfs_lookup(buf, sd_dentry)); d_cpu = debugfs_create_dir(buf, sd_dentry); i = 0; for_each_domain(cpu, sd) { struct dentry *d_sd; snprintf(buf, sizeof(buf), "domain%d", i); d_sd = debugfs_create_dir(buf, d_cpu); register_sd(sd, d_sd); i++; } __cpumask_clear_cpu(cpu, sd_sysctl_cpus); } } void dirty_sched_domain_sysctl(int cpu) { if (cpumask_available(sd_sysctl_cpus)) __cpumask_set_cpu(cpu, sd_sysctl_cpus); } #endif /* CONFIG_SMP */ #ifdef CONFIG_FAIR_GROUP_SCHED static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group *tg) { struct sched_entity *se = tg->se[cpu]; #define P(F) SEQ_printf(m, " .%-30s: %lld\n", #F, (long long)F) #define P_SCHEDSTAT(F) SEQ_printf(m, " .%-30s: %lld\n", #F, (long long)schedstat_val(F)) #define PN(F) SEQ_printf(m, " .%-30s: %lld.%06ld\n", #F, SPLIT_NS((long long)F)) #define PN_SCHEDSTAT(F) SEQ_printf(m, " .%-30s: %lld.%06ld\n", #F, SPLIT_NS((long long)schedstat_val(F))) if (!se) return; PN(se->exec_start); PN(se->vruntime); PN(se->sum_exec_runtime); if (schedstat_enabled()) { PN_SCHEDSTAT(se->statistics.wait_start); PN_SCHEDSTAT(se->statistics.sleep_start); PN_SCHEDSTAT(se->statistics.block_start); PN_SCHEDSTAT(se->statistics.sleep_max); PN_SCHEDSTAT(se->statistics.block_max); PN_SCHEDSTAT(se->statistics.exec_max); PN_SCHEDSTAT(se->statistics.slice_max); PN_SCHEDSTAT(se->statistics.wait_max); PN_SCHEDSTAT(se->statistics.wait_sum); P_SCHEDSTAT(se->statistics.wait_count); } P(se->load.weight); #ifdef CONFIG_SMP P(se->avg.load_avg); P(se->avg.util_avg); P(se->avg.runnable_avg); #endif #undef PN_SCHEDSTAT #undef PN #undef P_SCHEDSTAT #undef P } #endif #ifdef CONFIG_CGROUP_SCHED static DEFINE_SPINLOCK(sched_debug_lock); static char group_path[PATH_MAX]; static void task_group_path(struct task_group *tg, char *path, int plen) { if (autogroup_path(tg, path, plen)) return; cgroup_path(tg->css.cgroup, path, plen); } /* * Only 1 SEQ_printf_task_group_path() caller can use the full length * group_path[] for cgroup path. Other simultaneous callers will have * to use a shorter stack buffer. A "..." suffix is appended at the end * of the stack buffer so that it will show up in case the output length * matches the given buffer size to indicate possible path name truncation. */ #define SEQ_printf_task_group_path(m, tg, fmt...) \ { \ if (spin_trylock(&sched_debug_lock)) { \ task_group_path(tg, group_path, sizeof(group_path)); \ SEQ_printf(m, fmt, group_path); \ spin_unlock(&sched_debug_lock); \