projects/linux·blob master · refs

180 lines · 5.0 KiB

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
22static void show_irq_gap(struct seq_file *p, unsigned int gap)
23{
24 static const char zeros[] = " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0";
25
26 while (gap > 0) {
27 unsigned int inc;
28
29 inc = min_t(unsigned int, gap, ARRAY_SIZE(zeros) / 2);
30 seq_write(p, zeros, 2 * inc);
31 gap -= inc;
32 }
33}
34
35static void show_all_irqs(struct seq_file *p)
36{
37 unsigned int i, next = 0;
38
39 for_each_active_irq(i) {
40 show_irq_gap(p, i - next);
41 seq_put_decimal_ull(p, " ", kstat_irqs_usr(i));
42 next = i + 1;
43 }
44 show_irq_gap(p, irq_get_nr_irqs() - next);
45}
46
47static int show_stat(struct seq_file *p, void *v)
48{
49 int i, j;
50 u64 user, nice, system, idle, iowait, irq, softirq, steal;
51 u64 guest, guest_nice;
52 u64 sum = 0;
53 u64 sum_softirq = 0;
54 unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
55 struct timespec64 boottime;
56
57 user = nice = system = idle = iowait =
58 irq = softirq = steal = 0;
59 guest = guest_nice = 0;
60 getboottime64(&boottime);
61 /* shift boot timestamp according to the timens offset */
62 timens_sub_boottime(&boottime);
63
64 for_each_possible_cpu(i) {
65 struct kernel_cpustat kcpustat;
66 u64 *cpustat = kcpustat.cpustat;
67
68 kcpustat_cpu_fetch(&kcpustat, i);
69
70 user += cpustat[CPUTIME_USER];
71 nice += cpustat[CPUTIME_NICE];
72 system += cpustat[CPUTIME_SYSTEM];
73 idle += cpustat[CPUTIME_IDLE];
74 iowait += cpustat[CPUTIME_IOWAIT];
75 irq += cpustat[CPUTIME_IRQ];
76 softirq += cpustat[CPUTIME_SOFTIRQ];
77 steal += cpustat[CPUTIME_STEAL];
78 guest += cpustat[CPUTIME_GUEST];
79 guest_nice += cpustat[CPUTIME_GUEST_NICE];
80 sum += kstat_cpu_irqs_sum(i);
81 sum += arch_irq_stat_cpu(i);
82
83 for (j = 0; j < NR_SOFTIRQS; j++) {
84 unsigned int softirq_stat = kstat_softirqs_cpu(j, i);
85
86 per_softirq_sums[j] += softirq_stat;
87 sum_softirq += softirq_stat;
88 }
89 }
90
91 seq_put_decimal_ull(p, "cpu ", nsec_to_clock_t(user));
92 seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
93 seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
94 seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
95 seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
96 seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
97 seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
98 seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
99 seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
100 seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
101 seq_putc(p, '\n');
102
103 for_each_online_cpu(i) {
104 struct kernel_cpustat kcpustat;
105 u64 *cpustat = kcpustat.cpustat;
106
107 kcpustat_cpu_fetch(&kcpustat, i);
108
109 /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
110 user = cpustat[CPUTIME_USER];
111 nice = cpustat[CPUTIME_NICE];
112 system = cpustat[CPUTIME_SYSTEM];
113 idle = cpustat[CPUTIME_IDLE];
114 iowait = cpustat[CPUTIME_IOWAIT];
115 irq = cpustat[CPUTIME_IRQ];
116 softirq = cpustat[CPUTIME_SOFTIRQ];
117 steal = cpustat[CPUTIME_STEAL];
118 guest = cpustat[CPUTIME_GUEST];
119 guest_nice = cpustat[CPUTIME_GUEST_NICE];
120 seq_printf(p, "cpu%d", i);
121 seq_put_decimal_ull(p, " ", nsec_to_clock_t(user));
122 seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
123 seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
124 seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
125 seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
126 seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
127 seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
128 seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
129 seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
130 seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
131 seq_putc(p, '\n');
132 }
133 seq_put_decimal_ull(p, "intr ", (unsigned long long)sum);
134
135 show_all_irqs(p);
136
137 seq_printf(p,
138 "\nctxt %llu\n"
139 "btime %llu\n"
140 "processes %lu\n"
141 "procs_running %u\n"
142 "procs_blocked %u\n",
143 nr_context_switches(),
144 (unsigned long long)boottime.tv_sec,
145 total_forks,
146 nr_running(),
147 nr_iowait());
148
149 seq_put_decimal_ull(p, "softirq ", (unsigned long long)sum_softirq);
150
151 for (i = 0; i < NR_SOFTIRQS; i++)
152 seq_put_decimal_ull(p, " ", per_softirq_sums[i]);
153 seq_putc(p, '\n');
154
155 return 0;
156}
157
158static int stat_open(struct inode *inode, struct file *file)
159{
160 unsigned int size = 1024 + 128 * num_online_cpus();
161
162 /* minimum size to display an interrupt count : 2 bytes */
163 size += 2 * irq_get_nr_irqs();
164 return single_open_size(file, show_stat, NULL, size);
165}
166
167static const struct proc_ops stat_proc_ops = {
168 .proc_flags = PROC_ENTRY_PERMANENT,
169 .proc_open = stat_open,
170 .proc_read_iter = seq_read_iter,
171 .proc_lseek = seq_lseek,
172 .proc_release = single_release,
173};
174
175static int __init proc_stat_init(void)
176{
177 proc_create("stat", 0, NULL, &stat_proc_ops);
178 return 0;
179}
180fs_initcall(proc_stat_init);