Merge tag 'v4.19-rc5' of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds...
[sfrench/cifs-2.6.git] / fs / proc / stat.c
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/irqnr.h>
14 #include <linux/sched/cputime.h>
15 #include <linux/tick.h>
16
17 #ifndef arch_irq_stat_cpu
18 #define arch_irq_stat_cpu(cpu) 0
19 #endif
20 #ifndef arch_irq_stat
21 #define arch_irq_stat() 0
22 #endif
23
24 #ifdef arch_idle_time
25
26 static u64 get_idle_time(int cpu)
27 {
28         u64 idle;
29
30         idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
31         if (cpu_online(cpu) && !nr_iowait_cpu(cpu))
32                 idle += arch_idle_time(cpu);
33         return idle;
34 }
35
36 static u64 get_iowait_time(int cpu)
37 {
38         u64 iowait;
39
40         iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
41         if (cpu_online(cpu) && nr_iowait_cpu(cpu))
42                 iowait += arch_idle_time(cpu);
43         return iowait;
44 }
45
46 #else
47
48 static u64 get_idle_time(int cpu)
49 {
50         u64 idle, idle_usecs = -1ULL;
51
52         if (cpu_online(cpu))
53                 idle_usecs = get_cpu_idle_time_us(cpu, NULL);
54
55         if (idle_usecs == -1ULL)
56                 /* !NO_HZ or cpu offline so we can rely on cpustat.idle */
57                 idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
58         else
59                 idle = idle_usecs * NSEC_PER_USEC;
60
61         return idle;
62 }
63
64 static u64 get_iowait_time(int cpu)
65 {
66         u64 iowait, iowait_usecs = -1ULL;
67
68         if (cpu_online(cpu))
69                 iowait_usecs = get_cpu_iowait_time_us(cpu, NULL);
70
71         if (iowait_usecs == -1ULL)
72                 /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
73                 iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
74         else
75                 iowait = iowait_usecs * NSEC_PER_USEC;
76
77         return iowait;
78 }
79
80 #endif
81
82 static int show_stat(struct seq_file *p, void *v)
83 {
84         int i, j;
85         u64 user, nice, system, idle, iowait, irq, softirq, steal;
86         u64 guest, guest_nice;
87         u64 sum = 0;
88         u64 sum_softirq = 0;
89         unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
90         struct timespec64 boottime;
91
92         user = nice = system = idle = iowait =
93                 irq = softirq = steal = 0;
94         guest = guest_nice = 0;
95         getboottime64(&boottime);
96
97         for_each_possible_cpu(i) {
98                 user += kcpustat_cpu(i).cpustat[CPUTIME_USER];
99                 nice += kcpustat_cpu(i).cpustat[CPUTIME_NICE];
100                 system += kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM];
101                 idle += get_idle_time(i);
102                 iowait += get_iowait_time(i);
103                 irq += kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
104                 softirq += kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ];
105                 steal += kcpustat_cpu(i).cpustat[CPUTIME_STEAL];
106                 guest += kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
107                 guest_nice += kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
108                 sum += kstat_cpu_irqs_sum(i);
109                 sum += arch_irq_stat_cpu(i);
110
111                 for (j = 0; j < NR_SOFTIRQS; j++) {
112                         unsigned int softirq_stat = kstat_softirqs_cpu(j, i);
113
114                         per_softirq_sums[j] += softirq_stat;
115                         sum_softirq += softirq_stat;
116                 }
117         }
118         sum += arch_irq_stat();
119
120         seq_put_decimal_ull(p, "cpu  ", nsec_to_clock_t(user));
121         seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
122         seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
123         seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
124         seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
125         seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
126         seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
127         seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
128         seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
129         seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
130         seq_putc(p, '\n');
131
132         for_each_online_cpu(i) {
133                 /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
134                 user = kcpustat_cpu(i).cpustat[CPUTIME_USER];
135                 nice = kcpustat_cpu(i).cpustat[CPUTIME_NICE];
136                 system = kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM];
137                 idle = get_idle_time(i);
138                 iowait = get_iowait_time(i);
139                 irq = kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
140                 softirq = kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ];
141                 steal = kcpustat_cpu(i).cpustat[CPUTIME_STEAL];
142                 guest = kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
143                 guest_nice = kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
144                 seq_printf(p, "cpu%d", i);
145                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(user));
146                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
147                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
148                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
149                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
150                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
151                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
152                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
153                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
154                 seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
155                 seq_putc(p, '\n');
156         }
157         seq_put_decimal_ull(p, "intr ", (unsigned long long)sum);
158
159         /* sum again ? it could be updated? */
160         for_each_irq_nr(j)
161                 seq_put_decimal_ull(p, " ", kstat_irqs_usr(j));
162
163         seq_printf(p,
164                 "\nctxt %llu\n"
165                 "btime %llu\n"
166                 "processes %lu\n"
167                 "procs_running %lu\n"
168                 "procs_blocked %lu\n",
169                 nr_context_switches(),
170                 (unsigned long long)boottime.tv_sec,
171                 total_forks,
172                 nr_running(),
173                 nr_iowait());
174
175         seq_put_decimal_ull(p, "softirq ", (unsigned long long)sum_softirq);
176
177         for (i = 0; i < NR_SOFTIRQS; i++)
178                 seq_put_decimal_ull(p, " ", per_softirq_sums[i]);
179         seq_putc(p, '\n');
180
181         return 0;
182 }
183
184 static int stat_open(struct inode *inode, struct file *file)
185 {
186         unsigned int size = 1024 + 128 * num_online_cpus();
187
188         /* minimum size to display an interrupt count : 2 bytes */
189         size += 2 * nr_irqs;
190         return single_open_size(file, show_stat, NULL, size);
191 }
192
193 static const struct file_operations proc_stat_operations = {
194         .open           = stat_open,
195         .read           = seq_read,
196         .llseek         = seq_lseek,
197         .release        = single_release,
198 };
199
200 static int __init proc_stat_init(void)
201 {
202         proc_create("stat", 0, NULL, &proc_stat_operations);
203         return 0;
204 }
205 fs_initcall(proc_stat_init);