cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stat.c (6349B)


      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
     27u64 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
     49u64 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);