Branch data Line data Source code
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(struct kernel_cpustat *kcs, int cpu)
27 : : {
28 : : u64 idle;
29 : :
30 : : idle = kcs->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(struct kernel_cpustat *kcs, int cpu)
37 : : {
38 : : u64 iowait;
39 : :
40 : : iowait = kcs->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 : 80 : static u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
49 : : {
50 : : u64 idle, idle_usecs = -1ULL;
51 : :
52 [ + - ]: 80 : if (cpu_online(cpu))
53 : 80 : idle_usecs = get_cpu_idle_time_us(cpu, NULL);
54 : :
55 [ - + ]: 80 : if (idle_usecs == -1ULL)
56 : : /* !NO_HZ or cpu offline so we can rely on cpustat.idle */
57 : 0 : idle = kcs->cpustat[CPUTIME_IDLE];
58 : : else
59 : 80 : idle = idle_usecs * NSEC_PER_USEC;
60 : :
61 : 80 : return idle;
62 : : }
63 : :
64 : 80 : static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu)
65 : : {
66 : : u64 iowait, iowait_usecs = -1ULL;
67 : :
68 [ + - ]: 80 : if (cpu_online(cpu))
69 : 80 : iowait_usecs = get_cpu_iowait_time_us(cpu, NULL);
70 : :
71 [ - + ]: 80 : if (iowait_usecs == -1ULL)
72 : : /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
73 : 0 : iowait = kcs->cpustat[CPUTIME_IOWAIT];
74 : : else
75 : 80 : iowait = iowait_usecs * NSEC_PER_USEC;
76 : :
77 : 80 : return iowait;
78 : : }
79 : :
80 : : #endif
81 : :
82 : 1670 : static void show_irq_gap(struct seq_file *p, unsigned int gap)
83 : : {
84 : : static const char zeros[] = " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0";
85 : :
86 [ - + ]: 3340 : while (gap > 0) {
87 : : unsigned int inc;
88 : :
89 : 0 : inc = min_t(unsigned int, gap, ARRAY_SIZE(zeros) / 2);
90 : 0 : seq_write(p, zeros, 2 * inc);
91 : 0 : gap -= inc;
92 : : }
93 : 1670 : }
94 : :
95 : 10 : static void show_all_irqs(struct seq_file *p)
96 : : {
97 : : unsigned int i, next = 0;
98 : :
99 [ + + ]: 1670 : for_each_active_irq(i) {
100 : 1660 : show_irq_gap(p, i - next);
101 : 1660 : seq_put_decimal_ull(p, " ", kstat_irqs_usr(i));
102 : 1660 : next = i + 1;
103 : : }
104 : 10 : show_irq_gap(p, nr_irqs - next);
105 : 10 : }
106 : :
107 : 10 : static int show_stat(struct seq_file *p, void *v)
108 : : {
109 : : int i, j;
110 : : u64 user, nice, system, idle, iowait, irq, softirq, steal;
111 : : u64 guest, guest_nice;
112 : : u64 sum = 0;
113 : : u64 sum_softirq = 0;
114 : 10 : unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
115 : : struct timespec64 boottime;
116 : :
117 : : user = nice = system = idle = iowait =
118 : : irq = softirq = steal = 0;
119 : : guest = guest_nice = 0;
120 : 10 : getboottime64(&boottime);
121 : :
122 [ + + ]: 60 : for_each_possible_cpu(i) {
123 : 40 : struct kernel_cpustat *kcs = &kcpustat_cpu(i);
124 : :
125 : 40 : user += kcs->cpustat[CPUTIME_USER];
126 : 40 : nice += kcs->cpustat[CPUTIME_NICE];
127 : 40 : system += kcs->cpustat[CPUTIME_SYSTEM];
128 : 40 : idle += get_idle_time(kcs, i);
129 : 40 : iowait += get_iowait_time(kcs, i);
130 : 40 : irq += kcs->cpustat[CPUTIME_IRQ];
131 : 40 : softirq += kcs->cpustat[CPUTIME_SOFTIRQ];
132 : 40 : steal += kcs->cpustat[CPUTIME_STEAL];
133 : 40 : guest += kcs->cpustat[CPUTIME_GUEST];
134 : 40 : guest_nice += kcs->cpustat[CPUTIME_GUEST_NICE];
135 : 40 : sum += kstat_cpu_irqs_sum(i);
136 : 40 : sum += arch_irq_stat_cpu(i);
137 : :
138 [ + + ]: 440 : for (j = 0; j < NR_SOFTIRQS; j++) {
139 : 400 : unsigned int softirq_stat = kstat_softirqs_cpu(j, i);
140 : :
141 : 400 : per_softirq_sums[j] += softirq_stat;
142 : 400 : sum_softirq += softirq_stat;
143 : : }
144 : : }
145 : 10 : sum += arch_irq_stat();
146 : :
147 : 10 : seq_put_decimal_ull(p, "cpu ", nsec_to_clock_t(user));
148 : 10 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
149 : 10 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
150 : 10 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
151 : 10 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
152 : 10 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
153 : 10 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
154 : 10 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
155 : 10 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
156 : 10 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
157 : 10 : seq_putc(p, '\n');
158 : :
159 [ + + ]: 60 : for_each_online_cpu(i) {
160 : 40 : struct kernel_cpustat *kcs = &kcpustat_cpu(i);
161 : :
162 : : /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
163 : 40 : user = kcs->cpustat[CPUTIME_USER];
164 : 40 : nice = kcs->cpustat[CPUTIME_NICE];
165 : 40 : system = kcs->cpustat[CPUTIME_SYSTEM];
166 : 40 : idle = get_idle_time(kcs, i);
167 : 40 : iowait = get_iowait_time(kcs, i);
168 : 40 : irq = kcs->cpustat[CPUTIME_IRQ];
169 : 40 : softirq = kcs->cpustat[CPUTIME_SOFTIRQ];
170 : 40 : steal = kcs->cpustat[CPUTIME_STEAL];
171 : 40 : guest = kcs->cpustat[CPUTIME_GUEST];
172 : 40 : guest_nice = kcs->cpustat[CPUTIME_GUEST_NICE];
173 : 40 : seq_printf(p, "cpu%d", i);
174 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(user));
175 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
176 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
177 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
178 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
179 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
180 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
181 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
182 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
183 : 40 : seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
184 : 40 : seq_putc(p, '\n');
185 : : }
186 : 10 : seq_put_decimal_ull(p, "intr ", (unsigned long long)sum);
187 : :
188 : 10 : show_all_irqs(p);
189 : :
190 : 20 : seq_printf(p,
191 : : "\nctxt %llu\n"
192 : : "btime %llu\n"
193 : : "processes %lu\n"
194 : : "procs_running %lu\n"
195 : : "procs_blocked %lu\n",
196 : : nr_context_switches(),
197 : 10 : (unsigned long long)boottime.tv_sec,
198 : : total_forks,
199 : : nr_running(),
200 : : nr_iowait());
201 : :
202 : 10 : seq_put_decimal_ull(p, "softirq ", (unsigned long long)sum_softirq);
203 : :
204 [ + + ]: 110 : for (i = 0; i < NR_SOFTIRQS; i++)
205 : 100 : seq_put_decimal_ull(p, " ", per_softirq_sums[i]);
206 : 10 : seq_putc(p, '\n');
207 : :
208 : 10 : return 0;
209 : : }
210 : :
211 : 10 : static int stat_open(struct inode *inode, struct file *file)
212 : : {
213 : 10 : unsigned int size = 1024 + 128 * num_online_cpus();
214 : :
215 : : /* minimum size to display an interrupt count : 2 bytes */
216 : 10 : size += 2 * nr_irqs;
217 : 10 : return single_open_size(file, show_stat, NULL, size);
218 : : }
219 : :
220 : : static const struct file_operations proc_stat_operations = {
221 : : .open = stat_open,
222 : : .read = seq_read,
223 : : .llseek = seq_lseek,
224 : : .release = single_release,
225 : : };
226 : :
227 : 404 : static int __init proc_stat_init(void)
228 : : {
229 : 404 : proc_create("stat", 0, NULL, &proc_stat_operations);
230 : 404 : return 0;
231 : : }
232 : : fs_initcall(proc_stat_init);
|