1391e43daSPeter Zijlstra 2391e43daSPeter Zijlstra #include <linux/slab.h> 3391e43daSPeter Zijlstra #include <linux/fs.h> 4391e43daSPeter Zijlstra #include <linux/seq_file.h> 5391e43daSPeter Zijlstra #include <linux/proc_fs.h> 6391e43daSPeter Zijlstra 7391e43daSPeter Zijlstra #include "sched.h" 8391e43daSPeter Zijlstra 9391e43daSPeter Zijlstra /* 10391e43daSPeter Zijlstra * bump this up when changing the output format or the meaning of an existing 11391e43daSPeter Zijlstra * format, so that tools can adapt (or abort) 12391e43daSPeter Zijlstra */ 13391e43daSPeter Zijlstra #define SCHEDSTAT_VERSION 15 14391e43daSPeter Zijlstra 15391e43daSPeter Zijlstra static int show_schedstat(struct seq_file *seq, void *v) 16391e43daSPeter Zijlstra { 17391e43daSPeter Zijlstra int cpu; 18391e43daSPeter Zijlstra int mask_len = DIV_ROUND_UP(NR_CPUS, 32) * 9; 19391e43daSPeter Zijlstra char *mask_str = kmalloc(mask_len, GFP_KERNEL); 20391e43daSPeter Zijlstra 21391e43daSPeter Zijlstra if (mask_str == NULL) 22391e43daSPeter Zijlstra return -ENOMEM; 23391e43daSPeter Zijlstra 24391e43daSPeter Zijlstra seq_printf(seq, "version %d\n", SCHEDSTAT_VERSION); 25391e43daSPeter Zijlstra seq_printf(seq, "timestamp %lu\n", jiffies); 26391e43daSPeter Zijlstra for_each_online_cpu(cpu) { 27391e43daSPeter Zijlstra struct rq *rq = cpu_rq(cpu); 28391e43daSPeter Zijlstra #ifdef CONFIG_SMP 29391e43daSPeter Zijlstra struct sched_domain *sd; 30391e43daSPeter Zijlstra int dcount = 0; 31391e43daSPeter Zijlstra #endif 32391e43daSPeter Zijlstra 33391e43daSPeter Zijlstra /* runqueue-specific stats */ 34391e43daSPeter Zijlstra seq_printf(seq, 35391e43daSPeter Zijlstra "cpu%d %u %u %u %u %u %u %llu %llu %lu", 36391e43daSPeter Zijlstra cpu, rq->yld_count, 37391e43daSPeter Zijlstra rq->sched_switch, rq->sched_count, rq->sched_goidle, 38391e43daSPeter Zijlstra rq->ttwu_count, rq->ttwu_local, 39391e43daSPeter Zijlstra rq->rq_cpu_time, 40391e43daSPeter Zijlstra rq->rq_sched_info.run_delay, rq->rq_sched_info.pcount); 41391e43daSPeter Zijlstra 42391e43daSPeter Zijlstra seq_printf(seq, "\n"); 43391e43daSPeter Zijlstra 44391e43daSPeter Zijlstra #ifdef CONFIG_SMP 45391e43daSPeter Zijlstra /* domain-specific stats */ 46391e43daSPeter Zijlstra rcu_read_lock(); 47391e43daSPeter Zijlstra for_each_domain(cpu, sd) { 48391e43daSPeter Zijlstra enum cpu_idle_type itype; 49391e43daSPeter Zijlstra 50391e43daSPeter Zijlstra cpumask_scnprintf(mask_str, mask_len, 51391e43daSPeter Zijlstra sched_domain_span(sd)); 52391e43daSPeter Zijlstra seq_printf(seq, "domain%d %s", dcount++, mask_str); 53391e43daSPeter Zijlstra for (itype = CPU_IDLE; itype < CPU_MAX_IDLE_TYPES; 54391e43daSPeter Zijlstra itype++) { 55391e43daSPeter Zijlstra seq_printf(seq, " %u %u %u %u %u %u %u %u", 56391e43daSPeter Zijlstra sd->lb_count[itype], 57391e43daSPeter Zijlstra sd->lb_balanced[itype], 58391e43daSPeter Zijlstra sd->lb_failed[itype], 59391e43daSPeter Zijlstra sd->lb_imbalance[itype], 60391e43daSPeter Zijlstra sd->lb_gained[itype], 61391e43daSPeter Zijlstra sd->lb_hot_gained[itype], 62391e43daSPeter Zijlstra sd->lb_nobusyq[itype], 63391e43daSPeter Zijlstra sd->lb_nobusyg[itype]); 64391e43daSPeter Zijlstra } 65391e43daSPeter Zijlstra seq_printf(seq, 66391e43daSPeter Zijlstra " %u %u %u %u %u %u %u %u %u %u %u %u\n", 67391e43daSPeter Zijlstra sd->alb_count, sd->alb_failed, sd->alb_pushed, 68391e43daSPeter Zijlstra sd->sbe_count, sd->sbe_balanced, sd->sbe_pushed, 69391e43daSPeter Zijlstra sd->sbf_count, sd->sbf_balanced, sd->sbf_pushed, 70391e43daSPeter Zijlstra sd->ttwu_wake_remote, sd->ttwu_move_affine, 71391e43daSPeter Zijlstra sd->ttwu_move_balance); 72391e43daSPeter Zijlstra } 73391e43daSPeter Zijlstra rcu_read_unlock(); 74391e43daSPeter Zijlstra #endif 75391e43daSPeter Zijlstra } 76391e43daSPeter Zijlstra kfree(mask_str); 77391e43daSPeter Zijlstra return 0; 78391e43daSPeter Zijlstra } 79391e43daSPeter Zijlstra 80391e43daSPeter Zijlstra static int schedstat_open(struct inode *inode, struct file *file) 81391e43daSPeter Zijlstra { 82391e43daSPeter Zijlstra unsigned int size = PAGE_SIZE * (1 + num_online_cpus() / 32); 83391e43daSPeter Zijlstra char *buf = kmalloc(size, GFP_KERNEL); 84391e43daSPeter Zijlstra struct seq_file *m; 85391e43daSPeter Zijlstra int res; 86391e43daSPeter Zijlstra 87391e43daSPeter Zijlstra if (!buf) 88391e43daSPeter Zijlstra return -ENOMEM; 89391e43daSPeter Zijlstra res = single_open(file, show_schedstat, NULL); 90391e43daSPeter Zijlstra if (!res) { 91391e43daSPeter Zijlstra m = file->private_data; 92391e43daSPeter Zijlstra m->buf = buf; 93391e43daSPeter Zijlstra m->size = size; 94391e43daSPeter Zijlstra } else 95391e43daSPeter Zijlstra kfree(buf); 96391e43daSPeter Zijlstra return res; 97391e43daSPeter Zijlstra } 98391e43daSPeter Zijlstra 99391e43daSPeter Zijlstra static const struct file_operations proc_schedstat_operations = { 100391e43daSPeter Zijlstra .open = schedstat_open, 101391e43daSPeter Zijlstra .read = seq_read, 102391e43daSPeter Zijlstra .llseek = seq_lseek, 103391e43daSPeter Zijlstra .release = single_release, 104391e43daSPeter Zijlstra }; 105391e43daSPeter Zijlstra 106391e43daSPeter Zijlstra static int __init proc_schedstat_init(void) 107391e43daSPeter Zijlstra { 108391e43daSPeter Zijlstra proc_create("schedstat", 0, NULL, &proc_schedstat_operations); 109391e43daSPeter Zijlstra return 0; 110391e43daSPeter Zijlstra } 111391e43daSPeter Zijlstra module_init(proc_schedstat_init); 112