📄 mpstat.c
字号:
/* * mpstat: per-processor statistics * (C) 2000-2006 by Sebastien GODARD (sysstat <at> wanadoo.fr) * *************************************************************************** * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 2 of the License, or (at your * * option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY * * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along * * with this program; if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *************************************************************************** */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <errno.h>#include <ctype.h>#include <sys/utsname.h>#include <sys/param.h> /* for HZ */#include "mpstat.h"#include "common.h"#ifdef USE_NLS#include <locale.h>#include <libintl.h>#define _(string) gettext(string)#else#define _(string) (string)#endifstruct mp_stats *st_mp_cpu[DIM];/* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/unsigned char *cpu_bitmap; /* Bit 0: Global; Bit 1: 1st proc; etc. */struct mp_timestamp st_mp_tstamp[DIM];/* Nb of processors on the machine. A value of 1 means two processors */int cpu_nr = -1;long interval = -1, count = 0;/* *************************************************************************** * Print usage and exit *************************************************************************** */void usage(char *progname){ fprintf(stderr, _("Usage: %s [ options... ] [ <interval> [ <count> ] ]\n" "Options are:\n" "[ -P { <cpu> | ALL } ] [ -V ]\n"), progname); exit(1);}/* *************************************************************************** * SIGALRM signal handler *************************************************************************** */void alarm_handler(int sig){ signal(SIGALRM, alarm_handler); alarm(interval);}/* *************************************************************************** * Allocate mp_stats structures and cpu bitmap *************************************************************************** */void salloc_mp_cpu(int nr_cpus){ int i; for (i = 0; i < DIM; i++) { if ((st_mp_cpu[i] = (struct mp_stats *) malloc(MP_STATS_SIZE * nr_cpus)) == NULL) { perror("malloc"); exit(4); } memset(st_mp_cpu[i], 0, MP_STATS_SIZE * nr_cpus); } if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) { perror("malloc"); exit(4); } memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);}/* *************************************************************************** * Core function used to display statistics *************************************************************************** */void write_stats_core(short prev, short curr, short dis, char *prev_string, char *curr_string){ struct mp_stats *st_mp_cpu_i, *st_mp_cpu_j; unsigned long long itv; int cpu; /* * Under very special circumstances, STDOUT may become unavailable, * This is what we try to guess here */ if (write(STDOUT_FILENO, "", 0) == -1) { perror("stdout"); exit(6); } /* * Interval value in jiffies, multiplied by the number of proc. * The interval should always be smaller than 0xffffffff (ULONG_MAX on * 32-bit architectures), except perhaps if it is the interval since * system startup (we want stats since boot time). * Interval is and'ed with mask 0xffffffff to handle overflow conditions * that may happen since uptime values are unsigned long long but are * calculated as a sum of values that _may_ be unsigned long only... */ if (!interval) itv = st_mp_tstamp[curr].uptime; else itv = (st_mp_tstamp[curr].uptime - st_mp_tstamp[prev].uptime) & 0xffffffff; if (!itv) /* Paranoia checking */ itv = 1; /* Print stats */ if (dis) printf("\n%-11s CPU %%user %%nice %%sys %%iowait %%irq " "%%soft %%steal %%idle intr/s\n", prev_string); /* Check if we want global stats among all proc */ if (*cpu_bitmap & 1) { printf("%-11s all", curr_string); printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f", ll_sp_value(st_mp_cpu[prev]->cpu_user, st_mp_cpu[curr]->cpu_user, itv), ll_sp_value(st_mp_cpu[prev]->cpu_nice, st_mp_cpu[curr]->cpu_nice, itv), ll_sp_value(st_mp_cpu[prev]->cpu_system, st_mp_cpu[curr]->cpu_system, itv), ll_sp_value(st_mp_cpu[prev]->cpu_iowait, st_mp_cpu[curr]->cpu_iowait, itv), ll_sp_value(st_mp_cpu[prev]->cpu_hardirq, st_mp_cpu[curr]->cpu_hardirq, itv), ll_sp_value(st_mp_cpu[prev]->cpu_softirq, st_mp_cpu[curr]->cpu_softirq, itv), ll_sp_value(st_mp_cpu[prev]->cpu_steal, st_mp_cpu[curr]->cpu_steal , itv), (st_mp_cpu[curr]->cpu_idle < st_mp_cpu[prev]->cpu_idle) ? 0.0 : /* Handle buggy kernels */ ll_sp_value(st_mp_cpu[prev]->cpu_idle, st_mp_cpu[curr]->cpu_idle, itv)); } /* * Here, we reduce the interval value to one processor, * using the uptime computed for proc#0. */ if (cpu_nr) { if (!interval) itv = st_mp_tstamp[curr].uptime0; else itv = (st_mp_tstamp[curr].uptime0 - st_mp_tstamp[prev].uptime0) & 0xffffffff; if (!itv) itv = 1; } if (*cpu_bitmap & 1) { printf(" %9.2f\n", ll_s_value(st_mp_cpu[prev]->irq, st_mp_cpu[curr]->irq, itv)); } for (cpu = 1; cpu <= cpu_nr + 1; cpu++) { /* Check if we want stats about this proc */ if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07)))) continue; printf("%-11s %4d", curr_string, cpu - 1); st_mp_cpu_i = st_mp_cpu[curr] + cpu; st_mp_cpu_j = st_mp_cpu[prev] + cpu; printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %9.2f\n", ll_sp_value(st_mp_cpu_j->cpu_user, st_mp_cpu_i->cpu_user, itv), ll_sp_value(st_mp_cpu_j->cpu_nice, st_mp_cpu_i->cpu_nice, itv), ll_sp_value(st_mp_cpu_j->cpu_system, st_mp_cpu_i->cpu_system, itv), ll_sp_value(st_mp_cpu_j->cpu_iowait, st_mp_cpu_i->cpu_iowait, itv), ll_sp_value(st_mp_cpu_j->cpu_hardirq, st_mp_cpu_i->cpu_hardirq, itv), ll_sp_value(st_mp_cpu_j->cpu_softirq, st_mp_cpu_i->cpu_softirq, itv), ll_sp_value(st_mp_cpu_j->cpu_steal, st_mp_cpu_i->cpu_steal, itv), (st_mp_cpu_i->cpu_idle < st_mp_cpu_j->cpu_idle) ? 0.0 : ll_sp_value(st_mp_cpu_j->cpu_idle, st_mp_cpu_i->cpu_idle, itv), ll_s_value(st_mp_cpu_j->irq, st_mp_cpu_i->irq, itv)); }}/* *************************************************************************** * Print statistics average *************************************************************************** */void write_stats_avg(short curr, short dis){ char string[16]; strcpy(string, _("Average:")); write_stats_core(2, curr, dis, string, string);}/* *************************************************************************** * Print statistics *************************************************************************** */void write_stats(short curr, short dis, struct tm *loc_time){ char cur_time[2][16]; /* * Get previous timestamp * NOTE: loc_time structure must have been init'ed before! */ loc_time->tm_hour = st_mp_tstamp[!curr].hour; loc_time->tm_min = st_mp_tstamp[!curr].minute; loc_time->tm_sec = st_mp_tstamp[!curr].second; strftime(cur_time[!curr], 16, "%X", loc_time); /* Get current timestamp */ loc_time->tm_hour = st_mp_tstamp[curr].hour; loc_time->tm_min = st_mp_tstamp[curr].minute; loc_time->tm_sec = st_mp_tstamp[curr].second; strftime(cur_time[curr], 16, "%X", loc_time); write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);}/* *************************************************************************** * Read stats from /proc/stat *************************************************************************** */void read_proc_stat(short curr){ FILE *fp; struct mp_stats *st_mp_cpu_i; static char line[80]; unsigned long long cc_user, cc_nice, cc_system, cc_hardirq, cc_softirq; unsigned long long cc_idle, cc_iowait, cc_steal; int proc_nb; if ((fp = fopen(STAT, "r")) == NULL) { fprintf(stderr, _("Cannot open %s: %s\n"), STAT, strerror(errno)); exit(2); } while (fgets(line, 80, fp) != NULL) { if (!strncmp(line, "cpu ", 4)) { /* * Read the number of jiffies spent in the different modes * among all proc. CPU usage is not reduced to one * processor to avoid rounding problems. */ st_mp_cpu[curr]->cpu_iowait = 0; /* For pre 2.5 kernels */ cc_hardirq = cc_softirq = cc_steal = 0; /* CPU counters became unsigned long long with kernel 2.6.5 */ sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu", &(st_mp_cpu[curr]->cpu_user), &(st_mp_cpu[curr]->cpu_nice), &(st_mp_cpu[curr]->cpu_system), &(st_mp_cpu[curr]->cpu_idle), &(st_mp_cpu[curr]->cpu_iowait), &(st_mp_cpu[curr]->cpu_hardirq),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -