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 08:24:10 +03:00
# include <linux/irqnr.h>
2014-03-05 19:33:42 +04:00
# include <linux/cputime.h>
2011-08-24 11:40:25 +04: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 14:23:08 +04: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 20:45:17 +04:00
static u64 get_idle_time ( int cpu )
2011-08-24 11:40:25 +04:00
{
2012-10-10 10:21:09 +04:00
u64 idle , idle_time = - 1ULL ;
if ( cpu_online ( cpu ) )
idle_time = get_cpu_idle_time_us ( cpu , NULL ) ;
2011-08-24 11:40:25 +04:00
2012-03-30 14:23:08 +04:00
if ( idle_time = = - 1ULL )
2012-10-10 10:21:09 +04:00
/* !NO_HZ or cpu offline so we can rely on cpustat.idle */
2011-11-28 20:45:17 +04:00
idle = kcpustat_cpu ( cpu ) . cpustat [ CPUTIME_IDLE ] ;
2012-03-30 14:23:08 +04:00
else
2011-12-29 03:57:15 +04:00
idle = usecs_to_cputime64 ( idle_time ) ;
2011-08-24 11:40:25 +04:00
return idle ;
}
2011-11-28 20:45:17 +04:00
static u64 get_iowait_time ( int cpu )
2011-08-24 11:40:25 +04:00
{
2012-10-10 10:21:09 +04:00
u64 iowait , iowait_time = - 1ULL ;
if ( cpu_online ( cpu ) )
iowait_time = get_cpu_iowait_time_us ( cpu , NULL ) ;
2011-08-24 11:40:25 +04:00
if ( iowait_time = = - 1ULL )
2012-10-10 10:21:09 +04:00
/* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
2011-11-28 20:45:17 +04:00
iowait = kcpustat_cpu ( cpu ) . cpustat [ CPUTIME_IOWAIT ] ;
2011-08-24 11:40:25 +04:00
else
2011-12-29 03:57:15 +04:00
iowait = usecs_to_cputime64 ( iowait_time ) ;
2011-08-24 11:40:25 +04:00
return iowait ;
}
2012-03-30 14:23:08 +04:00
# endif
2008-10-05 00:01:56 +04:00
static int show_stat ( struct seq_file * p , void * v )
{
int i , j ;
unsigned long jif ;
2011-11-28 20:45:17 +04: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-18 03:25:55 +04:00
u64 sum_softirq = 0 ;
unsigned int per_softirq_sums [ NR_SOFTIRQS ] = { 0 } ;
2008-10-05 00:01:56 +04:00
struct timespec boottime ;
user = nice = system = idle = iowait =
2011-11-28 20:45:17 +04:00
irq = softirq = steal = 0 ;
guest = guest_nice = 0 ;
2008-10-05 00:01:56 +04:00
getboottime ( & boottime ) ;
jif = boottime . tv_sec ;
for_each_possible_cpu ( i ) {
2011-11-28 20:45:17 +04: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 04:01:01 +04:00
sum + = kstat_cpu_irqs_sum ( i ) ;
sum + = arch_irq_stat_cpu ( i ) ;
2009-06-18 03:25:55 +04: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 ( ) ;
2012-03-24 02:02:54 +04:00
seq_puts ( p , " cpu " ) ;
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 ) ) ;
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 20:45:17 +04: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 11:40:25 +04:00
idle = get_idle_time ( i ) ;
iowait = get_iowait_time ( i ) ;
2011-11-28 20:45:17 +04: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-24 02:02:54 +04:00
seq_printf ( p , " cpu%d " , i ) ;
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 ) ) ;
seq_putc ( p , ' \n ' ) ;
2008-10-05 00:01:56 +04:00
}
seq_printf ( p , " intr %llu " , ( unsigned long long ) sum ) ;
/* sum again ? it could be updated? */
2010-10-28 02:34:15 +04:00
for_each_irq_nr ( j )
2012-03-24 02:02:54 +04:00
seq_put_decimal_ull ( p , ' ' , kstat_irqs ( j ) ) ;
2008-10-05 00:01:56 +04:00
seq_printf ( p ,
" \n ctxt %llu \n "
" btime %lu \n "
" processes %lu \n "
" procs_running %lu \n "
" procs_blocked %lu \n " ,
nr_context_switches ( ) ,
( unsigned long ) jif ,
total_forks ,
nr_running ( ) ,
nr_iowait ( ) ) ;
2009-06-18 03:25:55 +04:00
seq_printf ( p , " softirq %llu " , ( unsigned long long ) sum_softirq ) ;
for ( i = 0 ; i < NR_SOFTIRQS ; i + + )
2012-03-24 02:02:54 +04:00
seq_put_decimal_ull ( p , ' ' , per_softirq_sums [ i ] ) ;
2011-01-13 04:00:32 +03:00
seq_putc ( p , ' \n ' ) ;
2009-06-18 03:25:55 +04:00
2008-10-05 00:01:56 +04:00
return 0 ;
}
static int stat_open ( struct inode * inode , struct file * file )
{
2013-01-10 23:14:17 +04:00
size_t size = 1024 + 128 * num_possible_cpus ( ) ;
2008-10-05 00:01:56 +04:00
char * buf ;
struct seq_file * m ;
int res ;
2012-03-24 02:02:53 +04:00
/* minimum size to display an interrupt count : 2 bytes */
size + = 2 * nr_irqs ;
2011-05-27 03:25:51 +04:00
/* don't ask for more than the kmalloc() max size */
if ( size > KMALLOC_MAX_SIZE )
size = KMALLOC_MAX_SIZE ;
2008-10-05 00:01:56 +04:00
buf = kmalloc ( size , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
res = single_open ( file , show_stat , NULL ) ;
if ( ! res ) {
m = file - > private_data ;
m - > buf = buf ;
2012-03-24 02:02:53 +04:00
m - > size = ksize ( buf ) ;
2008-10-05 00:01:56 +04:00
} else
kfree ( buf ) ;
return res ;
}
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-24 03:55:45 +04:00
fs_initcall ( proc_stat_init ) ;