Add CPU state for iopoll
Subsystems (4)
Hi everyone,
I'm just submitting to storage lists to see if anyone else thinks this is useful.
Linux kernel 4.4 adds a new block mode to poll IO for low-latency storage. When not polling, we can see CPU time spent in system vs. in iowait. For example, 'mpstat' may show:
CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
0 0.00 0.00 40.96 59.04 0.00 0.00 0.00 0.00 0.00and that's useful to see the iowait, and, when combined with other data, indicates how the h/w is performing. If we've enabled IO polling, though, we get something like this:
CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
0 0.00 0.00 100.00 0.00 0.00 0.00 0.00 0.00 0.00Which is pretty useless for gaining insights on how the h/w is doing. Right now I use 'perf record' to measure where CPU cycles are spent, but that's not always feasible or convenient.
The following series proposes a new CPU state called "iopoll" so we can get similarly useful information. The result looks like this:
CPU %usr %nice %sys %iowait %iopoll %irq %soft %steal %guest %gnice %idle
0 1.00 0.00 34.00 0.00 65.00 0.00 0.00 0.00 0.00 0.00 0.00
The first patch is the kernel part. The second is for sysstat. I might be concerned about the potential for breaking older stats tools...
Thanks!
Keith Busch (1):
CPU: New state for iopoll
block/blk-core.c | 7 ++++++- fs/proc/stat.c | 8 ++++++-- include/linux/kernel_stat.h | 1 + include/linux/sched.h | 1 + kernel/sched/cpuacct.c | 1 + kernel/sched/cputime.c | 7 ++++++- 6 files changed, 21 insertions(+), 4 deletions(-)
Keith Busch (1):
sysstat: Report iopoll CPU percentage
common.c | 4 ++-- iostat.c | 10 ++++++---- mpstat.c | 18 ++++++++++++------ rd_stats.c | 10 ++++++---- rd_stats.h | 1 + 5 files changed, 27 insertions(+), 16 deletions(-)
Signature · 1 line
2.6.2.307.g37023ba
RFC 1/1 CPU: New state for iopoll
This accounts for CPU time spent polling for IO seperately from system time.
--- block/blk-core.c | 7 ++++++- fs/proc/stat.c | 8 ++++++-- include/linux/kernel_stat.h | 1 + include/linux/sched.h | 1 + kernel/sched/cpuacct.c | 1 + kernel/sched/cputime.c | 7 ++++++- 6 files changed, 21 insertions(+), 4 deletions(-)
block/blk-core.c +6 -1
@@ -3330,6 +3330,7 @@ bool blk_poll(struct request_queue *q, blk_qc_t cookie)if (plug)blk_flush_plug_list (plug, false); + current->in_iopoll =1 ; state = current->state;while (!need_resched ()) {unsigned int queue_num =blk_qc_t_to_queue_num (cookie);
@@ -3342,19 +3343,23 @@ bool blk_poll(struct request_queue *q, blk_qc_t cookie)if (ret >0 ) { hctx->poll_success++;set_current_state (TASK_RUNNING ); + current->in_iopoll =0 ;return true; }if (signal_pending_state (state, current))set_current_state (TASK_RUNNING ); -if (current->state ==TASK_RUNNING ) +if (current->state ==TASK_RUNNING ) { + current->in_iopoll =0 ;return true; + }if (ret <0 )break ;cpu_relax (); } + current->in_iopoll =0 ;return false; }
fs/proc/stat.c +6 -2
@@ -81,14 +81,14 @@ static int show_stat(struct seq_file *p, void *v) {int i, j;unsigned long jif; -u64 user, nice, system, idle, iowait, irq, softirq, steal; +u64 user, nice, system, idle, iowait, iopoll, irq, softirq, steal;u64 guest, guest_nice;u64 sum =0 ;u64 sum_softirq =0 ;unsigned int per_softirq_sums[NR_SOFTIRQS ] = {0 };struct timespec boottime; - user = nice = system = idle = iowait = + user = nice = system = idle = iowait = iopoll = irq = softirq = steal =0 ; guest = guest_nice =0 ;getboottime (&boottime);
@@ -98,6 +98,7 @@ static int show_stat(struct seq_file *p, void *v) user +=kcpustat_cpu (i).cpustat[CPUTIME_USER ]; nice +=kcpustat_cpu (i).cpustat[CPUTIME_NICE ]; system +=kcpustat_cpu (i).cpustat[CPUTIME_SYSTEM ]; + iopoll +=kcpustat_cpu (i).cpustat[CPUTIME_IOPOLL ]; idle +=get_idle_time (i); iowait +=get_iowait_time (i); irq +=kcpustat_cpu (i).cpustat[CPUTIME_IRQ ];
@@ -128,6 +129,7 @@ static int show_stat(struct seq_file *p, void *v)seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (steal));seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (guest));seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (guest_nice)); +seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (iopoll));seq_putc (p,'\n' );for_each_online_cpu (i) {
@@ -135,6 +137,7 @@ static int show_stat(struct seq_file *p, void *v) user =kcpustat_cpu (i).cpustat[CPUTIME_USER ]; nice =kcpustat_cpu (i).cpustat[CPUTIME_NICE ]; system =kcpustat_cpu (i).cpustat[CPUTIME_SYSTEM ]; + iopoll =kcpustat_cpu (i).cpustat[CPUTIME_IOPOLL ]; idle =get_idle_time (i); iowait =get_iowait_time (i); irq =kcpustat_cpu (i).cpustat[CPUTIME_IRQ ];
@@ -153,6 +156,7 @@ static int show_stat(struct seq_file *p, void *v)seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (steal));seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (guest));seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (guest_nice)); +seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (iopoll));seq_putc (p,'\n' ); }seq_printf (p,"intr %llu" , (unsigned long long )sum);
include/linux/kernel_stat.h +1 -0
@@ -28,6 +28,7 @@ enum cpu_usage_stat {CPUTIME_STEAL ,CPUTIME_GUEST ,CPUTIME_GUEST_NICE , +CPUTIME_IOPOLL , NR_STATS, };
include/linux/sched.h +1 -0
@@ -1458,6 +1458,7 @@ struct task_struct { unsigned in_execve:1; /* Tell the LSMs that the process is doing an* execve */ unsigned in_iowait:1; + unsigned in_iopoll:1;/* Revert to default priority/policy when forking */ unsigned sched_reset_on_fork:1;
kernel/sched/cpuacct.c +1 -0
@@ -200,6 +200,7 @@ static int cpuacct_stats_show(struct seq_file *sf, void *v)for_each_online_cpu (cpu) {struct kernel_cpustat *kcpustat =per_cpu_ptr (ca->cpustat, cpu); val += kcpustat->cpustat[CPUTIME_SYSTEM ]; + val += kcpustat->cpustat[CPUTIME_IOPOLL ]; val += kcpustat->cpustat[CPUTIME_IRQ ]; val += kcpustat->cpustat[CPUTIME_SOFTIRQ ]; }
kernel/sched/cputime.c +6 -1
@@ -222,6 +222,8 @@ void account_system_time(struct task_struct *p, int hardirq_offset, index =CPUTIME_IRQ ; else if (in_serving_softirq()) index =CPUTIME_SOFTIRQ ; + else if (p->in_iopoll) + index =CPUTIME_IOPOLL ; else index =CPUTIME_SYSTEM ;
@@ -367,7 +369,10 @@ static void irqtime_account_process_tick(struct task_struct *p, int user_tick, }else if (p->flags &PF_VCPU ) {/* System time or guest time */ account_guest_time (p, cputime, scaled); }else { -__account_system_time (p, cputime, scaled,CPUTIME_SYSTEM ); +if (p->in_iopoll) +__account_system_time (p, cputime, scaled,CPUTIME_IOPOLL ); +else +__account_system_time (p, cputime, scaled,CPUTIME_SYSTEM ); } }
Signature · 1 line
2.6.2.307.g37023ba
[RFC] CPU: New state for iopoll
This is really goods do helpful, thanks Keith
Sent from my iPhone
Quoted 174 lines · Keith Busch
This accounts for CPU time spent polling for IO seperately from system time.
Signed-off-by Keith Busch <keith.busch at intel.com>---
block/blk-core.c | 7 ++++++- fs/proc/stat.c | 8 ++++++-- include/linux/kernel_stat.h | 1 + include/linux/sched.h | 1 + kernel/sched/cpuacct.c | 1 + kernel/sched/cputime.c | 7 ++++++- 6 files changed, 21 insertions(+), 4 deletions(-)block/blk-core.c +6
-1@@ -3330,6 +3330,7 @@ bool blk_poll(struct request_queue *q, blk_qc_t cookie)if (plug)blk_flush_plug_list (plug, false); + current->in_iopoll =1 ; state = current->state;while (!need_resched ()) {unsigned int queue_num =blk_qc_t_to_queue_num (cookie);@@ -3342,19 +3343,23 @@ bool blk_poll(struct request_queue *q, blk_qc_t cookie)if (ret >0 ) { hctx->poll_success++;set_current_state (TASK_RUNNING ); + current->in_iopoll =0 ;return true; }if (signal_pending_state (state, current))set_current_state (TASK_RUNNING ); -if (current->state ==TASK_RUNNING ) +if (current->state ==TASK_RUNNING ) { + current->in_iopoll =0 ;return true; + }if (ret <0 )break ;cpu_relax (); } + current->in_iopoll =0 ;return false; }fs/proc/stat.c +6
-2@@ -81,14 +81,14 @@ static int show_stat(struct seq_file *p, void *v) {int i, j;unsigned long jif; -u64 user, nice, system, idle, iowait, irq, softirq, steal; +u64 user, nice, system, idle, iowait, iopoll, irq, softirq, steal;u64 guest, guest_nice;u64 sum =0 ;u64 sum_softirq =0 ;unsigned int per_softirq_sums[NR_SOFTIRQS ] = {0 };struct timespec boottime; - user = nice = system = idle = iowait = + user = nice = system = idle = iowait = iopoll = irq = softirq = steal =0 ; guest = guest_nice =0 ;getboottime (&boottime);@@ -98,6 +98,7 @@ static int show_stat(struct seq_file *p, void *v) user +=kcpustat_cpu (i).cpustat[CPUTIME_USER ]; nice +=kcpustat_cpu (i).cpustat[CPUTIME_NICE ]; system +=kcpustat_cpu (i).cpustat[CPUTIME_SYSTEM ]; + iopoll +=kcpustat_cpu (i).cpustat[CPUTIME_IOPOLL ]; idle +=get_idle_time (i); iowait +=get_iowait_time (i); irq +=kcpustat_cpu (i).cpustat[CPUTIME_IRQ ];@@ -128,6 +129,7 @@ static int show_stat(struct seq_file *p, void *v)seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (steal));seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (guest));seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (guest_nice)); +seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (iopoll));seq_putc (p,'\n' );for_each_online_cpu (i) {@@ -135,6 +137,7 @@ static int show_stat(struct seq_file *p, void *v) user =kcpustat_cpu (i).cpustat[CPUTIME_USER ]; nice =kcpustat_cpu (i).cpustat[CPUTIME_NICE ]; system =kcpustat_cpu (i).cpustat[CPUTIME_SYSTEM ]; + iopoll =kcpustat_cpu (i).cpustat[CPUTIME_IOPOLL ]; idle =get_idle_time (i); iowait =get_iowait_time (i); irq =kcpustat_cpu (i).cpustat[CPUTIME_IRQ ];@@ -153,6 +156,7 @@ static int show_stat(struct seq_file *p, void *v)seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (steal));seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (guest));seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (guest_nice)); +seq_put_decimal_ull (p,' ' ,cputime64_to_clock_t (iopoll));seq_putc (p,'\n' ); }seq_printf (p,"intr %llu" , (unsigned long long )sum);include/linux/kernel_stat.h +1
-0@@ -28,6 +28,7 @@ enum cpu_usage_stat {CPUTIME_STEAL ,CPUTIME_GUEST ,CPUTIME_GUEST_NICE , +CPUTIME_IOPOLL , NR_STATS, };include/linux/sched.h +1
-0@@ -1458,6 +1458,7 @@ struct task_struct { unsigned in_execve:1; /* Tell the LSMs that the process is doing an* execve */ unsigned in_iowait:1; + unsigned in_iopoll:1;/* Revert to default priority/policy when forking */ unsigned sched_reset_on_fork:1;kernel/sched/cpuacct.c +1
-0@@ -200,6 +200,7 @@ static int cpuacct_stats_show(struct seq_file *sf, void *v)for_each_online_cpu (cpu) {struct kernel_cpustat *kcpustat =per_cpu_ptr (ca->cpustat, cpu); val += kcpustat->cpustat[CPUTIME_SYSTEM ]; + val += kcpustat->cpustat[CPUTIME_IOPOLL ]; val += kcpustat->cpustat[CPUTIME_IRQ ]; val += kcpustat->cpustat[CPUTIME_SOFTIRQ ]; }kernel/sched/cputime.c +6
-1@@ -222,6 +222,8 @@ void account_system_time(struct task_struct *p, int hardirq_offset, index =CPUTIME_IRQ ; else if (in_serving_softirq()) index =CPUTIME_SOFTIRQ ; + else if (p->in_iopoll) + index =CPUTIME_IOPOLL ; else index =CPUTIME_SYSTEM ;@@ -367,7 +369,10 @@ static void irqtime_account_process_tick(struct task_struct *p, int user_tick, }else if (p->flags &PF_VCPU ) {/* System time or guest time */ account_guest_time (p, cputime, scaled); }else { -__account_system_time (p, cputime, scaled,CPUTIME_SYSTEM ); +if (p->in_iopoll) +__account_system_time (p, cputime, scaled,CPUTIME_IOPOLL ); +else +__account_system_time (p, cputime, scaled,CPUTIME_SYSTEM ); } }Signature · 7 lines
2.6.2.307.g37023ba _______________________________________________ Linux-nvme mailing list Linux-nvme at lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-nvme
RFC 1/1 sysstat: Report iopoll CPU percentage
In reply to Keith Busch--- common.c | 4 ++-- iostat.c | 10 ++++++---- mpstat.c | 18 ++++++++++++------ rd_stats.c | 10 ++++++---- rd_stats.h | 1 + 5 files changed, 27 insertions(+), 16 deletions(-)
common.c +2 -2
@@ -605,11 +605,11 @@ unsigned long long get_per_cpu_interval(struct stats_cpu *scc,* because cpu_user and cpu_nice already include them. */ return ((scc->cpu_user + scc->cpu_nice + - scc->cpu_sys + scc->cpu_iowait + + scc->cpu_sys + scc->cpu_iowait + scc->cpu_iopoll + scc->cpu_idle + scc->cpu_steal + scc->cpu_hardirq + scc->cpu_softirq) - (scp->cpu_user + scp->cpu_nice + - scp->cpu_sys + scp->cpu_iowait + + scp->cpu_sys + scp->cpu_iowait + scp->cpu_iopoll + scp->cpu_idle + scp->cpu_steal + scp->cpu_hardirq + scp->cpu_softirq) + ishift);
iostat.c +6 -4
@@ -824,10 +824,10 @@ void compute_device_groups_stats(int curr)*/ void write_cpu_stat (int curr,unsigned long long itv) { -printf ("avg-cpu: %%user %%nice %%system %%iowait %%steal %%idle\n" ); +printf ("avg-cpu: %%user %%nice %%system %%iowait %%iopoll %%steal %%idle\n" );printf (" " ); - cprintf_pc(6, 7, 2, + cprintf_pc(7, 7, 2, ll_sp_value(st_cpu[!curr]->cpu_user, st_cpu[curr]->cpu_user, itv), ll_sp_value(st_cpu[!curr]->cpu_nice, st_cpu[curr]->cpu_nice, itv),/*
@@ -839,6 +839,7 @@ void write_cpu_stat(int curr, unsigned long long itv) st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_softirq + st_cpu[curr]->cpu_hardirq, itv),ll_sp_value (st_cpu[!curr]->cpu_iowait, st_cpu[curr]->cpu_iowait, itv), +ll_sp_value (st_cpu[!curr]->cpu_iopoll, st_cpu[curr]->cpu_iopoll, itv),ll_sp_value (st_cpu[!curr]->cpu_steal, st_cpu[curr]->cpu_steal, itv), (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ? 0.0 :
@@ -1088,7 +1089,7 @@ void write_stats(int curr, struct tm *rectime) fprintf(stderr, "itv=%llu st_cpu[curr]{ cpu_user=%llu cpu_nice=%llu " "cpu_sys=%llu cpu_idle=%llu cpu_iowait=%llu cpu_steal=%llu " "cpu_hardirq=%llu cpu_softirq=%llu cpu_guest=%llu " - "cpu_guest_nice=%llu }\n", + "cpu_guest_nice=%llu cpu_io_poll:%llu}\n", itv, st_cpu[curr]->cpu_user, st_cpu[curr]->cpu_nice,
@@ -1099,7 +1100,8 @@ void write_stats(int curr, struct tm *rectime) st_cpu[curr]->cpu_hardirq, st_cpu[curr]->cpu_softirq, st_cpu[curr]->cpu_guest, - st_cpu[curr]->cpu_guest_nice); + st_cpu[curr]->cpu_guest_nice, + st_cpu[curr]->cpu_iopoll); }#endif
mpstat.c +12 -6
@@ -227,7 +227,7 @@ void write_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,int cpu;if (dis) { -printf ("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq " +printf ("\n%-11s CPU %%usr %%nice %%sys %%iowait %%iopoll %%irq " "%%soft %%steal %%guest %%gnice %%idle\n" , prev_string); }
@@ -238,7 +238,7 @@ void write_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,printf ("%-11s" , curr_string);cprintf_in (IS_STR ," %s" ," all" ,0 ); - cprintf_pc(10, 7, 2, + cprintf_pc(11, 7, 2, (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) < (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ? 0.0 :
@@ -257,6 +257,9 @@ void write_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,ll_sp_value (st_cpu[prev]->cpu_iowait, st_cpu[curr]->cpu_iowait, g_itv), +ll_sp_value (st_cpu[prev]->cpu_iopoll, + st_cpu[curr]->cpu_iopoll, + g_itv),ll_sp_value (st_cpu[prev]->cpu_hardirq, st_cpu[curr]->cpu_hardirq, g_itv),
@@ -302,8 +305,8 @@ void write_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,if (!DISPLAY_ONLINE_CPU (flags)) {printf ("%-11s" , curr_string);cprintf_in (IS_INT ," %4d" ,"" , cpu -1 ); -cprintf_pc (10 ,7 ,2 , -0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ); +cprintf_pc (11 ,7 ,2 , +0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 );printf ("\n" ); }continue ;
@@ -320,13 +323,13 @@ void write_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,* If the CPU is tickless then there is no change in CPU values * but the sum of values is not zero. */ -cprintf_pc (10 ,7 ,2 , +cprintf_pc (11 ,7 ,2 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,0.0 ,100.0 );printf ("\n" ); } else { - cprintf_pc(10, 7, 2, + cprintf_pc(11, 7, 2, (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ? 0.0 : ll_sp_value(scp->cpu_user - scp->cpu_guest,
@@ -343,6 +346,9 @@ void write_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,ll_sp_value (scp->cpu_iowait, scc->cpu_iowait, pc_itv), +ll_sp_value (scp->cpu_iopoll, + scc->cpu_iopoll, + pc_itv),ll_sp_value (scp->cpu_hardirq, scc->cpu_hardirq, pc_itv),
rd_stats.c +6 -4
@@ -85,7 +85,7 @@ void read_stat_cpu(struct stats_cpu *st_cpu, int nbr,* (user, nice, etc.) among all proc. CPU usage is not reduced * to one processor to avoid rounding problems. */ - sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", + sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", &st_cpu->cpu_user, &st_cpu->cpu_nice, &st_cpu->cpu_sys,
@@ -95,7 +95,8 @@ void read_stat_cpu(struct stats_cpu *st_cpu, int nbr, &st_cpu->cpu_softirq, &st_cpu->cpu_steal, &st_cpu->cpu_guest, - &st_cpu->cpu_guest_nice); + &st_cpu->cpu_guest_nice, + &st_cpu->cpu_iopoll);/* * Compute the uptime of the system in jiffies (1/100ths of a second
@@ -120,7 +121,7 @@ void read_stat_cpu(struct stats_cpu *st_cpu, int nbr,* (user, nice, etc) for current proc. * This is done only on SMP machines. */ - sscanf(line + 3, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", + sscanf(line + 3, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", &proc_nb, &sc.cpu_user, &sc.cpu_nice,
@@ -131,7 +132,8 @@ void read_stat_cpu(struct stats_cpu *st_cpu, int nbr, &sc.cpu_softirq, &sc.cpu_steal, &sc.cpu_guest, - &sc.cpu_guest_nice); + &sc.cpu_guest_nice, + &sc.cpu_iopoll);if (proc_nb < (nbr -1 )) { st_cpu_i = st_cpu + proc_nb +1 ;
rd_stats.h +1 -0
@@ -88,6 +88,7 @@ struct stats_cpu { unsigned long long cpu_sys __attribute__ ((aligned (16))); unsigned long long cpu_idle __attribute__ ((aligned (16))); unsigned long long cpu_iowait __attribute__ ((aligned (16))); + unsigned long long cpu_iopoll __attribute__ ((aligned (16))); unsigned long long cpu_steal __attribute__ ((aligned (16))); unsigned long long cpu_hardirq __attribute__ ((aligned (16))); unsigned long long cpu_softirq __attribute__ ((aligned (16)));
Signature · 1 line
2.6.2.307.g37023ba