sched: Display deadline bandwidth and other SCHED_DEBUG clean up
Steven Rostedt
maintainercover sched: Display deadline bandwidth and other SCHED_DEBUG clean up
[ Nothing different since my v2 I posted, except hopefully people
will look at it this time :-) I also removed the RFC ]
I'm starting to play with SCHED_DEADLINE a bit and I'm able to cause a bandwidth "leak". Then I realized there's no way to examine what bandwidths are enabled on which CPUs. I added the bandwith ratios to the /proc/sched_debug file.
I will be posting the SCHED_DEADLINE issue in a separate thread.
# grep dl /proc/sched_debug dl_rq[0]: .dl_nr_running : 0 .dl_bw->bw : 996147 .dl_bw->total_bw : 0 dl_rq[1]: .dl_nr_running : 0 .dl_bw->bw : 996147 .dl_bw->total_bw : 104857 dl_rq[2]: .dl_nr_running : 0 .dl_bw->bw : 996147 .dl_bw->total_bw : 0 dl_rq[3]: .dl_nr_running : 0 .dl_bw->bw : 996147 .dl_bw->total_bw : 0 dl_rq[4]: .dl_nr_running : 0 .dl_bw->bw : 996147 .dl_bw->total_bw : 0 dl_rq[5]: .dl_nr_running : 0 .dl_bw->bw : 996147 .dl_bw->total_bw : 0 dl_rq[6]: .dl_nr_running : 0 .dl_bw->bw : 996147 .dl_bw->total_bw : 0 dl_rq[7]: .dl_nr_running : 0 .dl_bw->bw : 996147 .dl_bw->total_bw : 0
Before adding this code, I also realized there was a bit of SCHED_DEBUG code in the kernel/sched/core.c file, and decided to move that to kernel/sched/debug.c to clean the core.c file up a bit. Those patches are mostly orthognal to the deadline_bw file, but decided to group them together here.
Steven Rostedt (Red Hat) (4):
sched: Move sched_feature file setup into debug.c
sched: Move sched_domain_sysctl to debug.c
sched: Add bandwidth ratio to /proc/sched_debug
tracing: Add __print_ns_to_secs() and __print_ns_without_secs() helpers
----
include/trace/trace_events.h | 25 ++++ kernel/sched/core.c | 311 ------------------------------------------ kernel/sched/debug.c | 313 +++++++++++++++++++++++++++++++++++++++++++ kernel/sched/sched.h | 13 ++ 4 files changed, 351 insertions(+), 311 deletions(-)
Steven Rostedt
maintainerPATCH 1/4 sched: Move sched_feature file setup into debug.c
From: "Steven Rostedt (Red Hat)" <[email protected]>
As sched_feature is only created when SCHED_DEBUG is enabled, and the file debug.c is only compiled when SCHED_DEBUG is enabled, it makes sense to move sched_feature setup into that file and get rid of the #ifdef.
--- kernel/sched/core.c | 133 --------------------------------------------------- kernel/sched/debug.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 133 deletions(-)
kernel/sched/core.c +0 -133
@@ -66,7 +66,6 @@#include <linux/pagemap.h> #include <linux/hrtimer.h> #include <linux/tick.h> -#include <linux/debugfs.h> #include <linux/ctype.h> #include <linux/ftrace.h> #include <linux/slab.h>
@@ -124,138 +123,6 @@ const_debug unsigned int sysctl_sched_features =#undef SCHED_FEAT -#ifdef CONFIG_SCHED_DEBUG -#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 HAVE_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 (&sched_feat_keys[i]); -} - -static void sched_feat_enable (int i) -{ -static_key_enable (&sched_feat_keys[i]); -} -#else -static void sched_feat_disable (int i) { }; -static void sched_feat_enable (int i) { }; -#endif /* HAVE_JUMP_LABEL */ - -static int sched_feat_set (char *cmp) -{ -int i; -int neg =0 ; - -if (strncmp (cmp,"NO_" ,3 ) ==0 ) { - neg =1 ; - cmp +=3 ; - } - -for (i =0 ; i < __SCHED_FEAT_NR; i++) { -if (strcmp (cmp, sched_feat_names[i]) ==0 ) { -if (neg) { - sysctl_sched_features &= ~(1UL << i); -sched_feat_disable (i); - }else { - sysctl_sched_features |= (1UL << i); -sched_feat_enable (i); - } -break ; - } - } - -return i; -} - -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 i; -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); -inode_lock (inode); - i =sched_feat_set (cmp); -inode_unlock (inode); -if (i == __SCHED_FEAT_NR) -return -EINVAL ; - - *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, -}; - -static __init int sched_init_debug (void ) -{ -debugfs_create_file ("sched_features" ,0644 ,NULL ,NULL , - &sched_feat_fops); - -return 0 ; -} -late_initcall (sched_init_debug); -#endif /* CONFIG_SCHED_DEBUG */ -/* * Number of tasks to iterate in a single balance run. * Limited because this is done with IRQs disabled.
kernel/sched/debug.c +131 -0
143 lines not on this page · raw message
Signature · 1 line
2.6.4
tip-bot for Steven Rostedt (Red Hat)
merge bot[tip:sched/core] sched/debug: Move the /sys/kernel/debug/sched_features file setup into debug.c
sched/debug: Move the /sys/kernel/debug/sched_features file setup into debug.c
Commit-ID: d6ca41d7922ce0110a840ef4f8ec4afdd5a239d3 Gitweb: http://git.kernel.org/tip/d6ca41d7922ce0110a840ef4f8ec4afdd5a239d3 Author: Steven Rostedt (Red Hat) <[email protected]> AuthorDate: Mon, 22 Feb 2016 16:26:50 -0500 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 29 Feb 2016 09:53:06 +0100
sched/debug: Move the /sys/kernel/debug/sched_features file setup into debug.c
As /sys/kernel/debug/sched_features is only created when SCHED_DEBUG is enabled, and the file debug.c is only compiled when SCHED_DEBUG is enabled, it makes sense to move sched_feature setup into that file and get rid of the #ifdef.
--- kernel/sched/core.c | 133 --------------------------------------------------- kernel/sched/debug.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 133 deletions(-)
kernel/sched/core.c +0 -133
@@ -66,7 +66,6 @@#include <linux/pagemap.h> #include <linux/hrtimer.h> #include <linux/tick.h> -#include <linux/debugfs.h> #include <linux/ctype.h> #include <linux/ftrace.h> #include <linux/slab.h>
@@ -124,138 +123,6 @@ const_debug unsigned int sysctl_sched_features =#undef SCHED_FEAT -#ifdef CONFIG_SCHED_DEBUG -#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 HAVE_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 (&sched_feat_keys[i]); -} - -static void sched_feat_enable (int i) -{ -static_key_enable (&sched_feat_keys[i]); -} -#else -static void sched_feat_disable (int i) { }; -static void sched_feat_enable (int i) { }; -#endif /* HAVE_JUMP_LABEL */ - -static int sched_feat_set (char *cmp) -{ -int i; -int neg =0 ; - -if (strncmp (cmp,"NO_" ,3 ) ==0 ) { - neg =1 ; - cmp +=3 ; - } - -for (i =0 ; i < __SCHED_FEAT_NR; i++) { -if (strcmp (cmp, sched_feat_names[i]) ==0 ) { -if (neg) { - sysctl_sched_features &= ~(1UL << i); -sched_feat_disable (i); - }else { - sysctl_sched_features |= (1UL << i); -sched_feat_enable (i); - } -break ; - } - } - -return i; -} - -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 i; -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); -inode_lock (inode); - i =sched_feat_set (cmp); -inode_unlock (inode); -if (i == __SCHED_FEAT_NR) -return -EINVAL ; - - *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, -}; - -static __init int sched_init_debug (void ) -{ -debugfs_create_file ("sched_features" ,0644 ,NULL ,NULL , - &sched_feat_fops); - -return 0 ; -} -late_initcall (sched_init_debug); -#endif /* CONFIG_SCHED_DEBUG */ -/* * Number of tasks to iterate in a single balance run. * Limited because this is done with IRQs disabled.
kernel/sched/debug.c +131 -0
143 lines not on this page · raw message
Steven Rostedt
maintainerPATCH 2/4 sched: Move sched_domain_sysctl to debug.c
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
The sched_domain_sysctl setup is only enabled when SCHED_DEBUG is configured. As debug.c is only compiled when SCHED_DEBUG is configured as well, move the setup of sched_domain_sysctl into that file.
Note, the (un)register_sched_domain_sysctl() functions had to be changed from static to allow access to them from core.c.
--- kernel/sched/core.c | 178 --------------------------------------------------- kernel/sched/debug.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ kernel/sched/sched.h | 13 ++++ 3 files changed, 186 insertions(+), 178 deletions(-)
kernel/sched/core.c +0 -178
@@ -70,7 +70,6 @@#include <linux/ftrace.h> #include <linux/slab.h> #include <linux/init_task.h> -#include <linux/binfmts.h> #include <linux/context_tracking.h> #include <linux/compiler.h>
@@ -5272,183 +5271,6 @@ static void migrate_tasks(struct rq *dead_rq) }#endif /* CONFIG_HOTPLUG_CPU */ -#if defined(CONFIG_SCHED_DEBUG ) && defined(CONFIG_SYSCTL ) - -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 struct ctl_table *sd_alloc_ctl_entry (int n) -{ -struct ctl_table *entry = -kcalloc (n,sizeof (struct ctl_table ),GFP_KERNEL ); - -return entry; -} - -static void sd_free_ctl_entry (struct ctl_table **tablep) -{ -struct ctl_table *entry; - -/* -* In the intermediate directories, both the child directory and -* procname are dynamically allocated and could fail but the mode -* will always be set. In the lowest directory the names are -* static strings and all have proc handlers. -*/ -for (entry = *tablep; entry->mode; entry++) { -if (entry->child) -sd_free_ctl_entry (&entry->child); -if (entry->proc_handler ==NULL ) -kfree (entry->procname); - } - -kfree (*tablep); - *tablep =NULL ; -} - -static int min_load_idx =0 ; -static int max_load_idx =CPU_LOAD_IDX_MAX -1 ; - -static void -set_table_entry (struct ctl_table *entry, -const char *procname,void *data,int maxlen, -umode_t mode,proc_handler *proc_handler, -bool load_idx) -{ - entry->procname = procname; - entry->data = data; - entry->maxlen = maxlen; - entry->mode = mode; - entry->proc_handler = proc_handler; - -if (load_idx) { - entry->extra1 = &min_load_idx; - entry->extra2 = &max_load_idx; - } -} - -static struct ctl_table * -sd_alloc_ctl_domain_table (struct sched_domain *sd) -{ -struct ctl_table *table =sd_alloc_ctl_entry (14 ); - -if (table ==NULL ) -return NULL ; - -set_table_entry (&table[0 ],"min_interval" , &sd->min_interval, -sizeof (long ),0644 , proc_doulongvec_minmax, false); -set_table_entry (&table[1 ],"max_interval" , &sd->max_interval, -sizeof (long ),0644 , proc_doulongvec_minmax, false); -set_table_entry (&table[2 ],"busy_idx" , &sd->busy_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[3 ],"idle_idx" , &sd->idle_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[4 ],"newidle_idx" , &sd->newidle_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[5 ],"wake_idx" , &sd->wake_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[6 ],"forkexec_idx" , &sd->forkexec_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[7 ],"busy_factor" , &sd->busy_factor, -sizeof (int ),0644 , proc_dointvec_minmax, false); -set_table_entry (&table[8 ],"imbalance_pct" , &sd->imbalance_pct, -sizeof (int ),0644 , proc_dointvec_minmax, false); -set_table_entry (&table[9 ],"cache_nice_tries" , - &sd->cache_nice_tries, -sizeof (int ),0644 , proc_dointvec_minmax, false); -set_table_entry (&table[10 ],"flags" , &sd->flags, -sizeof (int ),0644 , proc_dointvec_minmax, false); -set_table_entry (&table[11 ],"max_newidle_lb_cost" , - &sd->max_newidle_lb_cost, -sizeof (long ),0644 , proc_doulongvec_minmax, false); -set_table_entry (&table[12 ],"name" , sd->name, -CORENAME_MAX_SIZE ,0444 , proc_dostring, false); -/* &table[13] 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 =sd_alloc_ctl_entry (domain_num +1 ); -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 struct ctl_table_header *sd_sysctl_header; -static void register_sched_domain_sysctl (void ) -{ -int i, cpu_num =num_possible_cpus (); -struct ctl_table *entry =sd_alloc_ctl_entry (cpu_num +1 ); -char buf[32 ]; - -WARN_ON (sd_ctl_dir[0 ].child); - sd_ctl_dir[0 ].child = entry; - -if (entry ==NULL ) -return ; - -for_each_possible_cpu (i) { -snprintf (buf,32 ,"cpu%d" , i); - entry->procname =kstrdup (buf,GFP_KERNEL ); - entry->mode =0555 ; - entry->child =sd_alloc_ctl_cpu_table (i); - entry++; - } - -WARN_ON (sd_sysctl_header); - sd_sysctl_header =register_sysctl_table (sd_ctl_root); -} - -/* may be called multiple times per register */ -static void unregister_sched_domain_sysctl (void ) -{ -unregister_sysctl_table (sd_sysctl_header); - sd_sysctl_header =NULL ; -if (sd_ctl_dir[0 ].child) -sd_free_ctl_entry (&sd_ctl_dir[0 ].child); -} -#else -static void register_sched_domain_sysctl (void ) -{ -} -static void unregister_sched_domain_sysctl (void ) -{ -} -#endif /* CONFIG_SCHED_DEBUG && CONFIG_SYSCTL */ -static void set_rq_online (struct rq *rq) {if (!rq->online) {
kernel/sched/debug.c +173 -0
179 lines not on this page · raw message
kernel/sched/sched.h +13 -0
@@ -3,6 +3,7 @@#include <linux/sched/sysctl.h> #include <linux/sched/rt.h> #include <linux/sched/deadline.h> +#include <linux/binfmts.h> #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/stop_machine.h>
@@ -909,6 +910,18 @@ static inline unsigned int group_first_cpu(struct sched_group *group)extern int group_balance_cpu (struct sched_group *sg); +#if defined(CONFIG_SCHED_DEBUG ) && defined(CONFIG_SYSCTL ) +void register_sched_domain_sysctl (void ); +void unregister_sched_domain_sysctl (void ); +#else +static inline void register_sched_domain_sysctl (void ) +{ +} +static inline void unregister_sched_domain_sysctl (void ) +{ +} +#endif +#else static inline void sched_ttwu_pending (void ) { }
Signature · 1 line
2.6.4
tip-bot for Steven Rostedt (Red Hat)
merge bot[tip:sched/core] sched/debug: Move sched_domain_sysctl to debug.c
sched/debug: Move sched_domain_sysctl to debug.c
Commit-ID: 3866e845ed522258c77da2eaa9f849ef55206ca2 Gitweb: http://git.kernel.org/tip/3866e845ed522258c77da2eaa9f849ef55206ca2 Author: Steven Rostedt (Red Hat) <[email protected]> AuthorDate: Mon, 22 Feb 2016 16:26:51 -0500 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 29 Feb 2016 09:53:06 +0100
sched/debug: Move sched_domain_sysctl to debug.c
The sched_domain_sysctl setup is only enabled when SCHED_DEBUG is configured. As debug.c is only compiled when SCHED_DEBUG is configured as well, move the setup of sched_domain_sysctl into that file.
Note, the (un)register_sched_domain_sysctl() functions had to be changed from static to allow access to them from core.c.
--- kernel/sched/core.c | 178 --------------------------------------------------- kernel/sched/debug.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ kernel/sched/sched.h | 13 ++++ 3 files changed, 186 insertions(+), 178 deletions(-)
kernel/sched/core.c +0 -178
@@ -70,7 +70,6 @@#include <linux/ftrace.h> #include <linux/slab.h> #include <linux/init_task.h> -#include <linux/binfmts.h> #include <linux/context_tracking.h> #include <linux/compiler.h>
@@ -5342,183 +5341,6 @@ static void migrate_tasks(struct rq *dead_rq) }#endif /* CONFIG_HOTPLUG_CPU */ -#if defined(CONFIG_SCHED_DEBUG ) && defined(CONFIG_SYSCTL ) - -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 struct ctl_table *sd_alloc_ctl_entry (int n) -{ -struct ctl_table *entry = -kcalloc (n,sizeof (struct ctl_table ),GFP_KERNEL ); - -return entry; -} - -static void sd_free_ctl_entry (struct ctl_table **tablep) -{ -struct ctl_table *entry; - -/* -* In the intermediate directories, both the child directory and -* procname are dynamically allocated and could fail but the mode -* will always be set. In the lowest directory the names are -* static strings and all have proc handlers. -*/ -for (entry = *tablep; entry->mode; entry++) { -if (entry->child) -sd_free_ctl_entry (&entry->child); -if (entry->proc_handler ==NULL ) -kfree (entry->procname); - } - -kfree (*tablep); - *tablep =NULL ; -} - -static int min_load_idx =0 ; -static int max_load_idx =CPU_LOAD_IDX_MAX -1 ; - -static void -set_table_entry (struct ctl_table *entry, -const char *procname,void *data,int maxlen, -umode_t mode,proc_handler *proc_handler, -bool load_idx) -{ - entry->procname = procname; - entry->data = data; - entry->maxlen = maxlen; - entry->mode = mode; - entry->proc_handler = proc_handler; - -if (load_idx) { - entry->extra1 = &min_load_idx; - entry->extra2 = &max_load_idx; - } -} - -static struct ctl_table * -sd_alloc_ctl_domain_table (struct sched_domain *sd) -{ -struct ctl_table *table =sd_alloc_ctl_entry (14 ); - -if (table ==NULL ) -return NULL ; - -set_table_entry (&table[0 ],"min_interval" , &sd->min_interval, -sizeof (long ),0644 , proc_doulongvec_minmax, false); -set_table_entry (&table[1 ],"max_interval" , &sd->max_interval, -sizeof (long ),0644 , proc_doulongvec_minmax, false); -set_table_entry (&table[2 ],"busy_idx" , &sd->busy_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[3 ],"idle_idx" , &sd->idle_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[4 ],"newidle_idx" , &sd->newidle_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[5 ],"wake_idx" , &sd->wake_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[6 ],"forkexec_idx" , &sd->forkexec_idx, -sizeof (int ),0644 , proc_dointvec_minmax, true); -set_table_entry (&table[7 ],"busy_factor" , &sd->busy_factor, -sizeof (int ),0644 , proc_dointvec_minmax, false); -set_table_entry (&table[8 ],"imbalance_pct" , &sd->imbalance_pct, -sizeof (int ),0644 , proc_dointvec_minmax, false); -set_table_entry (&table[9 ],"cache_nice_tries" , - &sd->cache_nice_tries, -sizeof (int ),0644 , proc_dointvec_minmax, false); -set_table_entry (&table[10 ],"flags" , &sd->flags, -sizeof (int ),0644 , proc_dointvec_minmax, false); -set_table_entry (&table[11 ],"max_newidle_lb_cost" , - &sd->max_newidle_lb_cost, -sizeof (long ),0644 , proc_doulongvec_minmax, false); -set_table_entry (&table[12 ],"name" , sd->name, -CORENAME_MAX_SIZE ,0444 , proc_dostring, false); -/* &table[13] 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 =sd_alloc_ctl_entry (domain_num +1 ); -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 struct ctl_table_header *sd_sysctl_header; -static void register_sched_domain_sysctl (void ) -{ -int i, cpu_num =num_possible_cpus (); -struct ctl_table *entry =sd_alloc_ctl_entry (cpu_num +1 ); -char buf[32 ]; - -WARN_ON (sd_ctl_dir[0 ].child); - sd_ctl_dir[0 ].child = entry; - -if (entry ==NULL ) -return ; - -for_each_possible_cpu (i) { -snprintf (buf,32 ,"cpu%d" , i); - entry->procname =kstrdup (buf,GFP_KERNEL ); - entry->mode =0555 ; - entry->child =sd_alloc_ctl_cpu_table (i); - entry++; - } - -WARN_ON (sd_sysctl_header); - sd_sysctl_header =register_sysctl_table (sd_ctl_root); -} - -/* may be called multiple times per register */ -static void unregister_sched_domain_sysctl (void ) -{ -unregister_sysctl_table (sd_sysctl_header); - sd_sysctl_header =NULL ; -if (sd_ctl_dir[0 ].child) -sd_free_ctl_entry (&sd_ctl_dir[0 ].child); -} -#else -static void register_sched_domain_sysctl (void ) -{ -} -static void unregister_sched_domain_sysctl (void ) -{ -} -#endif /* CONFIG_SCHED_DEBUG && CONFIG_SYSCTL */ -static void set_rq_online (struct rq *rq) {if (!rq->online) {
kernel/sched/debug.c +173 -0
179 lines not on this page · raw message
kernel/sched/sched.h +13 -0
@@ -3,6 +3,7 @@#include <linux/sched/sysctl.h> #include <linux/sched/rt.h> #include <linux/sched/deadline.h> +#include <linux/binfmts.h> #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/stop_machine.h>
@@ -908,6 +909,18 @@ static inline unsigned int group_first_cpu(struct sched_group *group)extern int group_balance_cpu (struct sched_group *sg); +#if defined(CONFIG_SCHED_DEBUG ) && defined(CONFIG_SYSCTL ) +void register_sched_domain_sysctl (void ); +void unregister_sched_domain_sysctl (void ); +#else +static inline void register_sched_domain_sysctl (void ) +{ +} +static inline void unregister_sched_domain_sysctl (void ) +{ +} +#endif +#else static inline void sched_ttwu_pending (void ) { }
Steven Rostedt
maintainerPATCH 3/4 sched: Add bandwidth ratio to /proc/sched_debug
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Playing with SCHED_DEADLINE and cpusets, I found that I was unable to create new SCHED_DEADLINE tasks, with the error of EBUSY as if the bandwidth was already used up. I then realized there wa no way to see what bandwidth is used by the runqueues to debug the issue.
By adding the dl_bw->bw and dl_bw->total_bw to the output of the deadline info in /proc/sched_debug, this allows us to see what bandwidth has been reserved and where a problem may exist.
For example, before the issue we see the ratio of the bandwidth:
# cat /proc/sys/kernel/sched_rt_runtime_us 950000 # cat /proc/sys/kernel/sched_rt_period_us 1000000
# grep dl /proc/sched_debug
dl_rq[0]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[1]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[2]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[3]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[4]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[5]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[6]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[7]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0Note: (950000 / 1000000) << 20 == 996147
After I played with cpusets and hit the issue, the result is now:
# grep dl /proc/sched_debug
dl_rq[0]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857
dl_rq[1]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 104857
dl_rq[2]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 104857
dl_rq[3]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 104857
dl_rq[4]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857
dl_rq[5]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857
dl_rq[6]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857
dl_rq[7]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857This shows that there is definitely a problem as we should never have a negative total bandwidth.
--- kernel/sched/debug.c | 9 +++++++++ 1 file changed, 9 insertions(+)
kernel/sched/debug.c +9 -0
@@ -562,8 +562,17 @@ void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)void print_dl_rq (struct seq_file *m,int cpu,struct dl_rq *dl_rq) { +struct dl_bw *dl_bw; +SEQ_printf (m,"\ndl_rq[%d]:\n" , cpu);SEQ_printf (m," .%-30s: %ld\n" ,"dl_nr_running" , dl_rq->dl_nr_running); +#ifdef CONFIG_SMP + dl_bw = &cpu_rq (cpu)->rd->dl_bw; +#else + dl_bw = &dl_rq->dl_bw; +#endif +SEQ_printf (m," .%-30s: %lld\n" ,"dl_bw->bw" , dl_bw->bw); +SEQ_printf (m," .%-30s: %lld\n" ,"dl_bw->total_bw" , dl_bw->total_bw); }extern __read_mostly int sched_clock_running;
Signature · 1 line
2.6.4
Re: [PATCH 3/4] sched: Add bandwidth ratio to /proc/sched_debug
Hi Steve,
Quoted 11 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Playing with
SCHED_DEADLINEand cpusets, I found that I was unable to create newSCHED_DEADLINEtasks, with the error of EBUSY as if the bandwidth was already used up. I then realized there wa no way to see what bandwidth is used by the runqueues to debug the issue.By adding the
dl_bw->bwanddl_bw->total_bwto the output of the deadline info in/proc/sched_debug, this allows us to see what bandwidth has been reserved and where a problem may exist.
[...]
Quoted 2 lines
Signed-off-by Steven Rostedt <[email protected]>
This is pretty useful yes.
FWIW,
Best,
- Juri
tip-bot for Steven Rostedt (Red Hat)
merge bot[tip:sched/core] sched/debug: Add deadline scheduler bandwidth ratio to /proc/sched_debug
In reply to Steven Rostedtsched/debug: Add deadline scheduler bandwidth ratio to /proc/sched_debug
Commit-ID: ef477183d06b0aa41c9e7c02cf5bfec41536e2c4 Gitweb: http://git.kernel.org/tip/ef477183d06b0aa41c9e7c02cf5bfec41536e2c4 Author: Steven Rostedt (Red Hat) <[email protected]> AuthorDate: Mon, 22 Feb 2016 16:26:52 -0500 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 29 Feb 2016 09:53:07 +0100
sched/debug: Add deadline scheduler bandwidth ratio to /proc/sched_debug
Playing with SCHED_DEADLINE and cpusets, I found that I was unable to create new SCHED_DEADLINE tasks, with the error of EBUSY as if the bandwidth was already used up. I then realized there wa no way to see what bandwidth is used by the runqueues to debug the issue.
By adding the dl_bw->bw and dl_bw->total_bw to the output of the deadline info in /proc/sched_debug, this allows us to see what bandwidth has been reserved and where a problem may exist.
For example, before the issue we see the ratio of the bandwidth:
# cat /proc/sys/kernel/sched_rt_runtime_us 950000 # cat /proc/sys/kernel/sched_rt_period_us 1000000
# grep dl /proc/sched_debug
dl_rq[0]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[1]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[2]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[3]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[4]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[5]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[6]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0
dl_rq[7]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 0Note: (950000 / 1000000) << 20 == 996147
After I played with cpusets and hit the issue, the result is now:
# grep dl /proc/sched_debug
dl_rq[0]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857
dl_rq[1]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 104857
dl_rq[2]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 104857
dl_rq[3]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : 104857
dl_rq[4]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857
dl_rq[5]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857
dl_rq[6]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857
dl_rq[7]:
.dl_nr_running : 0
.dl_bw->bw : 996147
.dl_bw->total_bw : -104857This shows that there is definitely a problem as we should never have a negative total bandwidth.
--- kernel/sched/debug.c | 9 +++++++++ 1 file changed, 9 insertions(+)
kernel/sched/debug.c +9 -0
@@ -566,8 +566,17 @@ void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)void print_dl_rq (struct seq_file *m,int cpu,struct dl_rq *dl_rq) { +struct dl_bw *dl_bw; +SEQ_printf (m,"\ndl_rq[%d]:\n" , cpu);SEQ_printf (m," .%-30s: %ld\n" ,"dl_nr_running" , dl_rq->dl_nr_running); +#ifdef CONFIG_SMP + dl_bw = &cpu_rq (cpu)->rd->dl_bw; +#else + dl_bw = &dl_rq->dl_bw; +#endif +SEQ_printf (m," .%-30s: %lld\n" ,"dl_bw->bw" , dl_bw->bw); +SEQ_printf (m," .%-30s: %lld\n" ,"dl_bw->total_bw" , dl_bw->total_bw); }extern __read_mostly int sched_clock_running;
Steven Rostedt
maintainerPATCH 4/4 tracing: Add __print_ns_to_secs() and __print_ns_without_secs() helpers
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
To have nanosecond output displayed in a more human readable format, its nicer to convert it to a seconds format (XXX.YYYYYYYYY). The problem is that to do so, the numbers must be divided by NSEC_PER_SEC, and moded too. But as these numbers are 64 bit, this can not be done simply with '/' and '%' operators, but must use do_div() instead.
Instead of performing the expensive do_div() in the hot path of the tracepoint, it is more efficient to perform it during the output phase. But passing in do_div() can confuse the parser, and do_div() doesn't work exactly like a normal C function. It modifies the number in place, and we don't want to modify the actual values in the ring buffer.
Two helper functions are now created:
__print_ns_to_secs() and __print_ns_without_secs()
They both take a value of nanoseconds, and the former will return that number divided by NSEC_PER_SEC, and the latter will mod it with NSEC_PER_SEC giving a way to print a nice human readable format:
__print_fmt("time=%llu.%09u",
__print_ns_to_secs(REC->nsec_val), __print_ns_without_secs(REC->nsec_val))
--- include/trace/trace_events.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
include/trace/trace_events.h +25 -0
@@ -283,6 +283,21 @@ TRACE_MAKE_SYSTEM_STR();trace_print_symbols_seq (p, value, symbols); \ }) +#undef __print_ns_to_secs +#define __print_ns_to_secs (value) \ + ({ \ + u64 ____val = (u64)value; \ + do_div(____val, NSEC_PER_SEC); \ + ____val; \ + }) + +#undef __print_ns_without_secs +#define __print_ns_without_secs (value) \ + ({ \ + u64 ____val = (u64)value; \ + do_div(____val, NSEC_PER_SEC); \ + }) +#undef __print_symbolic_u64#if BITS_PER_LONG ==32 #define __print_symbolic_u64(value, symbol_array...) \
@@ -720,6 +735,16 @@ static inline void ftrace_test_probe_##call(void) \#undef __get_bitmask#undef __print_array +/* +* The below is not executed in the kernel. It is only what is +* displayed in the print format for userspace to parse. +*/ +#undef __print_ns_to_secs +#define __print_ns_to_secs (val) val / 1000000000UL + +#undef __print_ns_without_secs +#define __print_ns_without_secs (val) val % 1000000000UL +#undef TP_printk #define TP_printk(fmt, args...) "\"" fmt "\", " __stringify(args)
Signature · 1 line
2.6.4
Peter Zijlstra
maintainerRe: [PATCH 4/4] tracing: Add __print_ns_to_secs() and __print_ns_without_secs() helpers
Quoted 7 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
To have nanosecond output displayed in a more human readable format, its nicer to convert it to a seconds format (XXX.YYYYYYYYY). The problem is that to do so, the numbers must be divided by
NSEC_PER_SEC, and moded too. But as these numbers are 64 bit, this can not be done simply with '/' and '%' operators, but must usedo_div()instead.
Would not div_[us]64_rem() make more sense? It would typically result in just the one division, instead of two.
Steven Rostedt
maintainerRe: [PATCH 4/4] tracing: Add __print_ns_to_secs() and __print_ns_without_secs() helpers
Quoted 11 lines · On Tue, 23 Feb 2016 13:49:15 +0100 Peter Zijlstra <[email protected]> wrote:
Quoted 7 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
To have nanosecond output displayed in a more human readable format, its nicer to convert it to a seconds format (XXX.YYYYYYYYY). The problem is that to do so, the numbers must be divided by
NSEC_PER_SEC, and moded too. But as these numbers are 64 bit, this can not be done simply with '/' and '%' operators, but must usedo_div()instead.Would not div_[us]64_rem() make more sense? It would typically result in just the one division, instead of two.
The problem is, how do you do that in a printf() statement?
We have "%llu.%09ul" which is two arguments in the printf(). And the values we are processing can't be modified. Which is why the macro uses ({ }) and creates a temp variable.
-- Steve
Peter Zijlstra
maintainerRe: [PATCH 4/4] tracing: Add __print_ns_to_secs() and __print_ns_without_secs() helpers
Quoted 12 lines · Steven Rostedt
Quoted 9 lines · On Tue, 23 Feb 2016 13:49:15 +0100 Peter Zijlstra <[email protected]> wrote:
Quoted 7 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
To have nanosecond output displayed in a more human readable format, its nicer to convert it to a seconds format (XXX.YYYYYYYYY). The problem is that to do so, the numbers must be divided by
NSEC_PER_SEC, and moded too. But as these numbers are 64 bit, this can not be done simply with '/' and '%' operators, but must usedo_div()instead.
Quoted 8 lines
Quoted 2 lines
Would not div_[us]64_rem() make more sense? It would typically result in just the one division, instead of two.
The problem is, how do you do that in a
printf()statement?We have "%llu.%09ul" which is two arguments in the
printf(). And the values we are processing can't be modified. Which is why the macro uses ({ }) and creates a temp variable.
Hurm,. yes that's not something easily done. We need a temporary limited in scope to the printf statement, and C doesn't really do that.
Steven Rostedt
maintainerRe: [PATCH 4/4] tracing: Add __print_ns_to_secs() and __print_ns_without_secs() helpers
Quoted 6 lines · On Tue, 23 Feb 2016 15:01:43 +0100 Peter Zijlstra <[email protected]> wrote:
Quoted 3 lines
We have "%llu.%09ul" which is two arguments in the
printf(). And the values we are processing can't be modified. Which is why the macro uses ({ }) and creates a temp variable.Hurm,. yes that's not something easily done. We need a temporary limited in scope to the printf statement, and C doesn't really do that.
The nice thing is, the division is done on output, which is considered the slow path. Having two divisions instead of just one may be inconvenient, but it's not slowing much down. And that's only performed when reading the ASCII trace files. If you use perf or trace-cmd, the event-parser will do the work for you at post processing.
-- Steve