1079 lines · 25.5 KB · C
RawDownload
// 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 */ /* * 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];	unsigned int scaling; 	if (cnt > 15)		cnt = 15; 	if (copy_from_user(&buf, ubuf, cnt))		return -EFAULT;	buf[cnt] = '\0'; 	if (kstrtouint(buf, 10, &scaling))		return -EINVAL; 	if (scaling >= SCHED_TUNABLESCALING_END)		return -EINVAL; 	sysctl_sched_tunable_scaling = scaling;	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("idle_min_granularity_ns", 0644, debugfs_sched, &sysctl_sched_idle_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; 	/*	 * This can unfortunately be invoked before sched_debug_init() creates	 * the debug directory. Don't touch sd_sysctl_cpus until then.	 */	if (!debugfs_sched)		return; 	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(stats->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(stats->F))) 	if (!se)		return; 	PN(se->exec_start);	PN(se->vruntime);	PN(se->sum_exec_runtime); 	if (schedstat_enabled()) {		struct sched_statistics *stats;		stats = __schedstats_from_se(se); 		PN_SCHEDSTAT(wait_start);		PN_SCHEDSTAT(sleep_start);		PN_SCHEDSTAT(block_start);		PN_SCHEDSTAT(sleep_max);		PN_SCHEDSTAT(block_max);		PN_SCHEDSTAT(exec_max);		PN_SCHEDSTAT(slice_max);		PN_SCHEDSTAT(wait_max);		PN_SCHEDSTAT(wait_sum);		P_SCHEDSTAT(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))

Lines 1–500 of 1079.