📄 sar.c
字号:
/* * sar: report system activity * (C) 1999-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 <time.h>#include <errno.h>#include <sys/param.h> /* for HZ */#include "sa.h"#include "common.h"#ifdef USE_NLS#include <locale.h>#include <libintl.h>#define _(string) gettext(string)#else#define _(string) (string)#endiflong interval = -1, count = 0;unsigned int sar_actflag = 0;unsigned int flags = 0;unsigned char irq_bitmap[(NR_IRQS / 8) + 1];unsigned char cpu_bitmap[(NR_CPUS / 8) + 1];int kb_shift = 0;struct stats_sum asum;struct file_hdr file_hdr;struct file_stats file_stats[DIM];struct stats_one_cpu *st_cpu[DIM] = {NULL, NULL, NULL};struct stats_serial *st_serial[DIM] = {NULL, NULL, NULL};struct stats_irq_cpu *st_irq_cpu[DIM] = {NULL, NULL, NULL};struct stats_net_dev *st_net_dev[DIM] = {NULL, NULL, NULL};struct disk_stats *st_disk[DIM] = {NULL, NULL, NULL};/* Array members of common types are always packed */unsigned int interrupts[DIM][NR_IRQS];/* Structures are aligned but also padded. Thus array members are packed */struct pid_stats *pid_stats[DIM][MAX_PID_NR];struct tm loc_time;/* Contain the date specified by -s and -e options */struct tstamp tm_start, tm_end;short dis_hdr = -1;int pid_nr = 0;char *args[MAX_ARGV_NR];/* *************************************************************************** * Print usage and exit *************************************************************************** */void usage(char *progname){ fprintf(stderr, _("Usage: %s [ options... ] [ <interval> [ <count> ] ]\n" "Options are:\n" "[ -A ] [ -b ] [ -B ] [ -c ] [ -d ] [ -i <interval> ] [ -p ] [ -q ]\n" "[ -r ] [ -R ] [ -t ] [ -u ] [ -v ] [ -V ] [ -w ] [ -W ] [ -y ]\n" "[ -I { <irq> | SUM | ALL | XALL } ] [ -P { <cpu> | ALL } ]\n" "[ -n { DEV | EDEV | NFS | NFSD | SOCK | ALL } ]\n" "[ -x { <pid> | SELF | ALL } ] [ -X { <pid> | SELF | ALL } ]\n" "[ -o [ <filename> ] | -f [ <filename> ] ]\n" "[ -s [ <hh:mm:ss> ] ] [ -e [ <hh:mm:ss> ] ]\n"), progname); exit(1);}/* *************************************************************************** * Init stats structures *************************************************************************** */void init_all_stats(void){ int i; init_stats(file_stats, interrupts); memset(&asum, 0, STATS_SUM_SIZE); for (i = 0; i < DIM; i++) pid_stats[i][0] = NULL;}/* *************************************************************************** * Allocate memory for sadc args *************************************************************************** */void salloc(int i, char *ltemp){ if ((args[i] = (char *) malloc(strlen(ltemp) + 1)) == NULL) { perror("malloc"); exit(4); } strcpy(args[i], ltemp);}/* *************************************************************************** * Allocate pid_stats structures *************************************************************************** */void salloc_pid(int nr_pid){ int i, pid; for (i = 0; i < DIM; i++) { if (pid_stats[i][0]) free(pid_stats[i][0]); if ((pid_stats[i][0] = (struct pid_stats *) malloc(PID_STATS_SIZE * nr_pid)) == NULL) { perror("malloc"); exit(4); } memset(pid_stats[i][0], 0, PID_STATS_SIZE * nr_pid); for (pid = 1; pid < nr_pid; pid++) /* Structures are aligned but also padded. Thus array members are packed */ pid_stats[i][pid] = pid_stats[i][0] + pid; /* Assume nr_pids <= MAX_PID_NR */ }}/* *************************************************************************** * Allocate structures *************************************************************************** */void allocate_structures(int stype){ if (file_hdr.sa_proc > 0) salloc_cpu_array(st_cpu, file_hdr.sa_proc + 1); if ((stype == USE_SADC) && (GET_PID(sar_actflag) || GET_CPID(sar_actflag))) { pid_nr = file_hdr.sa_nr_pid; salloc_pid(pid_nr); } if (file_hdr.sa_serial) salloc_serial_array(st_serial, file_hdr.sa_serial); if (file_hdr.sa_irqcpu) salloc_irqcpu_array(st_irq_cpu, file_hdr.sa_proc + 1, file_hdr.sa_irqcpu); if (file_hdr.sa_iface) salloc_net_dev_array(st_net_dev, file_hdr.sa_iface); if (file_hdr.sa_nr_disk) salloc_disk_array(st_disk, file_hdr.sa_nr_disk);}/* *************************************************************************** * Check if the user has the right to use -P option. * Note that he may use this option when reading stats from a file, * even if his machine is not an SMP one... * This routine is called only if we are *not* reading stats from a file. *************************************************************************** */void check_smp_option(unsigned int cpu_nr){ unsigned int j = 0, i; if (cpu_nr == 0) { fprintf(stderr, _("Not an SMP machine...\n")); exit(1); } for (i = (cpu_nr + 1); i < NR_CPUS; i++) j |= cpu_bitmap[i >> 3] & (1 << (i & 0x07)); if (j) { fprintf(stderr, _("Not that many processors!\n")); exit(1); }}/* *************************************************************************** * Check the use of option -P. * Called only if reading stats sent by the data collector. *************************************************************************** */void prep_smp_option(unsigned int cpu_nr){ unsigned int i; if (WANT_PER_PROC(flags)) { if (WANT_ALL_PROC(flags)) for (i = cpu_nr + 1; i < ((NR_CPUS >> 3) + 1) << 3; i++) /* * Reset every bit for proc > cpu_nr * (only done when -P ALL entered on the command line) */ cpu_bitmap[i >> 3] &= ~(1 << (i & 0x07)); check_smp_option(cpu_nr); }}/* *************************************************************************** * Fill loc_time structure according to time data saved in current * structure. ****************************************************************************/void set_loc_time(short curr){ struct tm *ltm; /* NOTE: loc_time structure must have been init'ed before! */ /* Check if option -t was specified on the command line */ if (PRINT_TRUE_TIME(flags)) { /* -t */ loc_time.tm_hour = file_stats[curr].hour; loc_time.tm_min = file_stats[curr].minute; loc_time.tm_sec = file_stats[curr].second; } else { ltm = localtime(&file_stats[curr].ust_time); loc_time = *ltm; }}/* *************************************************************************** * Set timestamp string ****************************************************************************/void set_timestamp(short curr, char *cur_time, int len){ set_loc_time(curr); /* Set cur_time date value */ strftime(cur_time, len, "%X", &loc_time);}/* *************************************************************************** * Core function used to display statistics *************************************************************************** */void write_stats_core(short prev, short curr, short dis, char *prev_string, char *curr_string, unsigned int act, unsigned long long itv, unsigned long long g_itv, int disp_avg, int want_since_boot){ int i, j = 0, k; struct file_stats *fsi = &file_stats[curr], *fsj = &file_stats[prev]; /* * 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); } /* Print number of processes created per second */ if (GET_PROC(act)) { if (dis) printf("\n%-11s proc/s\n", prev_string); printf("%-11s %9.2f\n", curr_string, S_VALUE(fsj->processes, fsi->processes, itv)); } /* Print number of context switches per second */ if (GET_CTXSW(act)) { if (dis) printf("\n%-11s cswch/s\n", prev_string); printf("%-11s %9.2f\n", curr_string, ll_s_value(fsj->context_swtch, fsi->context_swtch, itv)); } /* Print CPU usage */ if (GET_CPU(act)) { if (dis) printf("\n%-11s CPU %%user %%nice %%system " "%%iowait %%steal %%idle\n", prev_string); if (!WANT_PER_PROC(flags) || (WANT_PER_PROC(flags) && WANT_ALL_PROC(flags))) { printf("%-11s all", curr_string); printf(" %6.2f %6.2f %6.2f %6.2f %6.2f", ll_sp_value(fsj->cpu_user, fsi->cpu_user, g_itv), ll_sp_value(fsj->cpu_nice, fsi->cpu_nice, g_itv), ll_sp_value(fsj->cpu_system, fsi->cpu_system, g_itv), ll_sp_value(fsj->cpu_iowait, fsi->cpu_iowait, g_itv), ll_sp_value(fsj->cpu_steal, fsi->cpu_steal, g_itv)); printf(" %6.2f\n", fsi->cpu_idle < fsj->cpu_idle ? /* Handle buggy kernels */ 0.0 : ll_sp_value(fsj->cpu_idle, fsi->cpu_idle, g_itv)); } if (WANT_PER_PROC(flags) && file_hdr.sa_proc) { unsigned long long pc_itv; struct stats_one_cpu *sci = st_cpu[curr], *scj = st_cpu[prev]; for (i = 0; i <= file_hdr.sa_proc; i++, sci++, scj++) { if (cpu_bitmap[i >> 3] & (1 << (i & 0x07))) { printf("%-11s %3d", curr_string, i); /* Recalculate itv for current proc */ pc_itv = get_per_cpu_interval(sci, scj); printf(" %6.2f %6.2f %6.2f %6.2f %6.2f", ll_sp_value(scj->per_cpu_user, sci->per_cpu_user, pc_itv), ll_sp_value(scj->per_cpu_nice, sci->per_cpu_nice, pc_itv), ll_sp_value(scj->per_cpu_system, sci->per_cpu_system, pc_itv), ll_sp_value(scj->per_cpu_iowait, sci->per_cpu_iowait, pc_itv), ll_sp_value(scj->per_cpu_steal, sci->per_cpu_steal, pc_itv)); printf(" %6.2f\n", sci->per_cpu_idle < scj->per_cpu_idle ? 0.0 : ll_sp_value(scj->per_cpu_idle, sci->per_cpu_idle, pc_itv)); } } } } if (GET_IRQ(act) && (!WANT_PER_PROC(flags) || (WANT_PER_PROC(flags) && WANT_ALL_PROC(flags)))) { if (dis) printf("\n%-11s INTR intr/s\n", prev_string); /* Print number of interrupts per second */ printf("%-11s sum", curr_string); printf(" %9.2f\n", ll_s_value(fsj->irq_sum, fsi->irq_sum, itv)); } if (GET_ONE_IRQ(act)) { if (dis) printf("\n%-11s INTR intr/s\n", prev_string); /* Print number of interrupts per second */ for (i = 0; i < NR_IRQS; i++) { if (irq_bitmap[i >> 3] & (1 << (i & 0x07))) { printf("%-11s %3d", curr_string, i); printf(" %9.2f\n", S_VALUE(interrupts[prev][i], interrupts[curr][i], itv)); } } } /* Print paging statistics */ if (GET_PAGE(act)) { if (dis) printf("\n%-11s pgpgin/s pgpgout/s fault/s majflt/s\n", prev_string); printf("%-11s %9.2f %9.2f %9.2f %9.2f\n", curr_string, S_VALUE(fsj->pgpgin, fsi->pgpgin, itv), S_VALUE(fsj->pgpgout, fsi->pgpgout, itv), S_VALUE(fsj->pgfault, fsi->pgfault, itv), S_VALUE(fsj->pgmajfault, fsi->pgmajfault, itv)); } /* Print number of swap pages brought in and out */ if (GET_SWAP(act)) { if (dis) printf("\n%-11s pswpin/s pswpout/s\n", prev_string); printf("%-11s %9.2f %9.2f\n", curr_string, S_VALUE(fsj->pswpin, fsi->pswpin, itv), S_VALUE(fsj->pswpout, fsi->pswpout, itv)); } /* Print I/O stats (no distinction made between disks) */ if (GET_IO(act)) { if (dis) printf("\n%-11s tps rtps wtps bread/s bwrtn/s\n", prev_string); printf("%-11s %9.2f %9.2f %9.2f %9.2f %9.2f\n", curr_string, S_VALUE(fsj->dk_drive, fsi->dk_drive, itv), S_VALUE(fsj->dk_drive_rio, fsi->dk_drive_rio, itv), S_VALUE(fsj->dk_drive_wio, fsi->dk_drive_wio, itv), S_VALUE(fsj->dk_drive_rblk, fsi->dk_drive_rblk, itv), S_VALUE(fsj->dk_drive_wblk, fsi->dk_drive_wblk, itv)); } /* Print memory stats */ if (GET_MEMORY(act)) { if (dis) printf("\n%-11s frmpg/s bufpg/s campg/s\n", prev_string); printf("%-11s %9.2f %9.2f %9.2f\n", curr_string, S_VALUE((double) PG(fsj->frmkb), (double) PG(fsi->frmkb), itv), S_VALUE((double) PG(fsj->bufkb), (double) PG(fsi->bufkb), itv), S_VALUE((double) PG(fsj->camkb), (double) PG(fsi->camkb), itv)); } /* Print per-process statistics */ if (GET_PID(act)) { if (dis) { printf("\n%-11s PID minflt/s majflt/s %%user %%system nswap/s", prev_string); if (!disp_avg) printf(" CPU\n"); else printf("\n"); } for (i = 0; i < pid_nr; i++) { if (!pid_stats[curr][i]->pid || !(pid_stats[curr][i]->flag & X_PID_SET)) continue; printf("%-11s %9ld", curr_string, pid_stats[curr][i]->pid); printf(" %9.2f %9.2f %6.2f %6.2f %9.2f", S_VALUE(pid_stats[prev][i]->minflt, pid_stats[curr][i]->minflt, itv), S_VALUE(pid_stats[prev][i]->majflt, pid_stats[curr][i]->majflt, itv), SP_VALUE(pid_stats[prev][i]->utime, pid_stats[curr][i]->utime, itv), SP_VALUE(pid_stats[prev][i]->stime, pid_stats[curr][i]->stime, itv), S_VALUE((long) pid_stats[prev][i]->nswap,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -