📄 sadf.c
字号:
/* * sadf: system activity data formatter * (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 <stdarg.h>#include <unistd.h>#include <time.h>#include <errno.h>#include <sys/param.h> /* for HZ */#include "sadf.h"#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 sadf_actflag = 0;unsigned int flags = 0;unsigned short format = 0; /* Output format */unsigned char irq_bitmap[(NR_IRQS / 8) + 1];unsigned char cpu_bitmap[(NR_CPUS / 8) + 1];int kb_shift = 0;struct file_hdr file_hdr;struct file_stats file_stats[DIM];struct stats_one_cpu *st_cpu[DIM];struct stats_serial *st_serial[DIM];struct stats_irq_cpu *st_irq_cpu[DIM];struct stats_net_dev *st_net_dev[DIM];struct disk_stats *st_disk[DIM];/* Array members of common types are always packed */unsigned int interrupts[DIM][NR_IRQS];struct tm loc_time;/* Contain the date specified by -s and -e options */struct tstamp tm_start, tm_end;char *args[MAX_ARGV_NR];/* *************************************************************************** * Print usage and exit *************************************************************************** */void usage(char *progname){ fprintf(stderr, _("Usage: %s [ options... ] [ <interval> [ <count> ] ] [ <datafile> ]\n" "Options are:\n" "[ -d | -H | -p | -x ] [ -t ] [ -V ]\n" "[ -P { <cpu> | ALL } ] [ -s [ <hh:mm:ss> ] ] [ -e [ <hh:mm:ss> ] ]\n" "[ -- <sar_options...> ]\n"), progname); exit(1);}/* *************************************************************************** * Print tabulations *************************************************************************** */void prtab(int nr_tab){ int i; for (i = 0; i < nr_tab; i++) printf("\t");}/* *************************************************************************** * printf() function modified for XML display *************************************************************************** */void xprintf(short nr_tab, const char *fmt, ...){ static char buf[1024]; va_list args; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); prtab(nr_tab); printf("%s\n", buf);}/* *************************************************************************** * Fill loc_time structure according to time data saved in file. * NB: Option -t is ignored when option -p is used, since option -p * displays its timestamp as a long integer. This is type 'time_t', * which is the number of seconds since 1970 _always_ expressed in UTC. ****************************************************************************/void set_loc_time(short curr){ struct tm *ltm; /* NOTE: loc_time structure must have been init'ed before! */ if (PRINT_TRUE_TIME(flags) && ((format == S_O_DB_OPTION) || (format == S_O_XML_OPTION))) /* '-d -t' or '-x -t' */ ltm = localtime(&file_stats[curr].ust_time); else /* '-p' or '-p -t' or '-d' or '-x' */ ltm = gmtime(&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 */ if (format == S_O_DB_OPTION) { if (PRINT_TRUE_TIME(flags)) strftime(cur_time, len, "%Y-%m-%d %H:%M:%S", &loc_time); else strftime(cur_time, len, "%Y-%m-%d %H:%M:%S UTC", &loc_time); } else if (format == S_O_PPC_OPTION) sprintf(cur_time, "%ld", file_stats[curr].ust_time);}/* *************************************************************************** * cons() - * encapsulate a pair of ints or pair of char * into a static Cons and * return a pointer to it. * * given: t - type of Cons {iv, sv} * arg1 - unsigned long int (if iv), char * (if sv) to become * element 'a' * arg2 - unsigned long int (if iv), char * (if sv) to become * element 'b' * * does: load a static Cons with values using the t parameter to * guide pulling values from the arglist * * return: the address of it's static Cons. If you need to keep * the contents of this Cons, copy it somewhere before calling * cons() against to avoid overwrite. * ie. don't do this: f( cons( iv, i, j ), cons( iv, a, b ) ); *************************************************************************** */static Cons *cons(tcons t, ...){ va_list ap; static Cons c; c.t = t; va_start(ap, t); if (t == iv) { c.a.i = va_arg(ap, unsigned long int); c.b.i = va_arg(ap, unsigned long int); } else { c.a.s = va_arg(ap, char *); c.b.s = va_arg(ap, char *); } va_end(ap); return(&c);}/* *************************************************************************** * render(): * * given: isdb - flag, true if db printing, false if ppc printing * pre - prefix string for output entries * rflags - PT_.... rendering flags * pptxt - printf-format text required for ppc output (may be null) * dbtxt - printf-format text required for db output (may be null) * mid - pptxt/dbtxt format args as a Cons. * luval - %lu printable arg (PT_USEINT must be set) * dval - %.2f printable arg (used unless PT_USEINT is set) * * does: print [pre<sep>]([dbtxt,arg,arg<sep>]|[pptxt,arg,arg<sep>]) \ * (luval|dval)(<sep>|\n) * * return: void. *************************************************************************** */static void render(int isdb, char *pre, int rflags, const char *pptxt, const char *dbtxt, Cons *mid, unsigned long int luval, double dval){ static int newline = 1; const char *txt[] = {pptxt, dbtxt}; char *sep; /* Start a new line? */ if (newline) printf("%s%s", pre, seps[isdb]); /* Terminate this one ? ppc always gets a newline */ newline = ((rflags & PT_NEWLIN) || !isdb); if (txt[isdb]) { /* pp/dbtxt? */ if (mid) { /* Got format args? */ switch(mid->t) { case iv: printf(txt[isdb], mid->a.i, mid->b.i); break; case sv: printf(txt[isdb], mid->a.s, mid->b.s); break; } } else { printf(txt[isdb]); /* No args */ } printf("%s", seps[isdb]); /* Only if something actually got printed */ } sep = (newline) ? "\n" : seps[isdb]; /* How does this rendering end? */ if (rflags & PT_USEINT) { printf("%lu%s", luval, sep); } else { printf("%.2f%s", dval, sep); }}/* *************************************************************************** * write_mech_stats() - * Replace the old write_stats_for_ppc() and write_stats_for_db(), * making it easier for them to remain in sync and print the same data. *************************************************************************** */void write_mech_stats(short curr, unsigned int act, unsigned long dt, unsigned long long itv, unsigned long long g_itv, char *cur_time){ struct file_stats *fsi = &file_stats[curr], *fsj = &file_stats[!curr]; char pre[80]; /* Text at beginning of each line */ int wantproc = !WANT_PER_PROC(flags) || (WANT_PER_PROC(flags) && WANT_ALL_PROC(flags)); int isdb = (format == S_O_DB_OPTION); /* * This substring appears on every output line, preformat it here */ snprintf(pre, 80, "%s%s%ld%s%s", file_hdr.sa_nodename, seps[isdb], dt, seps[isdb], cur_time); if (GET_PROC(act)) { /* The first one as an example */ render(isdb, /* db/ppc flag */ pre, /* the preformatted line leader */ PT_NEWLIN, /* is this the end of a db line? */ "-\tproc/s", /* ppc text */ NULL, /* db text */ NULL, /* db/ppc text format args (Cons *) */ NOVAL, /* %lu value (unused unless PT_USEINT) */ /* and %.2f value, used unless PT_USEINT */ S_VALUE(fsj->processes, fsi->processes, itv)); } if (GET_CTXSW(act)) { render(isdb, pre, PT_NEWLIN, "-\tcswch/s", NULL, NULL, NOVAL, ll_s_value(fsj->context_swtch, fsi->context_swtch, itv)); } if (GET_CPU(act) && wantproc) { render(isdb, pre, PT_NOFLAG, /* that's zero but you know what it means */ "all\t%%user", /* all ppctext is used as format, thus '%%' */ "-1", /* look! dbtext */ NULL, /* no args */ NOVAL, /* another 0, named for readability */ ll_sp_value(fsj->cpu_user, fsi->cpu_user, g_itv)); render(isdb, pre, PT_NOFLAG, "all\t%%nice", NULL, NULL, NOVAL, ll_sp_value(fsj->cpu_nice, fsi->cpu_nice, g_itv)); render(isdb, pre, PT_NOFLAG, "all\t%%system", NULL, NULL, NOVAL, ll_sp_value(fsj->cpu_system, fsi->cpu_system, g_itv)); render(isdb, pre, PT_NOFLAG, "all\t%%iowait", NULL, NULL, NOVAL, ll_sp_value(fsj->cpu_iowait, fsi->cpu_iowait, g_itv)); render(isdb, pre, PT_NOFLAG, "all\t%%steal", NULL, NULL, NOVAL, ll_sp_value(fsj->cpu_steal, fsi->cpu_steal, g_itv)); render(isdb, pre, PT_NEWLIN, "all\t%%idle", NULL, NULL, NOVAL, (fsi->cpu_idle < fsj->cpu_idle) ? 0.0 : ll_sp_value(fsj->cpu_idle, fsi->cpu_idle, g_itv)); } if (GET_CPU(act) && WANT_PER_PROC(flags) && file_hdr.sa_proc) { int i; unsigned long long pc_itv; struct stats_one_cpu *sci = st_cpu[curr], *scj = st_cpu[!curr]; for (i = 0; i <= file_hdr.sa_proc; i++, sci++, scj++) { if (cpu_bitmap[i >> 3] & (1 << (i & 0x07))) { /* Recalculate itv for current proc */ pc_itv = get_per_cpu_interval(sci, scj); render(isdb, pre, PT_NOFLAG, "cpu%d\t%%user", /* ppc text with formatting */ "%d", /* db text with format char */ cons(iv, i, NOVAL), /* how we pass format args */ NOVAL, ll_sp_value(scj->per_cpu_user, sci->per_cpu_user, pc_itv)); render(isdb, pre, PT_NOFLAG, "cpu%d\t%%nice", NULL, cons(iv, i, NOVAL), NOVAL, ll_sp_value(scj->per_cpu_nice, sci->per_cpu_nice, pc_itv)); render(isdb, pre, PT_NOFLAG, "cpu%d\t%%system", NULL, cons(iv, i, NOVAL), NOVAL, ll_sp_value(scj->per_cpu_system, sci->per_cpu_system, pc_itv)); render(isdb, pre, PT_NOFLAG, "cpu%d\t%%iowait", NULL, cons(iv, i, NOVAL), NOVAL, ll_sp_value(scj->per_cpu_iowait, sci->per_cpu_iowait, pc_itv)); render(isdb, pre, PT_NOFLAG, "cpu%d\t%%steal", NULL, cons(iv, i, NOVAL), NOVAL, ll_sp_value(scj->per_cpu_steal, sci->per_cpu_steal, pc_itv)); render(isdb, pre, PT_NEWLIN, "cpu%d\t%%idle", NULL, cons(iv, i, NOVAL), NOVAL, (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) && wantproc) { /* Print number of interrupts per second */ render(isdb, pre, PT_NEWLIN, "sum\tintr/s", "-1", NULL, NOVAL, ll_s_value(fsj->irq_sum, fsi->irq_sum, itv)); } if (GET_ONE_IRQ(act)) { int i; for (i = 0; i < NR_IRQS; i++) { if (irq_bitmap[i >> 3] & (1 << (i & 0x07))) { render(isdb, pre, PT_NEWLIN, "i%03d\tintr/s", "%d", cons(iv, i, NOVAL), NOVAL, S_VALUE(interrupts[!curr][i], interrupts[curr][i], itv)); } } } /* print paging stats */ if (GET_PAGE(act)) { render(isdb, pre, PT_NOFLAG, "-\tpgpgin/s", NULL, NULL, NOVAL, S_VALUE(fsj->pgpgin, fsi->pgpgin, itv)); render(isdb, pre, PT_NOFLAG, "-\tpgpgout/s", NULL, NULL, NOVAL, S_VALUE(fsj->pgpgout, fsi->pgpgout, itv)); render(isdb, pre, PT_NOFLAG, "-\tfault/s", NULL, NULL, NOVAL, S_VALUE(fsj->pgfault, fsi->pgfault, itv)); render(isdb, pre, PT_NEWLIN, "-\tmajflt/s", NULL, NULL, NOVAL, S_VALUE(fsj->pgmajfault, fsi->pgmajfault, itv)); } /* Print number of swap pages brought in and out */ if (GET_SWAP(act)) { render(isdb, pre, PT_NOFLAG, "-\tpswpin/s", NULL, NULL, NOVAL, S_VALUE(fsj->pswpin, fsi->pswpin, itv)); render(isdb, pre, PT_NEWLIN, "-\tpswpout/s", NULL, NULL, NOVAL, S_VALUE(fsj->pswpout, fsi->pswpout, itv)); } /* Print I/O stats (no distinction made between disks) */ if (GET_IO(act)) { render(isdb, pre, PT_NOFLAG, "-\ttps", NULL, NULL, NOVAL, S_VALUE(fsj->dk_drive, fsi->dk_drive, itv)); render(isdb, pre, PT_NOFLAG, "-\trtps", NULL, NULL, NOVAL, S_VALUE(fsj->dk_drive_rio, fsi->dk_drive_rio, itv)); render(isdb, pre, PT_NOFLAG, "-\twtps", NULL, NULL, NOVAL, S_VALUE(fsj->dk_drive_wio, fsi->dk_drive_wio, itv)); render(isdb, pre, PT_NOFLAG, "-\tbread/s", NULL, NULL, NOVAL, S_VALUE(fsj->dk_drive_rblk, fsi->dk_drive_rblk, itv)); render(isdb, pre, PT_NEWLIN, "-\tbwrtn/s", NULL, NULL, NOVAL, S_VALUE(fsj->dk_drive_wblk, fsi->dk_drive_wblk, itv)); } /* Print memory stats */ if (GET_MEMORY(act)) { render(isdb, pre, PT_NOFLAG, "-\tfrmpg/s", NULL, NULL, NOVAL, S_VALUE((double) PG(fsj->frmkb), (double) PG(fsi->frmkb), itv)); render(isdb, pre, PT_NOFLAG, "-\tbufpg/s", NULL, NULL, NOVAL, S_VALUE((double) PG(fsj->bufkb), (double) PG(fsi->bufkb), itv)); render(isdb, pre, PT_NEWLIN, "-\tcampg/s", NULL, NULL, NOVAL, S_VALUE((double) PG(fsj->camkb), (double) PG(fsi->camkb), itv)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -