2008-10-05 00:01:56 +04:00
# include <linux/cpumask.h>
# include <linux/fs.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/kernel_stat.h>
# include <linux/proc_fs.h>
# include <linux/sched.h>
# include <linux/seq_file.h>
# include <linux/slab.h>
# include <linux/time.h>
2008-12-26 14:24:10 +09:00
# include <linux/irqnr.h>
2014-03-05 16:33:42 +01:00
# include <linux/cputime.h>
2011-08-24 09:40:25 +02:00
# include <linux/tick.h>
2008-10-05 00:01:56 +04:00
# ifndef arch_irq_stat_cpu
# define arch_irq_stat_cpu(cpu) 0
# endif
# ifndef arch_irq_stat
# define arch_irq_stat() 0
# endif
2012-03-30 12:23:08 +02:00
# ifdef arch_idle_time
static cputime64_t get_idle_time ( int cpu )
{
cputime64_t idle ;
idle = kcpustat_cpu ( cpu ) . cpustat [ CPUTIME_IDLE ] ;
if ( cpu_online ( cpu ) & & ! nr_iowait_cpu ( cpu ) )
idle + = arch_idle_time ( cpu ) ;
return idle ;
}
static cputime64_t get_iowait_time ( int cpu )
{
cputime64_t iowait ;
iowait = kcpustat_cpu ( cpu ) . cpustat [ CPUTIME_IOWAIT ] ;
if ( cpu_online ( cpu ) & & nr_iowait_cpu ( cpu ) )
iowait + = arch_idle_time ( cpu ) ;
return iowait ;
}
# else
2008-10-05 00:01:56 +04:00
2011-11-28 14:45:17 -02:00
static u64 get_idle_time ( int cpu )
2011-08-24 09:40:25 +02:00
{
2012-10-10 11:51:09 +05:30
u64 idle , idle_time = - 1ULL ;
if ( cpu_online ( cpu ) )
idle_time = get_cpu_idle_time_us ( cpu , NULL ) ;
2011-08-24 09:40:25 +02:00
2012-03-30 12:23:08 +02:00
if ( idle_time = = - 1ULL )
2012-10-10 11:51:09 +05:30
/* !NO_HZ or cpu offline so we can rely on cpustat.idle */
2011-11-28 14:45:17 -02:00
idle = kcpustat_cpu ( cpu ) . cpustat [ CPUTIME_IDLE ] ;
2012-03-30 12:23:08 +02:00
else
2011-12-28 15:57:15 -08:00
idle = usecs_to_cputime64 ( idle_time ) ;
2011-08-24 09:40:25 +02:00
return idle ;
}
2011-11-28 14:45:17 -02:00
static u64 get_iowait_time ( int cpu )
2011-08-24 09:40:25 +02:00
{
2012-10-10 11:51:09 +05:30
u64 iowait , iowait_time = - 1ULL ;
if ( cpu_online ( cpu ) )
iowait_time = get_cpu_iowait_time_us ( cpu , NULL ) ;
2011-08-24 09:40:25 +02:00
if ( iowait_time = = - 1ULL )
2012-10-10 11:51:09 +05:30
/* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
2011-11-28 14:45:17 -02:00
iowait = kcpustat_cpu ( cpu ) . cpustat [ CPUTIME_IOWAIT ] ;
2011-08-24 09:40:25 +02:00
else
2011-12-28 15:57:15 -08:00
iowait = usecs_to_cputime64 ( iowait_time ) ;
2011-08-24 09:40:25 +02:00
return iowait ;
}
2012-03-30 12:23:08 +02:00
# endif
2008-10-05 00:01:56 +04:00
static int show_stat ( struct seq_file * p , void * v )
{
int i , j ;
2011-11-28 14:45:17 -02:00
u64 user , nice , system , idle , iowait , irq , softirq , steal ;
u64 guest , guest_nice ;
2008-10-05 00:01:56 +04:00
u64 sum = 0 ;
2009-06-17 16:25:55 -07:00
u64 sum_softirq = 0 ;
unsigned int per_softirq_sums [ NR_SOFTIRQS ] = { 0 } ;
2016-08-02 14:03:22 -07:00
struct timespec64 boottime ;
2008-10-05 00:01:56 +04:00
user = nice = system = idle = iowait =
2011-11-28 14:45:17 -02:00
irq = softirq = steal = 0 ;
guest = guest_nice = 0 ;
2016-08-02 14:03:22 -07:00
getboottime64 ( & boottime ) ;
2008-10-05 00:01:56 +04:00
for_each_possible_cpu ( i ) {
2011-11-28 14:45:17 -02:00
user + = kcpustat_cpu ( i ) . cpustat [ CPUTIME_USER ] ;
nice + = kcpustat_cpu ( i ) . cpustat [ CPUTIME_NICE ] ;
system + = kcpustat_cpu ( i ) . cpustat [ CPUTIME_SYSTEM ] ;
idle + = get_idle_time ( i ) ;
iowait + = get_iowait_time ( i ) ;
irq + = kcpustat_cpu ( i ) . cpustat [ CPUTIME_IRQ ] ;
softirq + = kcpustat_cpu ( i ) . cpustat [ CPUTIME_SOFTIRQ ] ;
steal + = kcpustat_cpu ( i ) . cpustat [ CPUTIME_STEAL ] ;
guest + = kcpustat_cpu ( i ) . cpustat [ CPUTIME_GUEST ] ;
guest_nice + = kcpustat_cpu ( i ) . cpustat [ CPUTIME_GUEST_NICE ] ;
2012-01-14 00:01:01 +00:00
sum + = kstat_cpu_irqs_sum ( i ) ;
sum + = arch_irq_stat_cpu ( i ) ;
2009-06-17 16:25:55 -07:00
for ( j = 0 ; j < NR_SOFTIRQS ; j + + ) {
unsigned int softirq_stat = kstat_softirqs_cpu ( j , i ) ;
per_softirq_sums [ j ] + = softirq_stat ;
sum_softirq + = softirq_stat ;
}
2008-10-05 00:01:56 +04:00
}
sum + = arch_irq_stat ( ) ;
2016-10-07 17:02:20 -07:00
seq_put_decimal_ull ( p , " cpu " , cputime64_to_clock_t ( user ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( nice ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( system ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( idle ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( iowait ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( irq ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( softirq ) ) ;
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 ) ) ;
2012-03-23 15:02:54 -07:00
seq_putc ( p , ' \n ' ) ;
2008-10-05 00:01:56 +04:00
for_each_online_cpu ( i ) {
/* Copy values here to work around gcc-2.95.3, gcc-2.96 */
2011-11-28 14:45:17 -02:00
user = kcpustat_cpu ( i ) . cpustat [ CPUTIME_USER ] ;
nice = kcpustat_cpu ( i ) . cpustat [ CPUTIME_NICE ] ;
system = kcpustat_cpu ( i ) . cpustat [ CPUTIME_SYSTEM ] ;
2011-08-24 09:40:25 +02:00
idle = get_idle_time ( i ) ;
iowait = get_iowait_time ( i ) ;
2011-11-28 14:45:17 -02:00
irq = kcpustat_cpu ( i ) . cpustat [ CPUTIME_IRQ ] ;
softirq = kcpustat_cpu ( i ) . cpustat [ CPUTIME_SOFTIRQ ] ;
steal = kcpustat_cpu ( i ) . cpustat [ CPUTIME_STEAL ] ;
guest = kcpustat_cpu ( i ) . cpustat [ CPUTIME_GUEST ] ;
guest_nice = kcpustat_cpu ( i ) . cpustat [ CPUTIME_GUEST_NICE ] ;
2012-03-23 15:02:54 -07:00
seq_printf ( p , " cpu%d " , i ) ;
2016-10-07 17:02:20 -07:00
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( user ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( nice ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( system ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( idle ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( iowait ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( irq ) ) ;
seq_put_decimal_ull ( p , " " , cputime64_to_clock_t ( softirq ) ) ;
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 ) ) ;
2012-03-23 15:02:54 -07:00
seq_putc ( p , ' \n ' ) ;
2008-10-05 00:01:56 +04:00
}
2016-10-07 17:02:20 -07:00
seq_put_decimal_ull ( p , " intr " , ( unsigned long long ) sum ) ;
2008-10-05 00:01:56 +04:00
/* sum again ? it could be updated? */
2010-10-27 15:34:15 -07:00
for_each_irq_nr ( j )
2016-10-07 17:02:20 -07:00
seq_put_decimal_ull ( p , " " , kstat_irqs_usr ( j ) ) ;
2008-10-05 00:01:56 +04:00
seq_printf ( p ,
" \n ctxt %llu \n "
2016-08-02 14:03:22 -07:00
" btime %llu \n "
2008-10-05 00:01:56 +04:00
" processes %lu \n "
" procs_running %lu \n "
" procs_blocked %lu \n " ,
nr_context_switches ( ) ,
2016-08-02 14:03:22 -07:00
( unsigned long long ) boottime . tv_sec ,
2008-10-05 00:01:56 +04:00
total_forks ,
nr_running ( ) ,
nr_iowait ( ) ) ;
2016-10-07 17:02:20 -07:00
seq_put_decimal_ull ( p , " softirq " , ( unsigned long long ) sum_softirq ) ;
2009-06-17 16:25:55 -07:00
for ( i = 0 ; i < NR_SOFTIRQS ; i + + )
2016-10-07 17:02:20 -07:00
seq_put_decimal_ull ( p , " " , per_softirq_sums [ i ] ) ;
2011-01-12 17:00:32 -08:00
seq_putc ( p , ' \n ' ) ;
2009-06-17 16:25:55 -07:00
2008-10-05 00:01:56 +04:00
return 0 ;
}
static int stat_open ( struct inode * inode , struct file * file )
{
2014-07-02 15:22:37 -07:00
size_t size = 1024 + 128 * num_online_cpus ( ) ;
2008-10-05 00:01:56 +04:00
2012-03-23 15:02:53 -07:00
/* minimum size to display an interrupt count : 2 bytes */
size + = 2 * nr_irqs ;
2014-07-02 15:22:37 -07:00
return single_open_size ( file , show_stat , NULL , size ) ;
2008-10-05 00:01:56 +04:00
}
static const struct file_operations proc_stat_operations = {
. open = stat_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
static int __init proc_stat_init ( void )
{
proc_create ( " stat " , 0 , NULL , & proc_stat_operations ) ;
return 0 ;
}
2014-01-23 15:55:45 -08:00
fs_initcall ( proc_stat_init ) ;