The attached patch-in-progress removes the per-cpu statistics from
struct kernel_stat and puts them in a cpu_stat structure, one per cpu,
cacheline padded. The data is still coolated and presented through
/proc/stat, but another file /proc/cpustat is also added. The locking
is as nonexistant as it was with kernel_stat, but who cares, they're
just fuzzy stats to be eyeballed by system tuners :).
A tool for printing the cpu stats specifically can be found near:
http://www.osdlab.org/sw_resources/cpustat/index.shtml
Its output is almost identical to solaris' mpstat.
I'm not sure I like the macro use, but it shields the callers from the
union garbage. We can easily also make a THIS_CPU_STAT_ADD() interface,
as some have hinted would be nice :)
Currently its mostly ( :) ) only collecting the stats that were
collected in kernel_stat. I'd like to add more stats -- page faults,
syscalls, cross-cpu calls, etc. I understand people not wanting more
live cachelines in the fast paths. I can make CPU_CRITICAL_STAT defines
that are config-ed out..
comments? If its ok I can whip up a patch that updates all the ports
use of ->irqs[] as well.
- z
[ heading out for lunch :) ]
--- linux-2.4.5-cpustat/fs/proc/proc_misc.c.cpustat Fri Apr 13 20:26:07 2001
+++ linux-2.4.5-cpustat/fs/proc/proc_misc.c Thu Jun 21 12:23:49 2001
@@ -265,32 +265,36 @@
int i, len;
extern unsigned long total_forks;
unsigned long jif = jiffies;
- unsigned int sum = 0, user = 0, nice = 0, system = 0;
+ unsigned int sum = 0, user = 0, nice = 0, system = 0, ctxt = 0;
int major, disk;
for (i = 0 ; i < smp_num_cpus; i++) {
int cpu = cpu_logical_map(i), j;
- user += kstat.per_cpu_user[cpu];
- nice += kstat.per_cpu_nice[cpu];
- system += kstat.per_cpu_system[cpu];
+ user += CPU_STAT_VAL(cpu, user);
+ nice += CPU_STAT_VAL(cpu, nice);
+ system += CPU_STAT_VAL(cpu, system);
+ ctxt += CPU_STAT_VAL(cpu, context_swtch);
#if !defined(CONFIG_ARCH_S390)
for (j = 0 ; j < NR_IRQS ; j++)
- sum += kstat.irqs[cpu][j];
+ sum += CPU_STAT_VAL(cpu, irqs[j]);
#endif
}
len = sprintf(page, "cpu %u %u %u %lu\n", user, nice, system,
jif * smp_num_cpus - (user + nice + system));
- for (i = 0 ; i < smp_num_cpus; i++)
+ for (i = 0 ; i < smp_num_cpus; i++) {
+ unsigned int user_i, nice_i, system_i;
+
+ user_i = CPU_STAT_VAL(cpu_logical_map(i), user);
+ nice_i = CPU_STAT_VAL(cpu_logical_map(i), nice);
+ system_i = CPU_STAT_VAL(cpu_logical_map(i), system);
+
len += sprintf(page + len, "cpu%d %u %u %u %lu\n",
i,
- kstat.per_cpu_user[cpu_logical_map(i)],
- kstat.per_cpu_nice[cpu_logical_map(i)],
- kstat.per_cpu_system[cpu_logical_map(i)],
- jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
- + kstat.per_cpu_nice[cpu_logical_map(i)] \
- + kstat.per_cpu_system[cpu_logical_map(i)]));
+ user_i, nice_i, system_i,
+ jif - ( user_i + nice_i + system_i ) );
+ }
len += sprintf(page + len,
"page %u %u\n"
"swap %u %u\n"
@@ -330,13 +334,58 @@
"\nctxt %u\n"
"btime %lu\n"
"processes %lu\n",
- kstat.context_swtch,
+ ctxt,
xtime.tv_sec - jif / HZ,
total_forks);
return proc_calc_metrics(page, start, off, count, eof, len);
}
+static int cstat_read_proc(char *page, char **start, off_t off,
+int count, int *eof, void *data)
+{
+ int i, len;
+
+ len = sprintf(page, "cpu_stat 0.0\n");
+
+ for (i = 0 ; i < smp_num_cpus; i++) {
+ unsigned int user, nice, system;
+ int j, cpu = cpu_logical_map(i);
+
+#if !defined(CONFIG_ARCH_S390)
+ len += sprintf(page + len, "cpu%d irqs ", cpu);
+ for (j = 0 ; j < NR_IRQS ; j++) {
+ len += sprintf(page + len, " %u",
+ CPU_STAT_VAL(cpu, irqs[j]));
+ }
+ len += sprintf(page + len, "\n");
+#endif
+#if defined(CONFIG_SMP)
+ len += sprintf(page + len, "cpu%d context_migration %u\n",
+ cpu, CPU_STAT_VAL(cpu, context_migration));
+#endif
+ len += sprintf(page + len, "cpu%d bottom_halves %u\n",
+ cpu, CPU_STAT_VAL(cpu, bh));
+ len += sprintf(page + len, "cpu%d context_switches %u\n",
+ cpu, CPU_STAT_VAL(cpu, context_swtch));