linux/fs/proc/stat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/cpumask.h>
   3#include <linux/fs.h>
   4#include <linux/init.h>
   5#include <linux/interrupt.h>
   6#include <linux/kernel_stat.h>
   7#include <linux/proc_fs.h>
   8#include <linux/sched.h>
   9#include <linux/sched/stat.h>
  10#include <linux/seq_file.h>
  11#include <linux/slab.h>
  12#include <linux/time.h>
  13#include <linux/time_namespace.h>
  14#include <linux/irqnr.h>
  15#include <linux/sched/cputime.h>
  16#include <linux/tick.h>
  17
  18#ifndef arch_irq_stat_cpu
  19#define arch_irq_stat_cpu(cpu) 0
  20#endif
  21#ifndef arch_irq_stat
  22#define arch_irq_stat() 0
  23#endif
  24
  25#ifdef arch_idle_time
  26
  27static u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
  28{
  29        u64 idle;
  30
  31        idle = kcs->cpustat[CPUTIME_IDLE];
  32        if (cpu_online(cpu) && !nr_iowait_cpu(cpu))
  33                idle += arch_idle_time(cpu);
  34        return idle;
  35}
  36
  37static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu)
  38{
  39        u64 iowait;
  40
  41        iowait = kcs->cpustat[CPUTIME_IOWAIT];
  42        if (cpu_online(cpu) && nr_iowait_cpu(cpu))
  43                iowait += arch_idle_time(cpu);
  44        return iowait;
  45}
  46
  47#else
  48
  49static u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
  50{
  51        u64 idle, idle_usecs = -1ULL;
  52
  53        if (cpu_online(cpu))
  54                idle_usecs = get_cpu_idle_time_us(cpu, NULL);
  55
  56        if (idle_usecs == -1ULL)
  57                /* !NO_HZ or cpu offline so we can rely on cpustat.idle */
  58                idle = kcs->cpustat[CPUTIME_IDLE];
  59        else
  60                idle = idle_usecs * NSEC_PER_USEC;
  61
  62        return idle;
  63}
  64
  65static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu)
  66{
  67        u64 iowait, iowait_usecs = -1ULL;
  68
  69        if (cpu_online(cpu))
  70                iowait_usecs = get_cpu_iowait_time_us(cpu, NULL);
  71
  72        if (iowait_usecs == -1ULL)
  73                /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
  74                iowait = kcs->cpustat[CPUTIME_IOWAIT];
  75        else
  76                iowait = iowait_usecs * NSEC_PER_USEC;
  77
  78        return iowait;
  79}
  80
  81#endif
  82
  83static void show_irq_gap(struct seq_file *p, unsigned int gap)
  84{
  85        static const char zeros[] = " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0";
  86
  87        while (gap > 0) {
  88                unsigned int inc;
  89
  90                inc = min_t(unsigned int, gap, ARRAY_SIZE(zeros) / 2);
  91                seq_write(p, zeros, 2 * inc);
  92                gap -= inc;
  93        }
  94}
  95
  96static void show_all_irqs(struct seq_file *p)
  97{
  98        unsigned int i, next = 0;
  99
 100        for_each_active_irq(i) {
 101                show_irq_gap(p, i - next);
 102                seq_put_decimal_ull(p, " ", kstat_irqs_usr(i));
 103                next = i + 1;
 104        }
 105        show_irq_gap(p, nr_irqs - next);
 106}
 107
 108static int show_stat(struct seq_file *p, void *v)
 109{
 110        int i, j;
 111        u64 user, nice, system, idle, iowait, irq, softirq, steal;
 112        u64 guest, guest_nice;
 113        u64 sum = 0;
 114        u64 sum_softirq = 0;
 115        unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
 116        struct timespec64 boottime;
 117
 118        user = nice = system = idle = iowait =
 119                irq = softirq = steal = 0;
 120        guest = guest_nice = 0;
 121        getboottime64(&boottime);
 122        /* shift boot timestamp according to the timens offset */
 123        timens_sub_boottime(&boottime);
 124
 125        for_each_possible_cpu(i) {
 126                struct kernel_cpustat kcpustat;
 127                u64 *cpustat = kcpustat.cpustat;
 128
 129                kcpustat_cpu_fetch(&kcpustat, i);
 130
 131                user            += cpustat[CPUTIME_USER];
 132                nice            += cpustat[CPUTIME_NICE];
 133                system          += cpustat[CPUTIME_SYSTEM];
 134                idle            += get_idle_time(&kcpustat, i);
 135                iowait          += get_iowait_time(&kcpustat, i);
 136                irq             += cpustat[CPUTIME_IRQ];
 137                softirq         += cpustat[CPUTIME_SOFTIRQ];
 138                steal           += cpustat[CPUTIME_STEAL];
 139                guest           += cpustat[CPUTIME_GUEST];
 140                guest_nice      += cpustat[CPUTIME_GUEST_NICE];
 141                sum             += kstat_cpu_irqs_sum(i);
 142                sum             += arch_irq_stat_cpu(i);
 143
 144                for (j = 0; j < NR_SOFTIRQS; j++) {
 145                        unsigned int softirq_stat = kstat_softirqs_cpu(j, i);
 146
 147                        per_softirq_sums[j] += softirq_stat;
 148                        sum_softirq += softirq_stat;
 149                }
 150        }
 151        sum += arch_irq_stat();
 152
 153        seq_put_decimal_ull(p, "cpu  ", nsec_to_clock_t(user));
 154        seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
 155        seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
 156        seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
 157        seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
 158        seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
 159        seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
 160        seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
 161        seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
 162        seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
 163        seq_putc(p, '\n');
 164
 165        for_each_online_cpu(i) {
 166                struct kernel_cpustat kcpustat;
 167                u64 *cpustat = kcpustat.cpustat;
 168
 169                kcpustat_cpu_fetch(&kcpustat, i);
 170
 171                /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
 172                user            = cpustat[CPUTIME_USER];
 173                nice            = cpustat[CPUTIME_NICE];
 174                system          = cpustat[CPUTIME_SYSTEM];
 175                idle            = get_idle_time(&kcpustat, i);
 176                iowait          = get_iowait_time(&kcpustat, i);
 177                irq             = cpustat[CPUTIME_IRQ];
 178                softirq         = cpustat[CPUTIME_SOFTIRQ];
 179                steal           = cpustat[CPUTIME_STEAL];
 180                guest           = cpustat[CPUTIME_GUEST];
 181                guest_nice      = cpustat[CPUTIME_GUEST_NICE];
 182                seq_printf(p, "cpu%d", i);
 183                seq_put_decimal_ull(p, " ", nsec_to_clock_t(user));
 184                seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
 185                seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
 186                seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
 187                seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
 188                seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
 189                seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
 190                seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
 191                seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
 192                seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
 193                seq_putc(p, '\n');
 194        }
 195        seq_put_decimal_ull(p, "intr ", (unsigned long long)sum);
 196
 197        show_all_irqs(p);
 198
 199        seq_printf(p,
 200                "\nctxt %llu\n"
 201                "btime %llu\n"
 202                "processes %lu\n"
 203                "procs_running %u\n"
 204                "procs_blocked %u\n",
 205                nr_context_switches(),
 206                (unsigned long long)boottime.tv_sec,
 207                total_forks,
 208                nr_running(),
 209                nr_iowait());
 210
 211        seq_put_decimal_ull(p, "softirq ", (unsigned long long)sum_softirq);
 212
 213        for (i = 0; i < NR_SOFTIRQS; i++)
 214                seq_put_decimal_ull(p, " ", per_softirq_sums[i]);
 215        seq_putc(p, '\n');
 216
 217        return 0;
 218}
 219
 220static int stat_open(struct inode *inode, struct file *file)
 221{
 222        unsigned int size = 1024 + 128 * num_online_cpus();
 223
 224        /* minimum size to display an interrupt count : 2 bytes */
 225        size += 2 * nr_irqs;
 226        return single_open_size(file, show_stat, NULL, size);
 227}
 228
 229static const struct proc_ops stat_proc_ops = {
 230        .proc_flags     = PROC_ENTRY_PERMANENT,
 231        .proc_open      = stat_open,
 232        .proc_read_iter = seq_read_iter,
 233        .proc_lseek     = seq_lseek,
 234        .proc_release   = single_release,
 235};
 236
 237static int __init proc_stat_init(void)
 238{
 239        proc_create("stat", 0, NULL, &stat_proc_ops);
 240        return 0;
 241}
 242fs_initcall(proc_stat_init);
 243