mcst-linux-kernel/linux-kernel-5.10/fs/proc/mcst_debug.c

131 lines
3.1 KiB
C

/*
* SPDX-License-Identifier: GPL-2.0
* Copyright (c) 2023 MCST
*/
#ifdef CONFIG_MCST
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/seqlock.h>
#include <linux/timex.h>
#include <asm/timer.h>
#include <asm/uaccess.h>
#define GHZ 1000000000
#ifndef DINTR_TIMER_UNITS
#define DINTR_TIMER_UNITS "unknown"
#endif
/* Time of disabled interrupts */
DEFINE_PER_CPU(unsigned long, dintr_time_max);
DEFINE_PER_CPU(unsigned long, dintr_time_min);
/* The different cpu_times for printing */
cpu_times_t cpu_times[NR_CPUS] = {
[0 ... NR_CPUS-1] = {
.curr_time_switch_to = 0,
.min_time_switch_to = LLONG_MAX,
.max_time_switch_to = 0
}
};
static DEFINE_MUTEX(dintr_mutex);
int dintr_timer_state = DINTR_TIMER_WASNT_USE;
static int cpu_times_show(struct seq_file *m, void *v)
{
int my_cpu, cpu;
my_cpu = raw_smp_processor_id();
/* Print the time of disabled interrupt state */
seq_printf(m, "\t The duration of disabled interrupt state (in "
DINTR_TIMER_UNITS ")\n");
for_each_online_cpu(cpu) {
unsigned long min = per_cpu(dintr_time_min, cpu);
unsigned long max = per_cpu(dintr_time_max, cpu);
if (min > max)
seq_printf(m, "cpu=%d: no data\t%c\n", cpu,
cpu == my_cpu ? '*' : '\0');
else
seq_printf(m, "cpu=%d: min=%lu, max=%lu\t%c\n", cpu,
per_cpu(dintr_time_min, cpu),
per_cpu(dintr_time_max, cpu),
cpu == my_cpu ? '*' : '\0');
}
/* print times of switch_to */
seq_printf(m, "\t The cpu times of switch_to (in nsec)\t\n");
for_each_online_cpu(cpu) {
u64 min_part = cpu_times[cpu].min_time_switch_to*GHZ;
u64 max_part = cpu_times[cpu].max_time_switch_to*GHZ;
do_div(min_part, cpu_freq_hz);
do_div(max_part, cpu_freq_hz);
seq_printf(m, "cpu=%d: min=%llu, max=%llu\n", cpu,
min_part, max_part);
}
return 0;
}
static ssize_t cpu_times_write(struct file *f, const char __user *b,
size_t c, loff_t *o)
{
char s;
int cpu;
if (get_user(s, b) == 0) {
switch (s) {
case '1':
mutex_lock(&dintr_mutex);
if (dintr_timer_state != DINTR_TIMER_RUNNING)
dintr_timer_state = DINTR_TIMER_RUNNING;
mutex_unlock(&dintr_mutex);
break;
case '0':
mutex_lock(&dintr_mutex);
if (dintr_timer_state == DINTR_TIMER_RUNNING)
dintr_timer_state = DINTR_TIMER_STOPPED;
mutex_unlock(&dintr_mutex);
break;
default:
for_each_online_cpu(cpu) {
per_cpu(dintr_time_min, cpu) = ULONG_MAX;
per_cpu(dintr_time_max, cpu) = 0;
cpu_times[cpu].min_time_switch_to = LLONG_MAX;
cpu_times[cpu].max_time_switch_to = 0;
}
}
}
return c;
}
static int cpu_times_open(struct inode *inode, struct file *file)
{
return single_open(file, cpu_times_show, NULL);
}
static const struct proc_ops cpu_times_pops = {
.proc_open = cpu_times_open,
.proc_read = seq_read,
.proc_write = cpu_times_write,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int __init proc_cpu_times_init(void)
{
proc_create("cpu_times", 0, NULL, &cpu_times_pops);
return 0;
}
module_init(proc_cpu_times_init);
#endif