📄 sa_common.c
字号:
/* * sar and sadf common routines. * (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 <time.h>#include <errno.h>#include <unistd.h> /* For STDOUT_FILENO, among others */#include <dirent.h>#include <fcntl.h>#include <sys/types.h>#include <sys/ioctl.h>#include <sys/param.h> /* for HZ */#include "sa.h"#include "common.h"#include "ioconf.h"#ifdef USE_NLS#include <locale.h>#include <libintl.h>#define _(string) gettext(string)#else#define _(string) (string)#endif/* *************************************************************************** * Init a bitmap (CPU, IRQ, etc.) *************************************************************************** */void init_bitmap(unsigned char bitmap[], unsigned char value, unsigned int nr){ register int i; for (i = 0; i <= nr >> 3; i++) bitmap[i] = value;}/* *************************************************************************** * Init stats structures *************************************************************************** */void init_stats(struct file_stats file_stats[], unsigned int interrupts[][NR_IRQS]){ int i; for (i = 0; i < DIM; i++) { memset(&file_stats[i], 0, FILE_STATS_SIZE); memset(interrupts[i], 0, STATS_ONE_IRQ_SIZE); }}/* *************************************************************************** * Allocate stats_one_cpu structures * (only on SMP machines) *************************************************************************** */void salloc_cpu_array(struct stats_one_cpu *st_cpu[], unsigned int nr_cpu){ int i; for (i = 0; i < DIM; i++) SREALLOC(st_cpu[i], struct stats_one_cpu, STATS_ONE_CPU_SIZE * nr_cpu);}/* *************************************************************************** * Allocate stats_serial structures *************************************************************************** */void salloc_serial_array(struct stats_serial *st_serial[], int nr_serial){ int i; for (i = 0; i < DIM; i++) SREALLOC(st_serial[i], struct stats_serial, STATS_SERIAL_SIZE * nr_serial);}/* *************************************************************************** * Allocate stats_irq_cpu structures *************************************************************************** */void salloc_irqcpu_array(struct stats_irq_cpu *st_irq_cpu[], unsigned int nr_cpus, unsigned int nr_irqcpu){ int i; for (i = 0; i < DIM; i++) SREALLOC(st_irq_cpu[i], struct stats_irq_cpu, STATS_IRQ_CPU_SIZE * nr_cpus * nr_irqcpu);}/* *************************************************************************** * Allocate stats_net_dev structures *************************************************************************** */void salloc_net_dev_array(struct stats_net_dev *st_net_dev[], unsigned int nr_iface){ int i; for (i = 0; i < DIM; i++) SREALLOC(st_net_dev[i], struct stats_net_dev, STATS_NET_DEV_SIZE * nr_iface);}/* *************************************************************************** * Allocate disk_stats structures *************************************************************************** */void salloc_disk_array(struct disk_stats *st_disk[], int nr_disk){ int i; for (i = 0; i < DIM; i++) SREALLOC(st_disk[i], struct disk_stats, DISK_STATS_SIZE * nr_disk);}/* *************************************************************************** * Get device real name if possible. * Warning: This routine may return a bad name on 2.4 kernels where * disk activities are read from /proc/stat. *************************************************************************** */char *get_devname(unsigned int major, unsigned int minor, int pretty){ static char buf[32]; char *name; snprintf(buf, 32, "dev%d-%d", major, minor); if (!pretty) return (buf); if ((name = ioc_name(major, minor)) == NULL) return (buf); return (name);}/* *************************************************************************** * Check if we are close enough to desired interval ****************************************************************************/int next_slice(unsigned long long uptime_ref, unsigned long long uptime, struct file_hdr *file_hdr, int reset, long interval){ unsigned long file_interval, entry; static unsigned long long last_uptime = 0; int min, max, pt1, pt2; double f; if (!last_uptime || reset) last_uptime = uptime_ref; /* Interval cannot be greater than 0xffffffff here */ f = (((double) ((uptime - last_uptime) & 0xffffffff)) / (file_hdr->sa_proc + 1)) / HZ; file_interval = (unsigned long) f; if ((f * 10) - (file_interval * 10) >= 5) file_interval++; /* Rounding to correct value */ last_uptime = uptime; /* * A few notes about the "algorithm" used here to display selected entries * from the system activity file (option -f with -i flag): * Let 'Iu' be the interval value given by the user on the command line, * 'If' the interval between current and previous line in the system * activity file, * and 'En' the nth entry (identified by its time stamp) of the file. * We choose In = [ En - If/2, En + If/2 [ if If is even, * or In = [ En - If/2, En + If/2 ] if not. * En will be displayed if * (Pn * Iu) or (P'n * Iu) belongs to In * with Pn = En / Iu and P'n = En / Iu + 1 */ f = (((double) ((uptime - uptime_ref) & 0xffffffff)) / (file_hdr->sa_proc + 1)) / HZ; entry = (unsigned long) f; if ((f * 10) - (entry * 10) >= 5) entry++; min = entry - (file_interval / 2); max = entry + (file_interval / 2) + (file_interval & 0x1); pt1 = (entry / interval) * interval; pt2 = ((entry / interval) + 1) * interval; return (((pt1 >= min) && (pt1 < max)) || ((pt2 >= min) && (pt2 < max)));}/* *************************************************************************** * Use time stamp to fill tstamp structure *************************************************************************** */int decode_timestamp(char timestamp[], struct tstamp *tse){ timestamp[2] = timestamp[5] = '\0'; tse->tm_sec = atoi(&(timestamp[6])); tse->tm_min = atoi(&(timestamp[3])); tse->tm_hour = atoi(timestamp); if ((tse->tm_sec < 0) || (tse->tm_sec > 59) || (tse->tm_min < 0) || (tse->tm_min > 59) || (tse->tm_hour < 0) || (tse->tm_hour > 23)) return 1; tse->use = TRUE; return 0;}/* *************************************************************************** * Compare two time stamps *************************************************************************** */int datecmp(struct tm *loc_time, struct tstamp *tse){ if (loc_time->tm_hour == tse->tm_hour) { if (loc_time->tm_min == tse->tm_min) return (loc_time->tm_sec - tse->tm_sec); else return (loc_time->tm_min - tse->tm_min); } else return (loc_time->tm_hour - tse->tm_hour);}/* *************************************************************************** * Parse a time stamp entered on the command line (hh:mm:ss) *************************************************************************** */int parse_timestamp(char *argv[], int *opt, struct tstamp *tse, const char *def_timestamp){ char timestamp[9]; if ((argv[++(*opt)]) && (strlen(argv[*opt]) == 8)) strcpy(timestamp, argv[(*opt)++]); else strcpy(timestamp, def_timestamp); return decode_timestamp(timestamp, tse);}/* *************************************************************************** * Set interval value. * g_itv is the interval in jiffies multiplied by the # of proc. * itv is the interval in jiffies. *************************************************************************** */void get_itv_value(struct file_stats *file_stats_curr, struct file_stats *file_stats_prev, unsigned int nr_proc, unsigned long long *itv, unsigned long long *g_itv){ /* Interval value in jiffies */ if (!file_stats_prev->uptime) /* * Stats from boot time to be displayed: only in this case we admit * that the interval (which is unsigned long long) may be greater * than 0xffffffff, else it was an overflow. */ *g_itv = file_stats_curr->uptime; else *g_itv = (file_stats_curr->uptime - file_stats_prev->uptime) & 0xffffffff; if (!(*g_itv)) /* Paranoia checking */ *g_itv = 1; if (nr_proc) { if (!file_stats_prev->uptime0) *itv = file_stats_curr->uptime0; else *itv = (file_stats_curr->uptime0 - file_stats_prev->uptime0) & 0xffffffff; if (!(*itv)) *itv = 1; } else *itv = *g_itv;}/* *************************************************************************** * Print report header *************************************************************************** */void print_report_hdr(unsigned short format, unsigned int flags, struct tm *loc_time, struct file_hdr *file_hdr){ if (PRINT_TRUE_TIME(flags)) { /* Get local time */ get_localtime(loc_time); loc_time->tm_mday = file_hdr->sa_day; loc_time->tm_mon = file_hdr->sa_month; loc_time->tm_year = file_hdr->sa_year; /* * Call mktime() to set DST (Daylight Saving Time) flag. * Has anyone a better way to do it? */ loc_time->tm_hour = loc_time->tm_min = loc_time->tm_sec = 0; mktime(loc_time); } else loc_time = localtime(&(file_hdr->sa_ust_time)); if (!format) /* No output format (we are not using sadf) */ print_gal_header(loc_time, file_hdr->sa_sysname, file_hdr->sa_release, file_hdr->sa_nodename);}/* *************************************************************************** * Network interfaces may now be registered (and unregistered) dynamically. * This is what we try to guess here. *************************************************************************** */unsigned int check_iface_reg(struct file_hdr *file_hdr, struct stats_net_dev *st_net_dev[], short curr, short ref, unsigned int pos){ struct stats_net_dev *st_net_dev_i, *st_net_dev_j; unsigned int index = 0; st_net_dev_i = st_net_dev[curr] + pos; while (index < file_hdr->sa_iface) { st_net_dev_j = st_net_dev[ref] + index; if (!strcmp(st_net_dev_i->interface, st_net_dev_j->interface)) { /* * Network interface found. * If a counter has decreased, then we may assume that the * corresponding interface was unregistered, then registered again. */ if ((st_net_dev_i->rx_packets < st_net_dev_j->rx_packets) || (st_net_dev_i->tx_packets < st_net_dev_j->tx_packets) || (st_net_dev_i->rx_bytes < st_net_dev_j->rx_bytes) || (st_net_dev_i->tx_bytes < st_net_dev_j->tx_bytes) || (st_net_dev_i->rx_compressed < st_net_dev_j->rx_compressed) || (st_net_dev_i->tx_compressed < st_net_dev_j->tx_compressed) || (st_net_dev_i->multicast < st_net_dev_j->multicast) || (st_net_dev_i->rx_errors < st_net_dev_j->rx_errors) || (st_net_dev_i->tx_errors < st_net_dev_j->tx_errors) || (st_net_dev_i->collisions < st_net_dev_j->collisions) || (st_net_dev_i->rx_dropped < st_net_dev_j->rx_dropped) || (st_net_dev_i->tx_dropped < st_net_dev_j->tx_dropped) || (st_net_dev_i->tx_carrier_errors < st_net_dev_j->tx_carrier_errors) || (st_net_dev_i->rx_frame_errors < st_net_dev_j->rx_frame_errors) || (st_net_dev_i->rx_fifo_errors < st_net_dev_j->rx_fifo_errors) || (st_net_dev_i->tx_fifo_errors < st_net_dev_j->tx_fifo_errors)) { /* * Special processing for rx_bytes (_packets) and tx_bytes (_packets) * counters: If the number of bytes (packets) has decreased, whereas * the number of packets (bytes) has increased, then assume that the * relevant counter has met an overflow condition, and that the * interface was not unregistered, which is all the more plausible * that the previous value for the counter was > ULONG_MAX/2. * NB: the average value displayed will be wrong in this case... * * If such an overflow is detected, just set the flag. There is no * need to handle this in a special way: the difference is still * properly calculated if the result is of the same type (i.e. * unsigned long) as the two values. */ int ovfw = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -