diff --git a/packages/6.8/nmon-16m-x86_64-1_SBo.txz b/packages/6.8/nmon-16m-x86_64-1_SBo.txz
new file mode 100644
index 00000000..726aad40
Binary files /dev/null and b/packages/6.8/nmon-16m-x86_64-1_SBo.txz differ
diff --git a/packages/6.9/nmon-16m-x86_64-1_SBo.txz b/packages/6.9/nmon-16m-x86_64-1_SBo.txz
new file mode 100644
index 00000000..726aad40
Binary files /dev/null and b/packages/6.9/nmon-16m-x86_64-1_SBo.txz differ
diff --git a/source/SlackBuild/nmon/README.md b/source/SlackBuild/nmon/README.md
new file mode 100644
index 00000000..ed8c0b28
--- /dev/null
+++ b/source/SlackBuild/nmon/README.md
@@ -0,0 +1,13 @@
+## README for nmon
+
+- http://nmon.sourceforge.net/pmwiki.php?n=Site.CompilingNmon has the .c source files. It ALSO has a makefile that includes ARM and X86 and X86_64 compilation flag options.
+ - Ncurses needs to be installed. I'm using Slackware-current, which has `ncurses-6.2_20201024-x86_64-1.txz`. It also calls for GCC, so I have `gcc-10.2.0-x86_64-2.txz` installed. Finally, I have `make-4.2.1-x86_64-7.txz` installed, though I guess if I'm calling GCC directly, it's perhaps not necessary
+- https://slackbuilds.org/repository/14.2/system/nmon/ has a SlackBuild file, but was made for version 14i which is at least older than April 2015 (nmon15c was released).
+ - The GCC flags are a little out of date in comparison to the makefile, so I copied/merged the flags over. (The changelog notes the deprecation of some of these flags, such as -D LARGEMEM and JFS and GETUSER).
+ - NOTE: I did this on an X86_64 system and did not update the compile flags in the SlackBuild for other architectures.
+ - The SlackBuild also has scatterings of hardcoded version numbers, which I updated to be generic `lmon.c` as it is in the makefile.
+ - I also increased the set flags for more verbose output.
+ - Finally, the output was changed from `tgz` to `txz`
+- There was a "bug" in the 16m release of nmon where the version number string wasn't bumped from "16k" to "16m". I changed that string so the nmon executable properly shows that it is version 16m.
+- I copied the compiled `nmon-16m-x86_64-1_SBo.txz` file to Unraid 6.8.3 and 6.9-rc1 systems and confirmed that after `installpkg nmon-16m-x86_64-1_SBo.txz` I was able to call `nmon` and start up the utility without issue
+ - I thought Ncurses might need to be installed on Unraid for this to work, but it seems to only be needed at compile time.
diff --git a/source/SlackBuild/nmon/lmon16m.c b/source/SlackBuild/nmon/lmon16m.c
new file mode 100644
index 00000000..982838fd
--- /dev/null
+++ b/source/SlackBuild/nmon/lmon16m.c
@@ -0,0 +1,8584 @@
+/*
+ * lmon.c -- Curses based Performance Monitor for Linux
+ * with saving performance stats to a CSV file mode.
+ * Developer: Nigel Griffiths.
+ * (C) Copyright 2009 Nigel Griffiths
+
+ 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 3 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 even 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, see .
+ */
+
+/*
+ * Use the following Makefile (for Linux on POWER)
+CFLAGS=-g -Wall -D POWER
+LDFLAGS=-lcurses -lm
+nmon: lmon.o
+ * end of Makefile
+ */
+/* Other #ifdef's for specific features or platforms
+Platforms: POWER MAINFRAME X86 ARM - Mandatory one of these at a time
+Specific Linux versions: RHEL7 SLES113 SLES12
+Specific feature: NVIDIA_GPU
+Bug / missing feature workarounds:
+ REREAD - for RHEL3
+ LSBLK_NO_TYPE - SLES11.3 has not lsblk disk TYPE option
+
+Options which should always but switched on:
+SMALLMEM - removes huge memory, dirty, whritebak, mapped, slab, pagethreads as not in older kernels
+PRE_KERNEL_2_6_18 1 kernel levels before removed the following to the disk stats
+ pi_num_threads,
+ pi_rt_priority,
+ pi_policy,
+ pi_delayacct_blkio_ticks
+*/
+
+/* note: RAW assumes you are using the index "i" to select the CPU */
+#define RAW(member) (long)((long)(p->cpuN[i].member) - (long)(q->cpuN[i].member))
+#define RAWTOTAL(member) (long)((long)(p->cpu_total.member) - (long)(q->cpu_total.member))
+
+#define VERSION "16m"
+char version[] = VERSION;
+static char *SccsId = "nmon " VERSION;
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Windows moved here so they can be cleared when the screen mode changes */
+WINDOW *padwelcome = NULL;
+WINDOW *padtop = NULL;
+WINDOW *padmem = NULL;
+WINDOW *padlarge = NULL;
+WINDOW *padpage = NULL;
+WINDOW *padker = NULL;
+WINDOW *padnet = NULL;
+WINDOW *padneterr = NULL;
+WINDOW *padnfs = NULL;
+WINDOW *padres = NULL;
+WINDOW *padsmp = NULL;
+WINDOW *padutil = NULL;
+WINDOW *padwide = NULL;
+WINDOW *padgpu = NULL;
+WINDOW *padmhz = NULL;
+WINDOW *padlong = NULL;
+WINDOW *paddisk = NULL;
+WINDOW *paddg = NULL;
+WINDOW *padmap = NULL;
+WINDOW *padjfs = NULL;
+#ifdef POWER
+WINDOW *padlpar = NULL;
+#endif
+WINDOW *padverb = NULL;
+WINDOW *padhelp = NULL;
+
+
+/* for Disk Busy rain style output covering 100's of diskss on one screen */
+const char disk_busy_map_ch[] =
+ "_____.....----------++++++++++oooooooooo0000000000OOOOOOOOOO8888888888XXXXXXXXXX##########@@@@@@@@@@*";
+/*"00000555551111111111222222222233333333334444444444555555555566666666667777777777888888888899999999991"*/
+
+int extended_disk = 0; /* report additional data from /proc/diskstats to spreadsheet output */
+
+#define FLIP(variable) if(variable) variable=0; else variable=1;
+
+#ifdef MALLOC_DEBUG
+#define MALLOC(argument) mymalloc(argument,__LINE__)
+#define FREE(argument) myfree(argument,__LINE__)
+#define REALLOC(argument1,argument2) myrealloc(argument1,argument2,__LINE__)
+void *mymalloc(int size, int line)
+{
+ void *ptr;
+ ptr = malloc(size);
+ fprintf(stderr, "0x%x = malloc(%d) at line=%d\n", ptr, size, line);
+ return ptr;
+}
+
+void myfree(void *ptr, int line)
+{
+ fprintf(stderr, "free(0x%x) at line=%d\n", ptr, line);
+ free(ptr);
+}
+
+void *myrealloc(void *oldptr, int size, int line)
+{
+ void *ptr;
+ ptr = realloc(oldptr, size);
+ fprintf(stderr, "0x%x = realloc(0x%x, %d) at line=%d\n", ptr, oldptr,
+ size, line);
+ return ptr;
+}
+#else
+#define MALLOC(argument) malloc(argument)
+#define FREE(argument) free(argument)
+#define REALLOC(argument1,argument2) realloc(argument1,argument2)
+#endif /* MALLOC STUFF */
+
+#ifdef NVIDIA_GPU
+typedef int nvmlReturn_t;
+#define NVML_SUCCESS 0
+
+typedef struct nvmlUtilization_st {
+ unsigned int gpu;
+ unsigned int memory;
+} nvmlUtilization_t;
+
+struct nvmlDevice_st;
+typedef struct nvmlDevice_st *nvmlDevice_t;
+
+nvmlReturn_t nvmlInit(void);
+nvmlReturn_t nvmlShutdown(void);
+nvmlReturn_t nvmlDeviceGetCount(unsigned int *count);
+nvmlReturn_t nvmlDeviceGetHandleByIndex(unsigned int index,
+ nvmlDevice_t * device);
+nvmlReturn_t nvmlDeviceGetUtilizationRates(nvmlDevice_t device,
+ nvmlUtilization_t *
+ utilization);
+nvmlReturn_t nvmlSystemGetDriverVersion(char *version, int count);
+nvmlReturn_t nvmlSystemGetNVMLVersion(char *version, int count);
+nvmlReturn_t nvmlDeviceGetName(nvmlDevice_t device, char *name, int count);
+nvmlReturn_t nvmlDeviceGetTemperature(nvmlDevice_t device, int type,
+ unsigned int *temp);
+nvmlReturn_t nvmlDeviceGetPowerUsage(nvmlDevice_t device,
+ unsigned int *watts);
+nvmlReturn_t nvmlDeviceGetClockInfo(nvmlDevice_t device, int type,
+ unsigned int *mhz);
+
+#define NVML_TEMPERATURE_GPU 0
+#define NVML_CLOCK_GRAPHICS 0
+
+nvmlDevice_t gpu_device[4];
+nvmlUtilization_t gpu_util[4];
+unsigned int gpu_devices;
+char gpu_name[4][1024];
+unsigned int gpu_temp[4];
+unsigned int gpu_watts[4];
+unsigned int gpu_clock[4];
+char gpu_driver_version[1024];
+char gpu_nvml_version[1024];
+int first_time_gpu = 1;
+
+void gpu_init()
+{
+ int i;
+ nvmlReturn_t nvres;
+ if ((nvres = nvmlInit()) != NVML_SUCCESS) {
+ printf("nvmlInit failed %d\n", nvres);
+ return;
+ }
+
+ if ((nvres =
+ nvmlSystemGetDriverVersion(&gpu_driver_version[0],
+ 1024)) != NVML_SUCCESS) {
+ printf("nvmlSystemGetDriverVersion failed %d\n", nvres);
+ return;
+ }
+ if ((nvres =
+ nvmlSystemGetNVMLVersion(&gpu_nvml_version[0],
+ 1024)) != NVML_SUCCESS) {
+ printf("nvmlSystemGetDriverVersion failed %d\n", nvres);
+ return;
+ }
+
+ if ((nvres = nvmlDeviceGetCount(&gpu_devices)) != NVML_SUCCESS) {
+ printf("nvmlDeviceGetCount failed %d\n", nvres);
+ return;
+ }
+ if (gpu_devices > 4)
+ gpu_devices = 4;
+
+ for (i = 0; i < gpu_devices; i++) {
+ if (nvmlDeviceGetHandleByIndex(i, &gpu_device[i]) != NVML_SUCCESS) {
+ printf("nvmlDeviceGetHandleByIndex(%d) failed %d\n", i, nvres);
+ return;
+ }
+ }
+}
+#endif /* NVIDIA_GPU */
+
+#define P_CPUINFO 0
+#define P_STAT 1
+#define P_VERSION 2
+#define P_MEMINFO 3
+#define P_UPTIME 4
+#define P_LOADAVG 5
+#define P_NFS 6
+#define P_NFSD 7
+#define P_VMSTAT 8 /* new in 13h */
+#define P_NUMBER 9 /* one more than the max */
+
+char *month[12] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
+ "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
+};
+
+/* Cut of everything after the first space in callback
+ * Delete any '&' just before the space
+ */
+char *check_call_string(char *callback, const char *name)
+{
+ char *tmp_ptr = callback;
+
+ if (strlen(callback) > 256) {
+ fprintf(stderr, "ERROR nmon: ignoring %s - too long\n", name);
+ return (char *) NULL;
+ }
+
+ for (; *tmp_ptr != '\0' && *tmp_ptr != ' ' && *tmp_ptr != '&';
+ ++tmp_ptr);
+
+ *tmp_ptr = '\0';
+
+ if (tmp_ptr == callback)
+ return (char *) NULL;
+ else
+ return callback;
+}
+
+/* Remove error output to this buffer and display it if NMONDEBUG=1 */
+char errorstr[70];
+int error_on = 0;
+void error(char *err)
+{
+ strncpy(errorstr, err, 69);
+ errorstr[69] = 0;
+}
+
+/*
+ * lscpu command output save
+*/
+int lscpu_available = 0;
+
+struct {
+ char *arch;
+ char *byte_order;
+#define ORDER_UNKNOWN 0
+#define ORDER_LITTLE 1
+#define ORDER_BIG 2
+ int order;
+ int cpus;
+ char *cpu_online;
+ char *cpu_offline;
+ int threads;
+ int cores;
+ int sockets;
+ int numa_nodes;
+ char *model;
+ char *model_name;
+ int mhz;
+ int mhz_min;
+ int mhz_max;
+} lscpu;
+
+void lscpu_init()
+{
+ FILE *pop;
+ int len;
+ int data_col = 21;
+#define LSCPU_STRLEN 512
+ char tmpstr[LSCPU_STRLEN + 1];
+
+ if (lscpu_available == 1)
+ return;
+ pop = popen("/usr/bin/lscpu 2>/dev/null", "r");
+ if (pop != NULL) {
+ lscpu_available = 1;
+ tmpstr[0] = 0;
+ while (fgets(tmpstr, LSCPU_STRLEN, pop) != NULL) {
+ tmpstr[strlen(tmpstr) - 1] = 0; /* remove newline */
+ if (strncmp("Architecture:", tmpstr, strlen("Architecture:")) == 0) {
+
+ /* Architecture: SOMETHING OR OTHER
+ 0123456789012345678901
+ |-> ^ */
+ /* start from char after the : looking for some leters or numbers */
+ len = strlen(tmpstr);
+ for(data_col=14;data_col
+
+struct procsinfo {
+ int pi_pid;
+ char pi_comm[64];
+ char pi_state;
+ int pi_ppid;
+ int pi_pgrp;
+ int pi_session;
+ int pi_tty_nr;
+ int pi_tty_pgrp;
+ unsigned long pi_flags;
+ unsigned long pi_minflt;
+ unsigned long pi_cmin_flt;
+ unsigned long pi_majflt;
+ unsigned long pi_cmaj_flt;
+ unsigned long pi_utime;
+ unsigned long pi_stime;
+ long pi_cutime;
+ long pi_cstime;
+ long pi_pri;
+ long pi_nice;
+#ifdef PRE_KERNEL_2_6_18
+ long junk /* removed */ ;
+#else
+ long pi_num_threads;
+#endif
+ long pi_it_real_value;
+ unsigned long pi_start_time;
+ unsigned long pi_vsize;
+ long pi_rss; /* - 3 */
+ unsigned long pi_rlim_cur;
+ unsigned long pi_start_code;
+ unsigned long pi_end_code;
+ unsigned long pi_start_stack;
+ unsigned long pi_esp;
+ unsigned long pi_eip;
+ /* The signal information here is obsolete. */
+ unsigned long pi_pending_signal;
+ unsigned long pi_blocked_sig;
+ unsigned long pi_sigign;
+ unsigned long pi_sigcatch;
+ unsigned long pi_wchan;
+ unsigned long pi_nswap;
+ unsigned long pi_cnswap;
+ int pi_exit_signal;
+ int pi_cpu;
+#ifndef PRE_KERNEL_2_6_18
+ unsigned long pi_rt_priority;
+ unsigned long pi_policy;
+ unsigned long long pi_delayacct_blkio_ticks;
+#endif
+ unsigned long statm_size; /* total program size */
+ unsigned long statm_resident; /* resident set size */
+ unsigned long statm_share; /* shared pages */
+ unsigned long statm_trs; /* text (code) */
+ unsigned long statm_drs; /* data/stack */
+ unsigned long statm_lrs; /* library */
+ unsigned long statm_dt; /* dirty pages */
+
+ unsigned long long read_io; /* storage read bytes */
+ unsigned long long write_io; /* storage write bytes */
+};
+int isroot = 0;
+
+#include
+#include
+#include
+#include
+#include
+
+int debug = 0;
+time_t timer; /* used to work out the hour/min/second */
+
+/* Counts of resources */
+int cpus = 1; /* number of CPUs in system (lets hope its more than zero!) */
+#if X86 || ARM
+int cores = 0;
+int siblings = 0;
+int processorchips = 0;
+int hyperthreads = 0;
+char *vendor_ptr = "not-set";
+char *model_ptr = "not-set";
+char *mhz_ptr = "not-set";
+char *bogo_ptr = "not-set";
+#endif
+int old_cpus = 1; /* Number of CPU seen in previuos interval */
+int max_cpus = 1; /* highest number of CPUs in DLPAR */
+int networks = 0; /* number of networks in system */
+int partitions = 0; /* number of partitions in system */
+int partitions_short = 0; /* partitions file data short form (i.e. data missing) */
+int disks = 0; /* number of disks in system */
+int seconds = -1; /* pause interval */
+int maxloops = -1; /* stop after this number of updates */
+char hostname[256];
+char run_name[256];
+int run_name_set = 0;
+char fullhostname[256];
+int loop;
+
+#define DPL 150 /* Disks per line for file output to ensure it
+ does not overflow the spreadsheet input line max */
+
+int disks_per_line = DPL;
+
+#define NEWDISKGROUP(disk) ( (disk) % disks_per_line == 0)
+
+/* Mode of output variables */
+int show_aaa = 1;
+int show_para = 1;
+int show_headings = 1;
+int show_res = 0;
+int show_smp = 0;
+int show_util = 0;
+int first_util = 1;
+int show_wide = 0;
+int show_gpu = 0;
+int show_mhz = 0;
+int show_longterm = 0;
+int show_disk = 0;
+#define SHOW_DISK_NONE 0
+#define SHOW_DISK_STATS 1
+#define SHOW_DISK_GRAPH 2
+int show_diskmap = 0;
+int show_memory = 0;
+int show_large = 0;
+int show_kernel = 0;
+int show_nfs = 0;
+int show_net = 0;
+int show_neterror = 0;
+int show_help = 0;
+int show_top = 0;
+int show_topmode = 1;
+#define ARGS_NONE 0
+#define ARGS_ONLY 1
+int show_args = 0;
+int show_all = 1; /* 1=all procs& disk 0=only if 1% or more busy */
+int show_verbose = 0;
+int show_jfs = 0;
+int show_jfs_minimum = 0;
+int flash_on = 0;
+int first_huge = 1;
+int first_steal = 1;
+long huge_peak = 0;
+int welcome = 1;
+int dotline = 0;
+int show_rrd = 0;
+int show_lpar = 0;
+int show_vm = 0;
+int show_dgroup = 0; /* disk groups */
+int auto_dgroup = 0; /* disk groups defined via -g auto */
+int disk_only_mode = 0; /* disk stats shows disks only if user used -g auto */
+int dgroup_loaded = 0; /* 0 = no, 1=needed, 2=loaded */
+
+#define RRD if(show_rrd)
+
+double ignore_procdisk_threshold = 0.1;
+double ignore_io_threshold = 0.1;
+/* Curses support */
+#define CURSE if(cursed) /* Only use this for single line curses calls */
+#define COLOUR if(colour) /* Only use this for single line colour curses calls */
+int cursed = 1; /* 1 = using curses and
+ 0 = loging output for a spreadsheet */
+int colour = 1; /* 1 = using colour curses and
+ 0 = using black and white curses (see -b flag) */
+#define MVPRINTW(row,col,string) {move((row),(col)); \
+ attron(A_STANDOUT); \
+ printw(string); \
+ attroff(A_STANDOUT); }
+FILE *fp; /* filepointer for spreadsheet output */
+
+
+char *timestamp(int loop, time_t eon)
+{
+ static char string[64];
+ if (show_rrd)
+ snprintf(string, 64, "%ld", (long) eon);
+ else
+ snprintf(string, 64, "T%04d", loop);
+ return string;
+}
+
+#define LOOP timestamp(loop,timer)
+
+char *easy[5] = { "not found", 0, 0, 0, 0 };
+char *lsb_release[5] = { "not found", 0, 0, 0, 0 };
+
+void find_release()
+{
+ FILE *pop;
+ int i;
+ char tmpstr[1024+1];
+
+#if defined(SLES12) || defined(SLES15)
+ pop = popen("cat /etc/os-release 2>/dev/null", "r");
+#else
+ pop = popen("cat /etc/*ease 2>/dev/null", "r");
+#endif /* SLES12 */
+ if (pop != NULL) {
+ tmpstr[0] = 0;
+ for (i = 0; i < 4; i++) {
+ if (fgets(tmpstr, 1024, pop) == NULL)
+ break;
+ tmpstr[strlen(tmpstr) - 1] = 0; /* remove newline */
+ easy[i] = MALLOC(strlen(tmpstr) + 1);
+ strcpy(easy[i], tmpstr);
+ }
+ pclose(pop);
+ }
+ pop = popen("/usr/bin/lsb_release -idrc 2>/dev/null", "r");
+ if (pop != NULL) {
+ tmpstr[0] = 0;
+ for (i = 0; i < 4; i++) {
+ if (fgets(tmpstr, 70, pop) == NULL)
+ break;
+ tmpstr[strlen(tmpstr) - 1] = 0; /* remove newline */
+ lsb_release[i] = MALLOC(strlen(tmpstr) + 1);
+ strcpy(lsb_release[i], tmpstr);
+ }
+ pclose(pop);
+ }
+}
+
+
+
+/* Full Args Mode stuff here */
+
+#define ARGSMAX 1024*8
+#define CMDLEN 4096
+
+struct {
+ int pid;
+ char *args;
+} arglist[ARGSMAX];
+
+void args_output(int pid, int loop, char *progname)
+{
+ FILE *pop;
+ int i, j, n;
+ char tmpstr[CMDLEN];
+ static int arg_first_time = 1;
+
+ if (pid == 0)
+ return; /* ignore init */
+ for (i = 0; i < ARGSMAX - 1; i++) { /* clear data out */
+ if (arglist[i].pid == pid) {
+ return;
+ }
+ if (arglist[i].pid == 0) /* got to empty slot */
+ break;
+ }
+ snprintf(tmpstr, CMDLEN, "ps -p %d -o args 2>/dev/null", pid);
+ pop = popen(tmpstr, "r");
+ if (pop == NULL) {
+ return;
+ } else {
+ if (fgets(tmpstr, CMDLEN, pop) == NULL) { /* throw away header */
+ pclose(pop);
+ return;
+ }
+ tmpstr[0] = 0;
+ if (fgets(tmpstr, CMDLEN, pop) == NULL) {
+ pclose(pop);
+ return;
+ }
+ tmpstr[strlen(tmpstr) - 1] = 0;
+ if (tmpstr[strlen(tmpstr) - 1] == ' ')
+ tmpstr[strlen(tmpstr) - 1] = 0;
+ arglist[i].pid = pid;
+ if (arg_first_time) {
+ fprintf(fp, "UARG,+Time,PID,ProgName,FullCommand\n");
+ arg_first_time = 0;
+ }
+ n = strlen(tmpstr);
+ for (i = 0; i < n; i++) {
+ /*strip out stuff that confused Excel i.e. starting with maths symbol */
+ if (tmpstr[i] == ',' &&
+ ((tmpstr[i + 1] == '-') || tmpstr[i + 1] == '+'))
+ tmpstr[i + 1] = '_';
+ /*strip out double spaces */
+ if (tmpstr[i] == ' ' && tmpstr[i + 1] == ' ') {
+ for (j = 0; j < n - i; j++)
+ tmpstr[i + j] = tmpstr[i + j + 1];
+ i--; /* rescan to remove triple space etc */
+ }
+ }
+
+ fprintf(fp, "UARG,%s,%07d,%s,%s\n", LOOP, pid, progname, tmpstr);
+ pclose(pop);
+ return;
+ }
+}
+
+void args_load()
+{
+ FILE *pop;
+ int i;
+ char tmpstr[CMDLEN];
+
+ for (i = 0; i < ARGSMAX; i++) { /* clear data out */
+ if (arglist[i].pid == -1)
+ break;
+ if (arglist[i].pid != 0) {
+ arglist[i].pid = -1;
+ free(arglist[i].args);
+ }
+ }
+ pop = popen("ps -eo pid,args 2>/dev/null", "r");
+ if (pop == NULL) {
+ return;
+ } else {
+ if (fgets(tmpstr, CMDLEN, pop) == NULL) { /* throw away header */
+ pclose(pop);
+ return;
+ }
+ for (i = 0; i < ARGSMAX; i++) {
+ tmpstr[0] = 0;
+ if (fgets(tmpstr, CMDLEN, pop) == NULL) {
+ pclose(pop);
+ return;
+ }
+ tmpstr[strlen(tmpstr) - 1] = 0;
+ if (tmpstr[strlen(tmpstr) - 1] == ' ')
+ tmpstr[strlen(tmpstr) - 1] = 0;
+ arglist[i].pid = atoi(tmpstr);
+ arglist[i].args = MALLOC(strlen(tmpstr) + 1);
+ strcpy(arglist[i].args, &tmpstr[6]);
+ }
+ pclose(pop);
+ }
+}
+
+char *args_lookup(int pid, char *progname)
+{
+ int i;
+ for (i = 0; i < ARGSMAX; i++) {
+ if (arglist[i].pid == pid)
+ return arglist[i].args;
+ if (arglist[i].pid == -1)
+ return progname;
+ }
+ return progname;
+}
+
+/* end args mode stuff here */
+
+void linux_bbbp(char *name, char *cmd, char *err)
+{
+ int i;
+ int j;
+ int len;
+#define STRLEN 4096
+ char str[STRLEN];
+ FILE *pop;
+ static int lineno = 0;
+
+ pop = popen(cmd, "r");
+ if (pop == NULL) {
+ fprintf(fp, "BBBP,%03d,%s failed to run %s\n", lineno++, cmd, err);
+ } else {
+ fprintf(fp, "BBBP,%03d,%s\n", lineno++, name);
+ for (i = 0; i < 2048 && (fgets(str, STRLEN, pop) != NULL); i++) { /* 2048=sanity check only */
+ len = strlen(str);
+ if (len > STRLEN)
+ len = STRLEN;
+ if (str[len - 1] == '\n') /*strip off the newline */
+ str[len - 1] = 0;
+ /* fix text starting characters that confuses spread sheets */
+ if (str[0] == '+')
+ str[0] = 'p';
+ if (str[0] == '*')
+ str[0] = 'm';
+ if (str[0] == '-')
+ str[0] = 'n';
+ if (str[0] == '/')
+ str[0] = 'd';
+ if (str[0] == '=')
+ str[0] = 'e';
+ /* remove double quotes as it confuses spread sheets */
+ for (j = 0; str[j] != 0; j++)
+ if (str[j] == '"')
+ str[j] = 'Q';
+ fprintf(fp, "BBBP,%03d,%s,\"%s\"\n", lineno++, name, str);
+ }
+ pclose(pop);
+ }
+}
+
+#define WARNING "needs root permission or file not present"
+
+/* Global name of programme for printing it */
+char *progname;
+
+/* Seconds since epoc and the sting version */
+long long boottime = 0;
+char boottime_str[64] = "not found";
+/* Main data structure for collected stats.
+ * Two versions are previous and current data.
+ * Often its the difference that is printed.
+ * The pointers are swaped i.e. current becomes the previous
+ * and the previous over written rather than moving data around.
+ */
+struct cpu_stat { /* changed the order here to match this years kernel (man 5 /proc/stat) */
+ long long user;
+ long long nice;
+ long long sys;
+ long long idle;
+ long long wait; /* for IO */
+ long long irq;
+ long long softirq;
+ long long steal;
+ long long guest;
+ long long guest_nice;
+ /* below are non-cpu based numbers in the same file */
+ long long intr;
+ long long ctxt;
+ long long procs;
+ long long running;
+ long long blocked;
+ float uptime;
+ float idletime;
+ float mins1;
+ float mins5;
+ float mins15;
+};
+
+#define ulong unsigned long
+struct dsk_stat {
+ char dk_name[32];
+ int dk_major;
+ int dk_minor;
+ long dk_noinfo;
+ ulong dk_reads;
+ ulong dk_rmerge;
+ ulong dk_rmsec;
+ ulong dk_rkb;
+ ulong dk_writes;
+ ulong dk_wmerge;
+ ulong dk_wmsec;
+ ulong dk_wkb;
+ ulong dk_xfers;
+ ulong dk_bsize;
+ ulong dk_time;
+ ulong dk_inflight;
+ ulong dk_backlog;
+ ulong dk_partition;
+ ulong dk_blocks; /* in /proc/partitions only */
+ ulong dk_use;
+ ulong dk_aveq;
+};
+
+struct mem_stat {
+ long memtotal;
+ long memfree;
+ long memshared;
+ long buffers;
+ long cached;
+ long swapcached;
+ long active;
+ long inactive;
+ long hightotal;
+ long highfree;
+ long lowtotal;
+ long lowfree;
+ long swaptotal;
+ long swapfree;
+#ifndef SMALLMEM
+ long dirty;
+ long writeback;
+ long mapped;
+ long slab;
+ long committed_as;
+ long pagetables;
+ long hugetotal;
+ long hugefree;
+ long hugesize;
+#else
+ long bigfree;
+#endif /*SMALLMEM*/
+};
+
+struct vm_stat {
+ long long nr_dirty;
+ long long nr_writeback;
+ long long nr_unstable;
+ long long nr_page_table_pages;
+ long long nr_mapped;
+ long long nr_slab;
+ long long nr_slab_reclaimable;
+ long long nr_slab_unreclaimable;
+ long long pgpgin;
+ long long pgpgout;
+ long long pswpin;
+ long long pswpout;
+ long long pgalloc_high;
+ long long pgalloc_normal;
+ long long pgalloc_dma;
+ long long pgfree;
+ long long pgactivate;
+ long long pgdeactivate;
+ long long pgfault;
+ long long pgmajfault;
+ long long pgrefill_high;
+ long long pgrefill_normal;
+ long long pgrefill_dma;
+ long long pgsteal_high;
+ long long pgsteal_normal;
+ long long pgsteal_dma;
+ long long pgscan_kswapd_high;
+ long long pgscan_kswapd_normal;
+ long long pgscan_kswapd_dma;
+ long long pgscan_direct_high;
+ long long pgscan_direct_normal;
+ long long pgscan_direct_dma;
+ long long pginodesteal;
+ long long slabs_scanned;
+ long long kswapd_steal;
+ long long kswapd_inodesteal;
+ long long pageoutrun;
+ long long allocstall;
+ long long pgrotated;
+};
+
+
+#define NFS_V2_NAMES_COUNT 18
+char *nfs_v2_names[NFS_V2_NAMES_COUNT] = {
+ "null", "getattr", "setattr", "root", "lookup", "readlink",
+ "read", "wrcache", "write", "create", "remove", "rename",
+ "link", "symlink", "mkdir", "rmdir", "readdir", "fsstat"
+};
+
+#define NFS_V3_NAMES_COUNT 22
+char *nfs_v3_names[22] = {
+ "null", "getattr", "setattr", "lookup", "access", "readlink",
+ "read", "write", "create", "mkdir", "symlink", "mknod",
+ "remove", "rmdir", "rename", "link", "readdir", "readdirplus",
+ "fsstat", "fsinfo", "pathconf", "commit"
+};
+
+#define NFS_V4S_NAMES_COUNT 72
+int nfs_v4s_names_count = NFS_V4S_NAMES_COUNT;
+char *nfs_v4s_names[NFS_V4S_NAMES_COUNT] = { /* get these names from nfsstat as they are NOT documented */
+ "op0-unused", "op1-unused", "op2-future", "access", "close", "commit", /* 1 - 6 */
+ "create", "delegpurge", "delegreturn", "getattr", "getfh", "link", /* 7 - 12 */
+ "lock", "lockt", "locku", "lookup", "lookup_root", "nverify", /* 13 - 18 */
+ "open", "openattr", "open_conf", "open_dgrd", "putfh", "putpubfh", /* 19 - 24 */
+ "putrootfh", "read", "readdir", "readlink", "remove", "rename", /* 25 - 30 */
+ "renew", "restorefh", "savefh", "secinfo", "setattr", "setcltid", /* 31 - 36 */
+ "setcltidconf", "verify", "write", "rellockowner", "bc_ctl", "blind_conn", /* 37 - 42 */
+ "exchange_id", "create_ses", "destroy_ses", "free_statid", "getdirdelag", "getdevinfo", /* 43 - 48 */
+ "getdevlist", "layoutcommit", "layoutget", "layoutreturn", "secunfononam", "sequence", /* 49 - 54 */
+ "set_ssv", "test_stateid", "want_deleg", "destory_clid", "reclaim_comp", "stat60", /* 55 - 60 */
+ "stat61", "stat62", "stat63", "stat64", "stat65", "stat66", /* 61 - 66 */
+ "stat67", "stat68", "stat69", "stat70", "stat71", "stat72" /* 67 - 72 */
+};
+
+#define NFS_V4C_NAMES_COUNT 60
+int nfs_v4c_names_count = NFS_V4C_NAMES_COUNT;
+char *nfs_v4c_names[NFS_V4C_NAMES_COUNT] = { /* get these names from nfsstat as they are NOT documented */
+ "null", "read", "write", "commit", "open", "open_conf", /* 1 - 6 */
+ "open_noat", "open_dgrd", "close", "setattr", "fsinfo", "renew", /* 7 - 12 */
+ "setclntid", "confirm", "lock", "lockt", "locku", "access", /* 13 - 18 */
+ "getattr", "lookup", "lookup_root", "remove", "rename", "link", /* 19 - 24 */
+ "symlink", "create", "pathconf", "statfs", "readlink", "readdir", /* 25 - 30 */
+ "server_caps", "delegreturn", "getacl", "setacl", "fs_locations", "rel_lkowner", /* 31 - 36 */
+ "secinfo", "exchange_id", "create_ses", "destroy_ses", "sequence", "get_lease_t", /* 37 - 42 */
+ "reclaim_comp", "layoutget", "getdevinfo", "layoutcommit", "layoutreturn", "getdevlist", /* 43 - 48 */
+ "stat49", "stat50", "stat51", "stat52", "start53", "stat54", /* 49 - 54 */
+ "stat55", "stat56", "stat57", "stat58", "start59", "stat60" /* 55 - 60 */
+};
+
+
+int nfs_v2c_found = 0;
+int nfs_v2s_found = 0;
+int nfs_v3c_found = 0;
+int nfs_v3s_found = 0;
+int nfs_v4c_found = 0;
+int nfs_v4s_found = 0;
+int nfs_clear = 0;
+
+struct nfs_stat {
+ long v2c[NFS_V2_NAMES_COUNT]; /* verison 2 client */
+ long v3c[NFS_V3_NAMES_COUNT]; /* verison 3 client */
+ long v4c[NFS_V4C_NAMES_COUNT]; /* verison 4 client */
+ long v2s[NFS_V2_NAMES_COUNT]; /* verison 2 SERVER */
+ long v3s[NFS_V3_NAMES_COUNT]; /* verison 3 SERVER */
+ long v4s[NFS_V4S_NAMES_COUNT]; /* verison 4 SERVER */
+};
+
+#define NETMAX 32
+struct net_stat {
+ unsigned long if_name[17];
+ unsigned long long if_ibytes;
+ unsigned long long if_obytes;
+ unsigned long long if_ipackets;
+ unsigned long long if_opackets;
+ unsigned long if_ierrs;
+ unsigned long if_oerrs;
+ unsigned long if_idrop;
+ unsigned long if_ififo;
+ unsigned long if_iframe;
+ unsigned long if_odrop;
+ unsigned long if_ofifo;
+ unsigned long if_ocarrier;
+ unsigned long if_ocolls;
+};
+#ifdef PARTITIONS
+#define PARTMAX 256
+struct part_stat {
+ int part_major;
+ int part_minor;
+ unsigned long part_blocks;
+ char part_name[16];
+ unsigned long part_rio;
+ unsigned long part_rmerge;
+ unsigned long part_rsect;
+ unsigned long part_ruse;
+ unsigned long part_wio;
+ unsigned long part_wmerge;
+ unsigned long part_wsect;
+ unsigned long part_wuse;
+ unsigned long part_run;
+ unsigned long part_use;
+ unsigned long part_aveq;
+};
+#endif /*PARTITIONS*/
+#ifdef POWER
+#define VM_UNKNOWN 0
+#define VM_POWERVM 1
+#define VM_POWERKVM_GUEST 2
+#define VM_POWERKVM_HOST 3
+#define VM_NATIVE 4
+int power_vm_type = VM_UNKNOWN;
+
+/* XXXXXXX need to test if rewind() worked or not for lparcfg */
+int lparcfg_reread = 1;
+/* Reset at end of each interval so LPAR cfg is only read once each interval
+ * even if proc_lparcfg() is called multiple times
+ * Note: lparcfg is not read via proc_read() !
+ */
+int lparcfg_processed = 0;
+
+struct {
+ char version_string[16]; /*lparcfg 1.3 */
+ int version;
+ char serial_number[16]; /*HAL,0210033EA */
+ char system_type[64]; /*HAL,9124-720 */
+ /* new record is "IBM pSeries (emulated by qemu)" instead of "IBM 9119-MME" */
+ int partition_id; /*11 */
+/*
+R4=0x14
+R5=0x0
+R6=0x800b0000
+R7=0x1000000040004
+*/
+ int BoundThrds; /*=1*/
+ int CapInc; /*=1*/
+ long long DisWheRotPer; /*=2070000*/
+ int MinEntCap; /*=10*/
+ int MinEntCapPerVP; /*=10*/
+ int MinMem; /*=2048*/
+ int DesMem; /*=4096*/
+ int MinProcs; /*=1*/
+ int partition_max_entitled_capacity;/*=400*/
+ int system_potential_processors; /*=4*/
+ /**/ int partition_entitled_capacity;
+ /*=20*/
+ int system_active_processors; /*=4*/
+ int pool_capacity; /*=4*/
+ int unallocated_capacity_weight; /*=0*/
+ int capacity_weight; /*=0*/
+ int capped; /*=1*/
+ int unallocated_capacity; /*=0*/
+ long long pool_idle_time; /*=0*/
+ long long pool_idle_saved;
+ long long pool_idle_diff;
+ int pool_num_procs; /*=0*/
+ long long purr; /*=0*/
+ long long purr_saved;
+ long long purr_diff;
+ long long timebase;
+ int partition_active_processors; /*=1*/
+ int partition_potential_processors; /*=40*/
+ int shared_processor_mode; /*=1*/
+ int smt_mode; /* 1: off, 2: SMT-2, 4: SMT-4 */
+ int cmo_enabled; /* 1 means AMS is Active */
+ int entitled_memory_pool_number; /* pool number = 0 */
+ int entitled_memory_weight; /* 0 to 255 */
+ long cmo_faults; /* Hypervisor Page-in faults = big number */
+ long cmo_faults_save; /* above saved */
+ long cmo_faults_diff; /* delta */
+ long cmo_fault_time_usec; /* Hypervisor time in micro seconds = big */
+ long cmo_fault_time_usec_save; /* above saved */
+ long cmo_fault_time_usec_diff; /* delta */
+ long backing_memory; /* AIX pmem in bytes */
+ long cmo_page_size; /* AMS page size in bytes */
+ long entitled_memory_pool_size; /* AMS whole pool size in bytes */
+ long entitled_memory_loan_request; /* AMS requesting more memory loaning */
+
+ long DedDonMode;
+#ifdef EXPERIMENTAL
+/* new data in SLES11 for POWER 2.6.27 (may be a little earlier too) */
+ long DesEntCap;
+ long DesProcs;
+ long DesVarCapWt;
+ long group;
+ long pool;
+ long entitled_memory;
+ long entitled_memory_group_number;
+ long unallocated_entitled_memory_weight;
+ long unallocated_io_mapping_entitlement;
+/* new data in SLES11 for POWER 2.6.27 */
+#endif /* EXPERIMENTAL */
+
+} lparcfg;
+
+int lpar_count = 0;
+
+#define LPAR_LINE_MAX 100 /* MAGIC COOKIE WARNING */
+#define LPAR_LINE_WIDTH 80
+char lpar_buffer[LPAR_LINE_MAX][LPAR_LINE_WIDTH];
+
+int lpar_sanity = 55;
+
+char *locate(char *s)
+{
+ int i;
+ int len;
+ len = strlen(s);
+ for (i = 0; i < lpar_count; i++)
+ if (!strncmp(s, lpar_buffer[i], len))
+ return lpar_buffer[i];
+ return "";
+}
+
+#define NUMBER_NOT_VALID -999
+
+long long read_longlong(char *s)
+{
+ long long x;
+ int ret;
+ int len;
+ int i;
+ char *str;
+ str = locate(s);
+ len = strlen(str);
+ if (len == 0) {
+ return NUMBER_NOT_VALID;
+ }
+ for (i = 0; i < len; i++) {
+ if (str[i] == '=') {
+ ret = sscanf(&str[i + 1], "%lld", &x);
+ if (ret != 1) {
+ fprintf(stderr,
+ "sscanf for %s failed returned = %d line=%s\n", s,
+ ret, str);
+ return -1;
+ }
+/* fprintf(fp,"DEBUG read %s value %lld\n",s,x);*/
+ return x;
+ }
+ }
+ fprintf(stderr, "read_long_long failed returned line=%s\n", str);
+ return -2;
+}
+
+
+/* Return of 0 means data not available */
+int proc_lparcfg()
+{
+ static FILE *fp = (FILE *) - 1;
+/* Only try to read /proc/ppc64/lparcfg once - remember if it's readable */
+ static int lparinfo_not_available = 0;
+ int i;
+ char *str;
+ /* If we already read and processed /proc/lparcfg in this interval - just return */
+ if (lparcfg_processed == 1)
+ return 1;
+
+ if (lparinfo_not_available == 1)
+ return 0;
+
+ if (fp == (FILE *) - 1) {
+ if ((fp = fopen("/proc/ppc64/lparcfg", "r")) == NULL) {
+ error("failed to open - /proc/ppc64/lparcfg");
+ fp = (FILE *) - 1;
+ lparinfo_not_available = 1;
+ if (power_vm_type == VM_UNKNOWN) {
+ /* Heuristics for spotting PowerKVM Host
+ a) inside ifdef POWER so can't be x86
+ b) /proc/ppc64/lparcfg is missing
+ c) /etc/ *ease files have hints
+ Confirmed true for IBM_POWERKVM 2.1
+ */
+ if (strncmp("IBM_PowerKVM", easy[1], 12) == 0)
+ power_vm_type = VM_POWERKVM_HOST;
+ else
+ power_vm_type = VM_NATIVE;
+ }
+ return 0;
+ }
+ }
+
+ for (lpar_count = 0; lpar_count < LPAR_LINE_MAX - 1; lpar_count++) {
+ if (fgets(lpar_buffer[lpar_count], LPAR_LINE_WIDTH - 1, fp) ==
+ NULL)
+ break;
+ }
+ if (lparcfg_reread) { /* XXXX unclear if close+open is necessary - unfortunately this requires version many of Linux on POWER install to test early releases */
+ fclose(fp);
+ fp = (FILE *) - 1;
+ } else
+ rewind(fp);
+
+ str = locate("lparcfg");
+ sscanf(str, "lparcfg %s", lparcfg.version_string);
+ str = locate("serial_number");
+ sscanf(str, "serial_number=%s", lparcfg.serial_number);
+ str = locate("system_type");
+ for (i = 0; i < strlen(str); i++) /* Remove new spaces in massive string meaning PowerKVM Guest !! */
+ if (str[i] == ' ')
+ str[i] = '-';
+ sscanf(str, "system_type=%s", lparcfg.system_type);
+ if (power_vm_type == VM_UNKNOWN) {
+ /* Heuristics for spotting PowerKVM Guest
+ a) inside ifdef POWER so can't be x86
+ b) we have a /proc/ppc64/lparcfg - probably mostly missing (1.9)
+ c) system type string includes "qemu"
+ Confirmed true for SLES11.3 RHEL6.5 and Ubuntu 14.4.1
+ */
+ if (strstr(lparcfg.system_type, "(emulated-by-qemu)") == 0)
+ power_vm_type = VM_POWERVM; /* not found */
+ else
+ power_vm_type = VM_POWERKVM_GUEST;
+ }
+#define GETDATA(variable) lparcfg.variable = read_longlong( __STRING(variable) );
+
+ GETDATA(partition_id);
+ GETDATA(BoundThrds);
+ GETDATA(CapInc);
+ GETDATA(DisWheRotPer);
+ GETDATA(MinEntCap);
+ GETDATA(MinEntCapPerVP);
+ GETDATA(MinMem);
+ GETDATA(DesMem);
+ GETDATA(MinProcs);
+ GETDATA(partition_max_entitled_capacity);
+ GETDATA(system_potential_processors);
+ GETDATA(partition_entitled_capacity);
+ GETDATA(system_active_processors);
+ GETDATA(pool_capacity);
+ GETDATA(unallocated_capacity_weight);
+ GETDATA(capacity_weight);
+ GETDATA(capped);
+ GETDATA(unallocated_capacity);
+ lparcfg.pool_idle_saved = lparcfg.pool_idle_time;
+ GETDATA(pool_idle_time);
+ lparcfg.pool_idle_diff =
+ lparcfg.pool_idle_time - lparcfg.pool_idle_saved;
+ GETDATA(pool_num_procs);
+ lparcfg.purr_saved = lparcfg.purr;
+ GETDATA(purr);
+ lparcfg.purr_diff = lparcfg.purr - lparcfg.purr_saved;
+ GETDATA(partition_active_processors);
+ GETDATA(partition_potential_processors);
+ GETDATA(shared_processor_mode);
+ /* Brute force, may provide temporary incorrect data during
+ * dynamic reconfiguraiton envents
+ */
+ lparcfg.smt_mode = cpus / lparcfg.partition_active_processors;
+
+ /* AMS additions */
+ GETDATA(cmo_enabled);
+ if (lparcfg.cmo_enabled == NUMBER_NOT_VALID) {
+ lparcfg.cmo_enabled = 0;
+ }
+ if (lparcfg.cmo_enabled) {
+ GETDATA(entitled_memory_pool_number); /* pool number = 0 */
+ GETDATA(entitled_memory_weight); /* 0 to 255 */
+
+ lparcfg.cmo_faults_save = lparcfg.cmo_faults;
+ GETDATA(cmo_faults); /* Hypervisor Page-in faults = big number */
+ lparcfg.cmo_faults_diff =
+ lparcfg.cmo_faults - lparcfg.cmo_faults_save;
+
+ lparcfg.cmo_fault_time_usec_save = lparcfg.cmo_fault_time_usec;
+ GETDATA(cmo_fault_time_usec); /* Hypervisor time in micro seconds = big number */
+ lparcfg.cmo_fault_time_usec_diff =
+ lparcfg.cmo_fault_time_usec - lparcfg.cmo_fault_time_usec_save;
+
+ GETDATA(backing_memory); /* AIX pmem in bytes */
+ GETDATA(cmo_page_size); /* AMS page size in bytes */
+ GETDATA(entitled_memory_pool_size); /* AMS whole pool size in bytes */
+ GETDATA(entitled_memory_loan_request); /* AMS requesting more memory loaning */
+
+ }
+ GETDATA(DedDonMode);
+#ifdef EXPERIMENTAL
+ GETDATA(DesEntCap);
+ GETDATA(DesProcs);
+ GETDATA(DesVarCapWt);
+ GETDATA(group);
+ GETDATA(pool);
+ GETDATA(entitled_memory);
+ GETDATA(entitled_memory_group_number);
+ GETDATA(unallocated_entitled_memory_weight);
+ GETDATA(unallocated_io_mapping_entitlement);
+#endif /* EXPERIMENTAL */
+
+ lparcfg_processed = 1;
+ return 1;
+}
+#endif /*POWER*/
+#define DISKMIN 256
+#define DISKMAX diskmax
+int diskmax = DISKMIN;
+
+/* Supports up to 780, but not POWER6 595 follow-up with POWER7 */
+/* XXXX needs rework to cope to with fairly rare but interesting higher numbers of CPU machines */
+#define CPUMAX (192 * 8) /* MAGIC COOKIE WARNING */
+
+struct data {
+ struct dsk_stat *dk;
+ struct cpu_stat cpu_total;
+ struct cpu_stat cpuN[CPUMAX];
+ struct mem_stat mem;
+ struct vm_stat vm;
+ struct nfs_stat nfs;
+ struct net_stat ifnets[NETMAX];
+#ifdef PARTITIONS
+ struct part_stat parts[PARTMAX];
+#endif /*PARTITIONS*/
+ struct timeval tv;
+ double time;
+ struct procsinfo *procs;
+
+ int proc_records;
+ int processes;
+} database[2], *p, *q;
+
+
+long long get_vm_value(char *s)
+{
+ int currline;
+ int currchar;
+ long long result = -1;
+ char *check;
+ int len;
+ int found;
+
+ for (currline = 0; currline < proc[P_VMSTAT].lines; currline++) {
+ len = strlen(s);
+ for (currchar = 0, found = 1; currchar < len; currchar++) {
+ if (proc[P_VMSTAT].line[currline][currchar] == 0 ||
+ s[currchar] != proc[P_VMSTAT].line[currline][currchar]) {
+ found = 0;
+ break;
+ }
+ }
+ if (found && proc[P_VMSTAT].line[currline][currchar] == ' ') {
+ result =
+ strtoll(&proc[P_VMSTAT].line[currline][currchar + 1],
+ &check, 10);
+ if (*check == proc[P_VMSTAT].line[currline][currchar + 1]) {
+ fprintf(stderr, "%s has an unexpected format: >%s<\n",
+ proc[P_VMSTAT].filename,
+ proc[P_VMSTAT].line[currline]);
+ return -1;
+ }
+ return result;
+ }
+ }
+ return -1;
+}
+
+#define GETVM(variable) p->vm.variable = get_vm_value(__STRING(variable) );
+
+int read_vmstat()
+{
+ proc_read(P_VMSTAT);
+ if (proc[P_VMSTAT].read_this_interval == 0
+ || proc[P_VMSTAT].lines == 0)
+ return (-1);
+
+ /* Note: if the variable requested is not found in /proc/vmstat then it is set to -1 */
+ GETVM(nr_dirty);
+ GETVM(nr_writeback);
+ GETVM(nr_unstable);
+ GETVM(nr_page_table_pages);
+ GETVM(nr_mapped);
+ if(p->vm.nr_slab != -1)
+ GETVM(nr_slab);
+ if(p->vm.nr_slab == -1) {
+ GETVM(nr_slab_reclaimable);
+ GETVM(nr_slab_unreclaimable);
+ }
+ GETVM(pgpgin);
+ GETVM(pgpgout);
+ GETVM(pswpin);
+ GETVM(pswpout);
+ GETVM(pgalloc_high);
+ GETVM(pgalloc_normal);
+ GETVM(pgalloc_dma);
+ GETVM(pgfree);
+ GETVM(pgactivate);
+ GETVM(pgdeactivate);
+ GETVM(pgfault);
+ GETVM(pgmajfault);
+ GETVM(pgrefill_high);
+ GETVM(pgrefill_normal);
+ GETVM(pgrefill_dma);
+ GETVM(pgsteal_high);
+ GETVM(pgsteal_normal);
+ GETVM(pgsteal_dma);
+ GETVM(pgscan_kswapd_high);
+ GETVM(pgscan_kswapd_normal);
+ GETVM(pgscan_kswapd_dma);
+ GETVM(pgscan_direct_high);
+ GETVM(pgscan_direct_normal);
+ GETVM(pgscan_direct_dma);
+ GETVM(pginodesteal);
+ GETVM(slabs_scanned);
+ GETVM(kswapd_steal);
+ GETVM(kswapd_inodesteal);
+ GETVM(pageoutrun);
+ GETVM(allocstall);
+ GETVM(pgrotated);
+ return 1;
+}
+
+
+/* These macro simplify the access to the Main data structure */
+#define DKDELTA(member) ( (q->dk[i].member > p->dk[i].member) ? 0 : (p->dk[i].member - q->dk[i].member))
+#define SIDELTA(member) ( (q->si.member > p->si.member) ? 0 : (p->si.member - q->si.member))
+
+#define IFNAME 64
+
+#define TIMEDELTA(member,index1,index2) ((p->procs[index1].member) - (q->procs[index2].member))
+#define IODELTA(member,index1,index2) ( (q->procs[index2].member > p->procs[index1].member) ? 0 : (p->procs[index1].member - q->procs[index2].member) )
+#define COUNTDELTA(member) ( (q->procs[topper[j].other].member > p->procs[i].member) ? 0 : (p->procs[i].member - q->procs[topper[j].other].member) )
+
+#define TIMED(member) ((double)(p->procs[i].member.tv_sec))
+
+double *cpu_peak; /* ptr to array - 1 for each cpu - 0 = average for machine */
+double *disk_busy_peak;
+double *disk_rate_peak;
+double net_read_peak[NETMAX];
+double net_write_peak[NETMAX];
+int aiorunning;
+int aiorunning_max = 0;
+int aiocount;
+int aiocount_max = 0;
+float aiotime;
+float aiotime_max = 0.0;
+
+char *dskgrp(int i)
+{
+ static char error_string[] = { "Too-Many-Disks" };
+ static char *string[16] = { "", "1", "2", "3",
+ "4", "5", "6", "7",
+ "8", "9", "10", "11",
+ "12", "13", "14", "15"
+ };
+
+ i = (int) ((float) i / (float) disks_per_line);
+ if (0 <= i && i <= 15)
+ return string[i];
+ return error_string;
+}
+
+/* command checking against a list */
+
+#define CMDMAX 64
+
+char *cmdlist[CMDMAX];
+int cmdfound = 0;
+
+int cmdcheck(char *cmd)
+{
+ int i;
+#ifdef CMDDEBUG
+ fprintf(stderr, "cmdfound=%d\n", cmdfound);
+ for (i = 0; i < cmdfound; i++)
+ fprintf(stderr, "cmdlist[%d]=\"%s\"\n", i, cmdlist[i]);
+#endif /* CMDDEBUG */
+ for (i = 0; i < cmdfound; i++) {
+ if (strlen(cmdlist[i]) == 0)
+ continue;
+ if (!strncmp(cmdlist[i], cmd, strlen(cmdlist[i])))
+ return 1;
+ }
+ return 0;
+}
+
+/* Convert secs + micro secs to a double */
+double doubletime(void)
+{
+
+ gettimeofday(&p->tv, 0);
+ return ((double) p->tv.tv_sec + p->tv.tv_usec * 1.0e-6);
+}
+
+void get_cpu_cnt()
+{
+ int i;
+
+ /* Get CPU info from /proc/stat and populate proc[P_STAT] */
+ proc_read(P_STAT);
+
+ /* Start with index [1] as [0] contains overall CPU statistics */
+ for (i = 1; i < proc[P_STAT].lines; i++) {
+ if (strncmp("cpu", proc[P_STAT].line[i], 3) == 0)
+ cpus = i;
+ else
+ break;
+ }
+ if (cpus > CPUMAX) {
+ printf
+ ("This nmon supports only %d CPU threads (Logical CPUs) and the machine appears to have %d.\nnmon stopping as its unsafe to continue.\n",
+ CPUMAX, cpus);
+ exit(44);
+ }
+}
+
+#if X86 || ARM
+void get_intel_spec()
+{
+ int i;
+ int physicalcpu[256];
+ int id;
+
+ /* Get CPU info from /proc/stat and populate proc[P_STAT] */
+ proc_read(P_CPUINFO);
+
+ for (i = 0; i < 256; i++)
+ physicalcpu[i] = 0;
+
+ for (i = 0; i < proc[P_CPUINFO].lines; i++) {
+ if (strncmp("vendor_id", proc[P_CPUINFO].line[i], 9) == 0) {
+ vendor_ptr = &proc[P_CPUINFO].line[i][12];
+ }
+ }
+ for (i = 0; i < proc[P_CPUINFO].lines; i++) {
+ if (strncmp("model name", proc[P_CPUINFO].line[i], 10) == 0) {
+ model_ptr = &proc[P_CPUINFO].line[i][13];
+ }
+ }
+ for (i = 0; i < proc[P_CPUINFO].lines; i++) {
+ if (strncmp("cpu MHz", proc[P_CPUINFO].line[i], 7) == 0) {
+ mhz_ptr = &proc[P_CPUINFO].line[i][11];
+ }
+ }
+ for (i = 0; i < proc[P_CPUINFO].lines; i++) {
+ if((strncmp("bogomips", proc[P_CPUINFO].line[i], 8) == 0) ||
+ (strncmp("bogoMIPS", proc[P_CPUINFO].line[i], 8) == 0) ||
+ (strncmp("BogoMIPS", proc[P_CPUINFO].line[i], 8) == 0)){
+ bogo_ptr = &proc[P_CPUINFO].line[i][11];
+ }
+ }
+
+ for (i = 0; i < proc[P_CPUINFO].lines; i++) {
+ if (strncmp("physical id", proc[P_CPUINFO].line[i], 11) == 0) {
+ id = atoi(&proc[P_CPUINFO].line[i][14]);
+ if (id < 256)
+ physicalcpu[id] = 1;
+ }
+ }
+ for (i = 0; i < 256; i++)
+ if (physicalcpu[i] == 1)
+ processorchips++;
+
+ /* Start with index [1] as [0] contains overall CPU statistics */
+ for (i = 0; i < proc[P_CPUINFO].lines; i++) {
+ if (strncmp("siblings", proc[P_CPUINFO].line[i], 8) == 0) {
+ siblings = atoi(&proc[P_CPUINFO].line[i][11]);
+ break;
+ }
+ }
+ for (i = 0; i < proc[P_CPUINFO].lines; i++) {
+ if (strncmp("cpu cores", proc[P_CPUINFO].line[i], 9) == 0) {
+ cores = atoi(&proc[P_CPUINFO].line[i][12]);
+ break;
+ }
+ }
+ if (siblings > cores)
+ hyperthreads = siblings / cores;
+ else
+ hyperthreads = 0;
+}
+#endif
+
+int stat8 = 0; /* used to determine the number of variables on a cpu line in /proc/stat */
+int stat10 = 0; /* used to determine the number of variables on a cpu line in /proc/stat */
+
+
+void proc_cpu()
+{
+ int i;
+ int row;
+ static int intr_line = 0;
+ static int ctxt_line = 0;
+ static int btime_line = 0;
+ static int proc_line = 0;
+ static int run_line = 0;
+ static int block_line = 0;
+ static int proc_cpu_first_time = 1;
+ long long user;
+ long long nice;
+ long long sys;
+ long long idle;
+ long long iowait;
+ long long hardirq;
+ long long softirq;
+ long long steal;
+ long long guest;
+ long long guest_nice;
+
+ /* Only read data once per interval */
+ if (proc_cpu_done == 1)
+ return;
+
+ /* If number of CPUs changed, then we need to find the index of intr_line, ... again */
+ if (old_cpus != cpus)
+ intr_line = 0;
+
+ if (proc_cpu_first_time) {
+ stat8 =
+ sscanf(&proc[P_STAT].line[0][5],
+ "%lld %lld %lld %lld %lld %lld %lld %lld", &user, &nice,
+ &sys, &idle, &iowait, &hardirq, &softirq, &steal);
+ stat10 =
+ sscanf(&proc[P_STAT].line[0][5],
+ "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",
+ &user, &nice, &sys, &idle, &iowait, &hardirq, &softirq,
+ &steal, &guest, &guest_nice);
+ proc_cpu_first_time = 0;
+ }
+ user = nice = sys = idle = iowait = hardirq = softirq = steal = guest =
+ guest_nice = 0;
+ if (stat10 == 10) {
+ sscanf(&proc[P_STAT].line[0][5],
+ "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld", &user,
+ &nice, &sys, &idle, &iowait, &hardirq, &softirq, &steal,
+ &guest, &guest_nice);
+ } else {
+ if (stat8 == 8) {
+ sscanf(&proc[P_STAT].line[0][5],
+ "%lld %lld %lld %lld %lld %lld %lld %lld", &user, &nice,
+ &sys, &idle, &iowait, &hardirq, &softirq, &steal);
+ } else { /* stat 4 variables here as older Linux proc */
+ sscanf(&proc[P_STAT].line[0][5], "%lld %lld %lld %lld",
+ &user, &nice, &sys, &idle);
+ }
+ }
+ p->cpu_total.user = user;
+ p->cpu_total.nice = nice;
+ p->cpu_total.idle = idle;
+ p->cpu_total.sys = sys;
+ p->cpu_total.wait = iowait; /* in the case of 4 variables = 0 */
+ /* p->cpu_total.sys = sys + hardirq + softirq + steal; */
+
+ p->cpu_total.irq = hardirq;
+ p->cpu_total.softirq = softirq;
+ p->cpu_total.steal = steal;
+ p->cpu_total.guest = guest;
+ p->cpu_total.guest_nice = guest_nice;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "XX user=%lld wait=%lld sys=%lld idle=%lld\n",
+ p->cpu_total.user,
+ p->cpu_total.wait, p->cpu_total.sys, p->cpu_total.idle);
+#endif /*DEBUG*/
+ for (i = 0; i < cpus; i++) {
+ user = nice = sys = idle = iowait = hardirq = softirq = steal = 0;
+
+ /* allow for large CPU numbers */
+ if (i + 1 > 1000)
+ row = 8;
+ else if (i + 1 > 100)
+ row = 7;
+ else if (i + 1 > 10)
+ row = 6;
+ else
+ row = 5;
+
+ if (stat10 == 10) {
+ sscanf(&proc[P_STAT].line[i + 1][row],
+ "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",
+ &user,
+ &nice,
+ &sys,
+ &idle,
+ &iowait,
+ &hardirq, &softirq, &steal, &guest, &guest_nice);
+
+ } else if (stat8 == 8) {
+ sscanf(&proc[P_STAT].line[i + 1][row],
+ "%lld %lld %lld %lld %lld %lld %lld %lld",
+ &user,
+ &nice,
+ &sys, &idle, &iowait, &hardirq, &softirq, &steal);
+ } else {
+ sscanf(&proc[P_STAT].line[i + 1][row], "%lld %lld %lld %lld",
+ &user, &nice, &sys, &idle);
+ }
+ p->cpuN[i].user = user;
+ p->cpuN[i].nice = nice;
+ p->cpuN[i].sys = sys;
+ p->cpuN[i].idle = idle;
+ p->cpuN[i].wait = iowait;
+ p->cpuN[i].irq = hardirq;
+ p->cpuN[i].softirq = softirq;
+ p->cpuN[i].steal = steal;
+ p->cpuN[i].guest = guest;
+ p->cpuN[i].guest_nice = guest_nice;
+ }
+
+ if (intr_line == 0) {
+ if (proc[P_STAT].line[i + 1][0] == 'p' &&
+ proc[P_STAT].line[i + 1][1] == 'a' &&
+ proc[P_STAT].line[i + 1][2] == 'g' &&
+ proc[P_STAT].line[i + 1][3] == 'e') {
+ /* 2.4 kernel */
+ intr_line = i + 3;
+ ctxt_line = i + 5;
+ btime_line = i + 6;
+ proc_line = i + 7;
+ run_line = i + 8;
+ block_line = i + 9;
+ } else {
+ /* 2.6 kernel */
+ intr_line = i + 1;
+ ctxt_line = i + 2;
+ btime_line = i + 3;
+ proc_line = i + 4;
+ run_line = i + 5;
+ block_line = i + 6;
+ }
+ }
+ p->cpu_total.intr = -1;
+ p->cpu_total.ctxt = -1;
+ p->cpu_total.procs = -1;
+ p->cpu_total.running = -1;
+ p->cpu_total.blocked = -1;
+ if (proc[P_STAT].lines >= intr_line)
+ sscanf(&proc[P_STAT].line[intr_line][0], "intr %lld",
+ &p->cpu_total.intr);
+ if (proc[P_STAT].lines >= ctxt_line)
+ sscanf(&proc[P_STAT].line[ctxt_line][0], "ctxt %lld",
+ &p->cpu_total.ctxt);
+ if(boottime == 0) {
+ struct tm ts;
+ if (proc[P_STAT].lines >= btime_line)
+ sscanf(&proc[P_STAT].line[btime_line][0], "btime %lld", &boottime);
+ ts = *localtime((time_t *)&boottime);
+ strftime (boottime_str, 64, "%I:%M %p %d-%b-%Y", &ts);
+ }
+ if (proc[P_STAT].lines >= proc_line)
+ sscanf(&proc[P_STAT].line[proc_line][0], "processes %lld",
+ &p->cpu_total.procs);
+ if (proc[P_STAT].lines >= run_line)
+ sscanf(&proc[P_STAT].line[run_line][0], "procs_running %lld",
+ &p->cpu_total.running);
+ if (proc[P_STAT].lines >= block_line)
+ sscanf(&proc[P_STAT].line[block_line][0], "procs_blocked %lld",
+ &p->cpu_total.blocked);
+
+ /* If we had a change in the number of CPUs, copy current interval data to the previous, so we
+ * get a "0" utilization interval, but better than negative or 100%.
+ * Heads-up - This effects POWER SMT changes too.
+ */
+ if (old_cpus != cpus) {
+ memcpy((void *) &(q->cpu_total), (void *) &(p->cpu_total),
+ sizeof(struct cpu_stat));
+ memcpy((void *) q->cpuN, (void *) p->cpuN,
+ sizeof(struct cpu_stat) * cpus);
+ }
+
+ /* Flag that we processed /proc/stat data; re-set in proc_read() when we re-read /proc/stat */
+ proc_cpu_done = 1;
+}
+
+void proc_nfs()
+{
+ int i;
+ int j;
+ int len;
+ int lineno;
+
+/* sample /proc/net/rpc/nfs
+net 0 0 0 0
+rpc 70137 0 0
+proc2 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+proc3 22 0 27364 0 32 828 22 40668 0 1 0 0 0 0 0 0 0 0 1212 6 2 1 0
+proc4 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+*/
+ if (proc[P_NFS].fp != 0) {
+ for (lineno = 0; lineno < proc[P_NFS].lines; lineno++) {
+ if (!strncmp("proc2 ", proc[P_NFS].line[lineno], 6)) {
+ /* client version 2 line readers "proc2 18 num num etc" */
+ len = strlen(proc[P_NFS].line[lineno]);
+ for (j = 0, i = 8; i < len && j < NFS_V2_NAMES_COUNT; i++) {
+ if (proc[P_NFS].line[lineno][i] == ' ') {
+ p->nfs.v2c[j] =
+ atol(&proc[P_NFS].line[lineno][i + 1]);
+ nfs_v2c_found = 1;
+ j++;
+ }
+ }
+ }
+ if (!strncmp("proc3 ", proc[P_NFS].line[lineno], 6)) {
+ /* client version 3 line readers "proc3 22 num num etc" */
+ len = strlen(proc[P_NFS].line[lineno]);
+ for (j = 0, i = 8; i < len && j < NFS_V3_NAMES_COUNT; i++) {
+ if (proc[P_NFS].line[lineno][i] == ' ') {
+ p->nfs.v3c[j] =
+ atol(&proc[P_NFS].line[lineno][i + 1]);
+ nfs_v3c_found = 1;
+ j++;
+ }
+ }
+ }
+ if (!strncmp("proc4 ", proc[P_NFS].line[lineno], 6)) {
+ /* client version 4 line readers "proc4 35 num num etc" */
+ nfs_v4c_names_count = atoi(&proc[P_NFS].line[lineno][6]);
+ len = strlen(proc[P_NFS].line[lineno]);
+ for (j = 0, i = 8; i < len && j < nfs_v4c_names_count; i++) {
+ if (proc[P_NFS].line[lineno][i] == ' ') {
+ p->nfs.v4c[j] =
+ atol(&proc[P_NFS].line[lineno][i + 1]);
+ nfs_v4c_found = 1;
+ j++;
+ }
+ }
+ }
+ }
+ }
+/* sample /proc/net/rpc/nfsd
+rc 0 0 0
+fh 0 0 0 0 0
+io 0 0
+th 4 0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
+ra 32 0 0 0 0 0 0 0 0 0 0 0
+net 0 0 0 0
+rpc 0 0 0 0 0
+proc2 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+proc3 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+proc4 2 0 0
+proc4ops 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+*/
+ if (proc[P_NFSD].fp != 0) {
+ for (lineno = 0; lineno < proc[P_NFSD].lines; lineno++) {
+ if (!strncmp("proc2 ", proc[P_NFSD].line[lineno], 6)) {
+ /* server version 2 line readers "proc2 18 num num etc" */
+ len = strlen(proc[P_NFSD].line[lineno]);
+ for (j = 0, i = 8; i < len && j < NFS_V2_NAMES_COUNT; i++) {
+ if (proc[P_NFSD].line[lineno][i] == ' ') {
+ p->nfs.v2s[j] =
+ atol(&proc[P_NFSD].line[lineno][i + 1]);
+ nfs_v2s_found = 1;
+ j++;
+ }
+ }
+ }
+ if (!strncmp("proc3 ", proc[P_NFSD].line[lineno], 6)) {
+ /* server version 3 line readers "proc3 22 num num etc" */
+ len = strlen(proc[P_NFSD].line[lineno]);
+ for (j = 0, i = 8; i < len && j < NFS_V2_NAMES_COUNT; i++) {
+ if (proc[P_NFSD].line[lineno][i] == ' ') {
+ p->nfs.v3s[j] =
+ atol(&proc[P_NFSD].line[lineno][i + 1]);
+ nfs_v3s_found = 1;
+ j++;
+ }
+ }
+ }
+ if (!strncmp("proc4ops ", proc[P_NFSD].line[lineno], 9)) {
+ /* server version 4 line readers "proc4ops 40 num num etc"
+ NOTE: the "ops" hence starting in column 9 */
+ nfs_v4s_names_count = atol(&proc[P_NFSD].line[lineno][9]);
+ len = strlen(proc[P_NFSD].line[lineno]);
+ for (j = 0, i = 11; i < len && j < nfs_v4s_names_count;
+ i++) {
+ if (proc[P_NFSD].line[lineno][i] == ' ') {
+ p->nfs.v4s[j] =
+ atol(&proc[P_NFSD].line[lineno][i + 1]);
+ nfs_v4s_found = 1;
+ j++;
+ }
+ }
+ }
+ }
+ }
+}
+
+void proc_kernel()
+{
+ int i;
+ p->cpu_total.uptime = 0.0;
+ p->cpu_total.idletime = 0.0;
+ p->cpu_total.uptime = atof(proc[P_UPTIME].line[0]);
+ for (i = 0; i < strlen(proc[P_UPTIME].line[0]); i++) {
+ if (proc[P_UPTIME].line[0][i] == ' ') {
+ p->cpu_total.idletime = atof(&proc[P_UPTIME].line[0][i + 1]);
+ break;
+ }
+ }
+
+ sscanf(&proc[P_LOADAVG].line[0][0], "%f %f %f",
+ &p->cpu_total.mins1, &p->cpu_total.mins5, &p->cpu_total.mins15);
+
+}
+
+char *proc_find_sb(char *p)
+{
+ for (; *p != 0; p++)
+ if (*p == ' ' && *(p + 1) == '(')
+ return p;
+ return 0;
+}
+
+#define DISK_MODE_IO 1
+#define DISK_MODE_DISKSTATS 2
+#define DISK_MODE_PARTITIONS 3
+
+int disk_mode = 0;
+
+void proc_disk_io(double elapsed)
+{
+ int diskline;
+ int i;
+ int ret;
+ char *str;
+ int fudged_busy;
+
+ disks = 0;
+ for (diskline = 0; diskline < proc[P_STAT].lines; diskline++) {
+ if (strncmp("disk_io", proc[P_STAT].line[diskline], 7) == 0)
+ break;
+ }
+ for (i = 8; i < strlen(proc[P_STAT].line[diskline]); i++) {
+ if (proc[P_STAT].line[diskline][i] == ':')
+ disks++;
+ }
+
+ str = &proc[P_STAT].line[diskline][0];
+ for (i = 0; i < disks; i++) {
+ str = proc_find_sb(str);
+ if (str == 0)
+ break;
+ ret = sscanf(str, " (%d,%d):(%ld,%ld,%ld,%ld,%ld",
+ &p->dk[i].dk_major,
+ &p->dk[i].dk_minor,
+ &p->dk[i].dk_noinfo,
+ &p->dk[i].dk_reads,
+ &p->dk[i].dk_rkb,
+ &p->dk[i].dk_writes, &p->dk[i].dk_wkb);
+ if (ret != 7)
+ exit(7);
+ p->dk[i].dk_xfers = p->dk[i].dk_noinfo;
+ /* blocks are 512 bytes */
+ p->dk[i].dk_rkb = p->dk[i].dk_rkb / 2;
+ p->dk[i].dk_wkb = p->dk[i].dk_wkb / 2;
+
+ p->dk[i].dk_bsize =
+ (p->dk[i].dk_rkb + p->dk[i].dk_wkb) / p->dk[i].dk_xfers * 1024;
+
+ /* assume a disk does 200 op per second */
+ fudged_busy = (p->dk[i].dk_reads + p->dk[i].dk_writes) / 2;
+ if (fudged_busy > 100 * elapsed)
+ p->dk[i].dk_time += 100 * elapsed;
+ p->dk[i].dk_time = fudged_busy;
+
+ snprintf(p->dk[i].dk_name, 32, "dev-%d-%d", p->dk[i].dk_major,
+ p->dk[i].dk_minor);
+/* fprintf(stderr,"disk=%d name=\"%s\" major=%d minor=%d\n", i,p->dk[i].dk_name, p->dk[i].dk_major,p->dk[i].dk_minor); */
+ str++;
+ }
+}
+
+void proc_diskstats(double elapsed)
+{
+ static FILE *fp = (FILE *) - 1;
+ char buf[1024];
+ int i;
+ int ret;
+
+ if (fp == (FILE *) - 1) {
+ if ((fp = fopen("/proc/diskstats", "r")) == NULL) {
+ /* DEBUG if( (fp = fopen("diskstats","r")) == NULL) { */
+ error("failed to open - /proc/diskstats");
+ disks = 0;
+ return;
+ }
+ }
+/*
+ 2 0 fd0 1 0 2 13491 0 0 0 0 0 13491 13491
+ 3 0 hda 41159 53633 1102978 620181 39342 67538 857108 4042631 0 289150 4668250
+ 3 1 hda1 58209 58218 0 0
+ 3 2 hda2 148 4794 10 20
+ 3 3 hda3 65 520 0 0
+ 3 4 hda4 35943 1036092 107136 857088
+ 22 0 hdc 167 5394 22308 32250 0 0 0 0 0 22671 32250 <-- USB !!
+ 8 0 sda 990 2325 4764 6860 9 3 12 417 0 6003 7277
+ 8 1 sda1 3264 4356 12 12
+*/
+ for (i = 0; i < DISKMAX;) {
+ if (fgets(buf, 1024, fp) == NULL)
+ break;
+ /* zero the data ready for reading */
+ p->dk[i].dk_major =
+ p->dk[i].dk_minor =
+ p->dk[i].dk_name[0] =
+ p->dk[i].dk_reads =
+ p->dk[i].dk_rmerge =
+ p->dk[i].dk_rkb =
+ p->dk[i].dk_rmsec =
+ p->dk[i].dk_writes =
+ p->dk[i].dk_wmerge =
+ p->dk[i].dk_wkb =
+ p->dk[i].dk_wmsec =
+ p->dk[i].dk_inflight =
+ p->dk[i].dk_time = p->dk[i].dk_backlog = 0;
+
+ ret =
+ sscanf(&buf[0],
+ "%d %d %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+ &p->dk[i].dk_major, &p->dk[i].dk_minor,
+ &p->dk[i].dk_name[0], &p->dk[i].dk_reads,
+ &p->dk[i].dk_rmerge, &p->dk[i].dk_rkb,
+ &p->dk[i].dk_rmsec, &p->dk[i].dk_writes,
+ &p->dk[i].dk_wmerge, &p->dk[i].dk_wkb,
+ &p->dk[i].dk_wmsec, &p->dk[i].dk_inflight,
+ &p->dk[i].dk_time, &p->dk[i].dk_backlog);
+ if (ret == 7) { /* shuffle the data around due to missing columns for partitions */
+ p->dk[i].dk_partition = 1;
+ p->dk[i].dk_wkb = p->dk[i].dk_rmsec;
+ p->dk[i].dk_writes = p->dk[i].dk_rkb;
+ p->dk[i].dk_rkb = p->dk[i].dk_rmerge;
+ p->dk[i].dk_rmsec = 0;
+ p->dk[i].dk_rmerge = 0;
+
+ } else if (ret == 14)
+ p->dk[i].dk_partition = 0;
+ else
+ fprintf(stderr,
+ "disk sscanf wanted 14 but returned=%d line=%s\n", ret,
+ buf);
+
+ p->dk[i].dk_rkb /= 2; /* sectors = 512 bytes */
+ p->dk[i].dk_wkb /= 2;
+ p->dk[i].dk_xfers = p->dk[i].dk_reads + p->dk[i].dk_writes;
+ if (p->dk[i].dk_xfers == 0)
+ p->dk[i].dk_bsize = 0;
+ else
+ p->dk[i].dk_bsize =
+ ((p->dk[i].dk_rkb +
+ p->dk[i].dk_wkb) / p->dk[i].dk_xfers) * 1024;
+
+ p->dk[i].dk_time /= 10.0; /* in milli-seconds to make it upto 100%, 1000/100 = 10 */
+
+ if (p->dk[i].dk_xfers > 0)
+ i++;
+ }
+ if (reread) {
+ fclose(fp);
+ fp = (FILE *) - 1;
+ } else
+ rewind(fp);
+ disks = i;
+}
+
+void strip_spaces(char *s)
+{
+ char *p;
+ int spaced = 1;
+
+ p = s;
+ for (p = s; *p != 0; p++) {
+ if (*p == ':')
+ *p = ' ';
+ if (*p != ' ') {
+ *s = *p;
+ s++;
+ spaced = 0;
+ } else if (spaced) {
+ /* do no thing as this is second space */
+ } else {
+ *s = *p;
+ s++;
+ spaced = 1;
+ }
+
+ }
+ *s = 0;
+}
+
+void proc_partitions(double elapsed)
+{
+ static FILE *fp = (FILE *) - 1;
+ char buf[1024];
+ int i = 0;
+ int ret;
+
+ if (fp == (FILE *) - 1) {
+ if ((fp = fopen("/proc/partitions", "r")) == NULL) {
+ error("failed to open - /proc/partitions");
+ partitions = 0;
+ return;
+ }
+ }
+ if (fgets(buf, 1024, fp) == NULL)
+ goto end; /* throw away the header lines */
+ if (fgets(buf, 1024, fp) == NULL)
+ goto end;
+/*
+major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
+
+ 33 0 1052352 hde 2855 15 2890 4760 0 0 0 0 -4 7902400 11345292
+ 33 1 1050304 hde1 2850 0 2850 3930 0 0 0 0 0 3930 3930
+ 3 0 39070080 hda 9287 19942 226517 90620 8434 25707 235554 425790 -12 7954830 33997658
+ 3 1 31744408 hda1 651 90 5297 2030 0 0 0 0 0 2030 2030
+ 3 2 6138720 hda2 7808 19561 218922 79430 7299 20529 222872 241980 0 59950 321410
+ 3 3 771120 hda3 13 41 168 80 0 0 0 0 0 80 80
+ 3 4 1 hda4 0 0 0 0 0 0 0 0 0 0 0
+ 3 5 408208 hda5 812 241 2106 9040 1135 5178 12682 183810 0 11230 192850
+*/
+ for (i = 0; i < DISKMAX; i++) {
+ if (fgets(buf, 1024, fp) == NULL)
+ break;
+ strip_spaces(buf);
+ ret =
+ sscanf(&buf[0],
+ "%d %d %lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+ &p->dk[i].dk_major, &p->dk[i].dk_minor,
+ &p->dk[i].dk_blocks, (char *) &p->dk[i].dk_name,
+ &p->dk[i].dk_reads, &p->dk[i].dk_rmerge,
+ &p->dk[i].dk_rkb, &p->dk[i].dk_rmsec,
+ &p->dk[i].dk_writes, &p->dk[i].dk_wmerge,
+ &p->dk[i].dk_wkb, &p->dk[i].dk_wmsec,
+ &p->dk[i].dk_inflight, &p->dk[i].dk_use,
+ &p->dk[i].dk_aveq);
+ p->dk[i].dk_rkb /= 2; /* sectors = 512 bytes */
+ p->dk[i].dk_wkb /= 2;
+ p->dk[i].dk_xfers = p->dk[i].dk_rkb + p->dk[i].dk_wkb;
+ if (p->dk[i].dk_xfers == 0)
+ p->dk[i].dk_bsize = 0;
+ else
+ p->dk[i].dk_bsize =
+ (p->dk[i].dk_rkb +
+ p->dk[i].dk_wkb) / p->dk[i].dk_xfers * 1024;
+
+ p->dk[i].dk_time /= 10.0; /* in milli-seconds to make it upto 100%, 1000/100 = 10 */
+
+ if (ret != 15) {
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "sscanf wanted 15 returned = %d line=%s\n",
+ ret, buf);
+#endif /*DEBUG*/
+ partitions_short = 1;
+ } else
+ partitions_short = 0;
+ }
+ end:
+ if (reread) {
+ fclose(fp);
+ fp = (FILE *) - 1;
+ } else
+ rewind(fp);
+ disks = i;
+}
+
+void proc_disk(double elapsed)
+{
+ struct stat buf;
+ int ret;
+ if (disk_mode == 0) {
+ ret = stat("/proc/diskstats", &buf);
+ if (ret == 0) {
+ disk_mode = DISK_MODE_DISKSTATS;
+ } else {
+ ret = stat("/proc/partitions", &buf);
+ if (ret == 0) {
+ disk_mode = DISK_MODE_PARTITIONS;
+ } else {
+ disk_mode = DISK_MODE_IO;
+ }
+ }
+ }
+ switch (disk_mode) {
+ case DISK_MODE_IO:
+ proc_disk_io(elapsed);
+ break;
+ case DISK_MODE_DISKSTATS:
+ proc_diskstats(elapsed);
+ break;
+ case DISK_MODE_PARTITIONS:
+ proc_partitions(elapsed);
+ break;
+ }
+}
+
+#undef isdigit
+#define isdigit(ch) ( ( '0' <= (ch) && (ch) >= '9')? 0: 1 )
+
+long proc_mem_search(char *s)
+{
+ int i;
+ int j;
+ int len;
+ len = strlen(s);
+ for (i = 0; i < proc[P_MEMINFO].lines; i++) {
+ if (!strncmp(s, proc[P_MEMINFO].line[i], len)) {
+ for (j = len;
+ !isdigit(proc[P_MEMINFO].line[i][j]) &&
+ proc[P_MEMINFO].line[i][j] != 0; j++)
+ /* do nothing */ ;
+ return atol(&proc[P_MEMINFO].line[i][j]);
+ }
+ }
+ return -1;
+}
+
+void proc_mem()
+{
+ if (proc[P_MEMINFO].read_this_interval == 0)
+ proc_read(P_MEMINFO);
+
+ p->mem.memtotal = proc_mem_search("MemTotal");
+ p->mem.memfree = proc_mem_search("MemFree");
+ p->mem.memshared = proc_mem_search("MemShared");
+ /* memshared was renamed (pointlessly) Sheme and includes RAM disks in later kernels */
+ if(p->mem.memshared <= 0)
+ p->mem.memshared = proc_mem_search("Shmem");
+
+ p->mem.buffers = proc_mem_search("Buffers");
+ p->mem.cached = proc_mem_search("Cached");
+ p->mem.swapcached = proc_mem_search("SwapCached");
+ p->mem.active = proc_mem_search("Active");
+ p->mem.inactive = proc_mem_search("Inactive");
+ p->mem.hightotal = proc_mem_search("HighTotal");
+ p->mem.highfree = proc_mem_search("HighFree");
+ p->mem.lowtotal = proc_mem_search("LowTotal");
+ p->mem.lowfree = proc_mem_search("LowFree");
+ p->mem.swaptotal = proc_mem_search("SwapTotal");
+ p->mem.swapfree = proc_mem_search("SwapFree");
+#ifndef SMALLMEM
+ p->mem.dirty = proc_mem_search("Dirty");
+ p->mem.writeback = proc_mem_search("Writeback");
+ p->mem.mapped = proc_mem_search("Mapped");
+ p->mem.slab = proc_mem_search("Slab");
+ p->mem.committed_as = proc_mem_search("Committed_AS");
+ p->mem.pagetables = proc_mem_search("PageTables");
+ p->mem.hugetotal = proc_mem_search("HugePages_Total");
+ p->mem.hugefree = proc_mem_search("HugePages_Free");
+ p->mem.hugesize = proc_mem_search("Hugepagesize");
+#else
+ p->mem.bigfree = proc_mem_search("BigFree");
+#endif /*SMALLMEM*/
+}
+
+#define MAX_SNAPS 72
+#define MAX_SNAP_ROWS 20
+#define SNAP_OFFSET 6
+
+int next_cpu_snap = 0;
+int cpu_snap_all = 0;
+
+struct {
+ double user;
+ double kernel;
+ double iowait;
+ double idle;
+ double steal;
+} cpu_snap[MAX_SNAPS];
+
+int snap_average()
+{
+ int i;
+ int end;
+ int total = 0;
+
+ if (cpu_snap_all)
+ end = MAX_SNAPS;
+ else
+ end = next_cpu_snap;
+
+ for (i = 0; i < end; i++) {
+ total = total + cpu_snap[i].user + cpu_snap[i].kernel;
+ }
+ return (total / end);
+}
+
+void snap_clear()
+{
+ int i;
+ for (i = 0; i < MAX_SNAPS; i++) {
+ cpu_snap[i].user = 0;
+ cpu_snap[i].kernel = 0;
+ cpu_snap[i].iowait = 0;
+ cpu_snap[i].idle = 0;
+ cpu_snap[i].steal = 0;
+ }
+ next_cpu_snap = 0;
+ cpu_snap_all = 0;
+}
+
+void plot_snap(WINDOW * pad)
+{
+ int i;
+ int j;
+ double k;
+ if (cursed) {
+ mvwprintw(pad, 0, 0,
+ " CPU +---Long-Term-------------------------------------------------------------+");
+ mvwprintw(pad, 1, 0, "100%%-|");
+ mvwprintw(pad, 2, 1, "95%%-|");
+ mvwprintw(pad, 3, 1, "90%%-|");
+ mvwprintw(pad, 4, 1, "85%%-|");
+ mvwprintw(pad, 5, 1, "80%%-|");
+ mvwprintw(pad, 6, 1, "75%%-|");
+ mvwprintw(pad, 7, 1, "70%%-|");
+ mvwprintw(pad, 8, 1, "65%%-|");
+ mvwprintw(pad, 9, 1, "60%%-|");
+ mvwprintw(pad, 10, 1, "55%%-|");
+ mvwprintw(pad, 11, 1, "50%%-|");
+ mvwprintw(pad, 12, 1, "45%%-|");
+ mvwprintw(pad, 13, 1, "40%%-|");
+ mvwprintw(pad, 14, 1, "35%%-|");
+ mvwprintw(pad, 15, 1, "30%%-|");
+ mvwprintw(pad, 16, 1, "25%%-|");
+ mvwprintw(pad, 17, 1, "20%%-|");
+ mvwprintw(pad, 18, 1, "15%%-|");
+ mvwprintw(pad, 19, 1, "10%%-|");
+ mvwprintw(pad, 20, 1, " 5%%-|");
+
+ mvwprintw(pad, 21, 4,
+ " +-------------------------------------------------------------------------+");
+ if (colour) {
+ COLOUR wattrset(pad, COLOR_PAIR(2));
+ mvwprintw(pad, 0, 26, "User%%");
+ COLOUR wattrset(pad, COLOR_PAIR(1));
+ mvwprintw(pad, 0, 36, "System%%");
+ COLOUR wattrset(pad, COLOR_PAIR(4));
+ mvwprintw(pad, 0, 49, "Wait%%");
+ COLOUR wattrset(pad, COLOR_PAIR(5));
+ mvwprintw(pad, 0, 59, "Steal%%");
+ COLOUR wattrset(pad, COLOR_PAIR(0));
+ }
+
+ for (j = 0; j < MAX_SNAPS; j++) {
+ for (i = 0; i < MAX_SNAP_ROWS; i++) {
+ wmove(pad, MAX_SNAP_ROWS - i, j + SNAP_OFFSET);
+ if (cpu_snap[j].user + cpu_snap[j].kernel + cpu_snap[j].iowait + cpu_snap[j].idle + cpu_snap[j].steal == 0) { /* if not all zeros */
+ COLOUR wattrset(pad, COLOR_PAIR(0));
+ wprintw(pad, " ");
+ } else if ((cpu_snap[j].user / 100 * MAX_SNAP_ROWS) >
+ i + 0.5) {
+ COLOUR wattrset(pad, COLOR_PAIR(9));
+ wprintw(pad, "U");
+ } else if ((cpu_snap[j].user + cpu_snap[j].kernel) / 100 *
+ MAX_SNAP_ROWS > i + 0.5) {
+ COLOUR wattrset(pad, COLOR_PAIR(8));
+ wprintw(pad, "s");
+ } else
+ if ((cpu_snap[j].user + cpu_snap[j].kernel +
+ cpu_snap[j].iowait) / 100 * MAX_SNAP_ROWS >
+ i + 0.5) {
+ COLOUR wattrset(pad, COLOR_PAIR(10));
+ wprintw(pad, "w");
+ } else if ((cpu_snap[j].user + cpu_snap[j].kernel + cpu_snap[j].iowait + cpu_snap[j].idle) / 100 * MAX_SNAP_ROWS > i) { /*no +0.5 or too few Steal's */
+ COLOUR wattrset(pad, COLOR_PAIR(0));
+ wprintw(pad, " ");
+ } else if (cpu_snap[j].user + cpu_snap[j].kernel + cpu_snap[j].iowait + cpu_snap[j].idle + cpu_snap[j].steal > i) { /* if not all zeros */
+ COLOUR wattrset(pad, COLOR_PAIR(5));
+ wprintw(pad, "S");
+ }
+ }
+ k = cpu_snap[j].user + cpu_snap[j].kernel + cpu_snap[j].iowait;
+ if (0.1 < k && k < 5.0) { /* not zero but less than 5% */
+ wmove(pad, MAX_SNAP_ROWS, j + SNAP_OFFSET);
+ COLOUR wattrset(pad, COLOR_PAIR(2));
+ wprintw(pad, "_");
+ }
+ }
+ COLOUR wattrset(pad, COLOR_PAIR(0));
+ for (i = 0; i < MAX_SNAP_ROWS; i++) {
+ wmove(pad, MAX_SNAP_ROWS - i, next_cpu_snap + SNAP_OFFSET);
+ wprintw(pad, "|");
+ }
+ wmove(pad, MAX_SNAP_ROWS + 1 - (snap_average() / 5),
+ next_cpu_snap + SNAP_OFFSET);
+ wprintw(pad, "+");
+ if (dotline) {
+ for (i = 0; i < MAX_SNAPS; i++) {
+ wmove(pad, MAX_SNAP_ROWS + 1 - dotline * 2,
+ i + SNAP_OFFSET);
+ wprintw(pad, "+");
+ }
+ dotline = 0;
+ }
+ }
+}
+
+/* This saves the CPU overall usage for later ploting on the screen */
+void save_snap(double user, double kernel, double iowait, double idle,
+ double steal)
+{
+ cpu_snap[next_cpu_snap].user = user;
+ cpu_snap[next_cpu_snap].kernel = kernel;
+ cpu_snap[next_cpu_snap].iowait = iowait;
+ cpu_snap[next_cpu_snap].idle = idle;
+ cpu_snap[next_cpu_snap].steal = steal;
+ next_cpu_snap++;
+ if (next_cpu_snap >= MAX_SNAPS) {
+ next_cpu_snap = 0;
+ cpu_snap_all = 1;
+ }
+}
+
+void plot_smp(WINDOW * pad, int cpu_no, int row, double user,
+ double kernel, double iowait, double idle, double steal)
+{
+ int i;
+ int peak_col;
+
+ if (show_rrd)
+ return;
+
+ if (cpu_peak[cpu_no] < (user + kernel + iowait))
+ cpu_peak[cpu_no] =
+ (double) ((int) user / 2 + (int) kernel / 2 +
+ (int) iowait / 2) * 2.0;
+
+ if (cursed) {
+ if (cpu_no == 0)
+ mvwprintw(pad, row, 0, "Avg");
+ else
+ mvwprintw(pad, row, 0, "%3d", cpu_no);
+ mvwprintw(pad, row, 3, "% 6.1lf", user);
+ mvwprintw(pad, row, 9, "% 6.1lf", kernel);
+ mvwprintw(pad, row, 15, "% 6.1lf", iowait);
+ if (steal) {
+ mvwprintw(pad, row, 21, "% 6.1lf", steal);
+ } else {
+ mvwprintw(pad, row, 21, "% 6.1lf", idle);
+ }
+ mvwprintw(pad, row, 27, "|");
+ wmove(pad, row, 28);
+ for (i = 0; i < (int) (user / 2); i++) {
+ COLOUR wattrset(pad, COLOR_PAIR(9));
+ wprintw(pad, "U");
+ }
+ for (i = 0; i < (int) (kernel / 2); i++) {
+ COLOUR wattrset(pad, COLOR_PAIR(8));
+ wprintw(pad, "s");
+ }
+ for (i = 0; i < (int) (iowait / 2); i++) {
+ COLOUR wattrset(pad, COLOR_PAIR(10));
+ wprintw(pad, "W");
+ }
+ COLOUR wattrset(pad, COLOR_PAIR(0));
+ for (i = 0; i <= (int) (idle / 2); i++) { /* added "=" to try to conteract missing halves */
+#ifdef POWER
+ if (lparcfg.smt_mode > 1
+ && ((cpu_no - 1) % lparcfg.smt_mode) == 0 && (i % 2))
+ wprintw(pad, ".");
+ else
+#endif
+ wprintw(pad, " ");
+ }
+ for (i = 0; i < (int) ((steal + 1) / 2); i++) {
+ COLOUR wattrset(pad, COLOR_PAIR(5));
+ wprintw(pad, "S");
+ }
+ COLOUR wattrset(pad, COLOR_PAIR(0));
+ mvwprintw(pad, row, 77, "| ");
+
+ peak_col = 28 + (int) (cpu_peak[cpu_no] / 2);
+ if (peak_col > 77)
+ peak_col = 77;
+ mvwprintw(pad, row, peak_col, ">");
+ } else {
+ /* Sanity check the numnbers */
+ if (user < 0.0 || kernel < 0.0 || iowait < 0.0 || idle < 0.0
+ || idle > 100.0 || steal < 0) {
+ user = kernel = iowait = idle = steal = 0;
+ }
+
+ if (first_steal && steal > 0) {
+ fprintf(fp, "AAA,steal,1\n");
+ first_steal = 0;
+ }
+ if (cpu_no == 0)
+ fprintf(fp, "CPU_ALL,%s,%.1lf,%.1lf,%.1lf,%.1f,%.1lf,,%d\n",
+ LOOP, user, kernel, iowait, idle, steal, cpus);
+ else {
+ fprintf(fp, "CPU%03d,%s,%.1lf,%.1lf,%.1lf,%.1lf,%.1f\n",
+ cpu_no, LOOP, user, kernel, iowait, idle, steal);
+ }
+ }
+}
+
+/* Added variable to remember started children
+ * 0 - start
+ * 1 - snap
+ * 2 - end
+*/
+#define CHLD_START 0
+#define CHLD_SNAP 1
+#define CHLD_END 2
+int nmon_children[3] = { -1, -1, -1 };
+
+void init_pairs()
+{
+ COLOUR init_pair((short) 0, (short) 7, (short) 0); /* White */
+ COLOUR init_pair((short) 1, (short) 1, (short) 0); /* Red */
+ COLOUR init_pair((short) 2, (short) 2, (short) 0); /* Green */
+ COLOUR init_pair((short) 3, (short) 3, (short) 0); /* Yellow */
+ COLOUR init_pair((short) 4, (short) 4, (short) 0); /* Blue */
+ COLOUR init_pair((short) 5, (short) 5, (short) 0); /* Magenta */
+ COLOUR init_pair((short) 6, (short) 6, (short) 0); /* Cyan */
+ COLOUR init_pair((short) 7, (short) 7, (short) 0); /* White */
+ COLOUR init_pair((short) 8, (short) 0, (short) 1); /* Red background, red text */
+ COLOUR init_pair((short) 9, (short) 0, (short) 2); /* Green background, green text */
+ COLOUR init_pair((short) 10, (short) 0, (short) 4); /* Blue background, blue text */
+ COLOUR init_pair((short) 11, (short) 0, (short) 3); /* Yellow background, yellow text */
+ COLOUR init_pair((short) 12, (short) 0, (short) 6); /* Cyan background, cyan text */
+}
+
+/* Signal handler
+ * SIGUSR1 or 2 is used to stop nmon cleanly
+ * SIGWINCH is used when the window size is changed
+ */
+void interrupt(int signum)
+{
+ int child_pid;
+ int waitstatus;
+ if (signum == SIGCHLD) {
+ while ((child_pid = waitpid(0, &waitstatus, 0)) == -1) {
+ if (errno == EINTR) /* retry */
+ continue;
+ return; /* ECHLD, EFAULT */
+ }
+ if (child_pid == nmon_children[CHLD_SNAP])
+ nmon_children[CHLD_SNAP] = -1;
+ signal(SIGCHLD, interrupt);
+ return;
+ }
+ if (signum == SIGUSR1 || signum == SIGUSR2) {
+ maxloops = loop;
+ return;
+ }
+ if (signum == SIGWINCH) {
+ CURSE endwin(); /* stop + start curses so it works out the # of row and cols */
+ CURSE initscr();
+ CURSE cbreak();
+ signal(SIGWINCH, interrupt);
+ COLOUR colour = has_colors();
+ COLOUR start_color();
+ COLOUR init_pairs();
+ CURSE clear();
+ return;
+ }
+ CURSE endwin();
+ exit(0);
+}
+
+
+/* only place the q=previous and p=currect pointers are modified */
+void switcher(void)
+{
+ static int which = 1;
+ int i;
+
+ if (which) {
+ p = &database[0];
+ q = &database[1];
+ which = 0;
+ } else {
+ p = &database[1];
+ q = &database[0];
+ which = 1;
+ }
+ if (flash_on)
+ flash_on = 0;
+ else
+ flash_on = 1;
+
+ /* Reset flags so /proc/... is re-read in next interval */
+ for (i = 0; i < P_NUMBER; i++) {
+ proc[i].read_this_interval = 0;
+ }
+#ifdef POWER
+ lparcfg_processed = 0;
+#endif
+}
+
+
+/* Lookup the right string */
+char *status(int n)
+{
+ switch (n) {
+ case 0:
+ return "Run ";
+ default:
+ return "Sleep";
+ }
+}
+
+/* Lookup the right process state string */
+char *get_state(char n)
+{
+ static char duff[64];
+ switch (n) {
+ case 'R':
+ return "Running ";
+ case 'S':
+ return "Sleeping ";
+ case 'D':
+ return "DiskSleep";
+ case 'Z':
+ return "Zombie ";
+ case 'T':
+ return "Traced ";
+ case 'W':
+ return "Paging ";
+ default:
+ snprintf(duff, 64, "%d", n);
+ return duff;
+ }
+}
+
+/* User Defined Disk Groups */
+char *save_word(char *in, char *out)
+{
+ int len;
+ int i;
+ len = strlen(in);
+ out[0] = 0;
+ for (i = 0; i < len; i++) {
+ if (isalnum(in[i]) || in[i] == '_' || in[i] == '-' || in[i] == '/') {
+ out[i] = in[i];
+ out[i + 1] = 0;
+ } else
+ break;
+ }
+ for (; i < len; i++)
+ if (isalnum(in[i]))
+ return &in[i];
+ return &in[i];
+}
+
+#define DGROUPS 64
+#define DGROUPITEMS 512
+
+char *dgroup_filename;
+char *dgroup_name[DGROUPS];
+int *dgroup_data;
+int dgroup_disks[DGROUPS];
+int dgroup_total_disks = 0;
+int dgroup_total_groups;
+
+void load_dgroup(struct dsk_stat *dk)
+{
+ FILE *gp;
+ char line[4096];
+ char name[1024];
+ int i, j;
+ char *nextp;
+
+ if (dgroup_loaded == 2)
+ return;
+ dgroup_data = MALLOC(sizeof(int) * DGROUPS * DGROUPITEMS);
+ for (i = 0; i < DGROUPS; i++)
+ for (j = 0; j < DGROUPITEMS; j++)
+ dgroup_data[i * DGROUPITEMS + j] = -1;
+
+ gp = fopen(dgroup_filename, "r");
+
+ if (gp == NULL) {
+ perror("opening disk group file");
+ fprintf(stderr, "ERROR: failed to open %s\n", dgroup_filename);
+ exit(9);
+ }
+
+ for (dgroup_total_groups = 0;
+ fgets(line, 4096 - 1, gp) != NULL
+ && dgroup_total_groups < DGROUPS; dgroup_total_groups++) {
+ /* ignore lines starting with # */
+ if (line[0] == '#') { /* was a comment line */
+ /* Decrement dgroup_total_groups by 1 to correct index for next loop */
+ --dgroup_total_groups;
+ continue;
+ }
+ /* save the name */
+ nextp = save_word(line, name);
+ if (strlen(name) == 0) { /* was a blank line */
+ fprintf(stderr,
+ "ERROR nmon:ignoring odd line in diskgroup file \"%s\"\n",
+ line);
+ /* Decrement dgroup_total_groups by 1 to correct index for next loop */
+ --dgroup_total_groups;
+ continue;
+ }
+ /* Added +1 to be able to correctly store the terminating \0 character */
+ dgroup_name[dgroup_total_groups] = MALLOC(strlen(name) + 1);
+ strcpy(dgroup_name[dgroup_total_groups], name);
+
+ /* save the hdisks */
+ for (i = 0; i < DGROUPITEMS && *nextp != 0; i++) {
+ nextp = save_word(nextp, name);
+ for (j = 0; j < disks; j++) {
+ if (strcmp(dk[j].dk_name, name) == 0) {
+ /*DEBUG printf("DGadd group=%s,name=%s,disk=%s,dgroup_total_groups=%d,dgroup_total_disks=%d,j=%d,i=%d,index=%d.\n",
+ dgroup_name[dgroup_total_groups],
+ name, dk[j].dk_name, dgroup_total_groups, dgroup_total_disks, j, i,dgroup_total_groups*DGROUPITEMS+i);
+ */
+ dgroup_data[dgroup_total_groups * DGROUPITEMS + i] = j;
+ dgroup_disks[dgroup_total_groups]++;
+ dgroup_total_disks++;
+ break;
+ }
+ }
+ if (j == disks)
+ fprintf(stderr,
+ "ERROR nmon:diskgroup file - failed to find disk=%s for group=%s disks known=%d\n",
+ name, dgroup_name[dgroup_total_groups], disks);
+ }
+ }
+ fclose(gp);
+ dgroup_loaded = 2;
+}
+
+
+void list_dgroup(struct dsk_stat *dk)
+{
+ int i, j, k, n;
+ int first = 1;
+
+ /* DEBUG for (n = 0, i = 0; i < dgroup_total_groups; i++) {
+ fprintf(fp, "CCCG,%03d,%s", n++, dgroup_name[i]);
+ for (j = 0; j < dgroup_disks[i]; j++) {
+ if (dgroup_data[i*DGROUPITEMS+j] != -1) {
+ fprintf(fp, ",%d=%d", j, dgroup_data[i*DGROUPITEMS+j]);
+ }
+ }
+ fprintf(fp, "\n");
+ }
+ */
+ if (!show_dgroup)
+ return;
+
+ for (n = 0, i = 0; i < dgroup_total_groups; i++) {
+ if (first) {
+ fprintf(fp, "BBBG,%03d,User Defined Disk Groups Name,Disks\n",
+ n++);
+ first = 0;
+ }
+ fprintf(fp, "BBBG,%03d,%s", n++, dgroup_name[i]);
+ for (k = 0, j = 0; j < dgroup_disks[i]; j++) {
+ if (dgroup_data[i * DGROUPITEMS + j] != -1) {
+ fprintf(fp, ",%s",
+ dk[dgroup_data[i * DGROUPITEMS + j]].dk_name);
+ k++;
+ }
+ /* add extra line if we have lots to stop spreadsheet line width problems */
+ if (k == 128) {
+ fprintf(fp, "\nBBBG,%03d,%s continued", n++,
+ dgroup_name[i]);
+ }
+ }
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "DGBUSY,Disk Group Busy %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGREAD,Disk Group Read KB/s %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGWRITE,Disk Group Write KB/s %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGSIZE,Disk Group Block Size KB %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGXFER,Disk Group Transfers/s %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+
+ /* If requested provide additional data available in /proc/diskstats */
+ if (extended_disk == 1 && disk_mode == DISK_MODE_DISKSTATS) {
+ fprintf(fp, "DGREADS,Disk Group read/s %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGREADMERGE,Disk Group merged read/s %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGREADSERV,Disk Group read service time (SUM ms) %s",
+ hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGWRITES,Disk Group write/s %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGWRITEMERGE,Disk Group merged write/s %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp,
+ "DGWRITESERV,Disk Group write service time (SUM ms) %s",
+ hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGINFLIGHT,Disk Group in flight IO %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGBACKLOG,Disk Group Backlog time (ms) %s", hostname);
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] != 0)
+ fprintf(fp, ",%s", dgroup_name[i]);
+ }
+ fprintf(fp, "\n");
+ }
+}
+
+int is_dgroup_name(char *name)
+{
+ int i;
+ for (i = 0; i < DGROUPS; i++) {
+ if (dgroup_name[i] == (char *) 0)
+ return 0;
+ if (strncmp(name, dgroup_name[i], strlen(name)) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
+
+void hint(void)
+{
+ printf("Hint for %s version %s\n", progname, VERSION);
+ printf("\tFull Help Info : %s -h\n\n", progname);
+ printf("\tOn-screen Stats: %s\n", progname);
+ printf
+ ("\tData Collection: %s -f [-s ] [-c ] [-t|-T]\n",
+ progname);
+ printf("\tCapacity Plan : %s -x\n", progname);
+ printf("Interactive-Mode:\n");
+ printf
+ ("\tRead the Welcome screen & at any time type: \"h\" for more help\n");
+ printf("\tType \"q\" to exit nmon\n\n");
+ printf("For Data-Collect-Mode\n");
+ printf
+ ("\t-f Must be the first option on the line (switches off interactive mode)\n");
+ printf
+ ("\t Saves data to a CSV Spreadsheet format .nmon file in then local directory\n");
+ printf
+ ("\t Note: -f sets a defaults -s300 -c288 which you can then modify\n");
+ printf("\tFurther Data Collection Options:\n");
+ printf("\t-s time between data snapshots\n");
+ printf("\t-c of snapshots before exiting\n");
+ printf
+ ("\t-t Includes Top Processes stats (-T also collects command arguments)\n");
+ printf
+ ("\t-x Capacity Planning=15 min snapshots for 1 day. (nmon -ft -s 900 -c 96)\n");
+ printf("---- End of Hints\n");
+}
+
+void help(void)
+{
+ hint();
+ printf("---- Full Help Information for %s\n\n", SccsId);
+ printf("For Interactive and Data Collection Mode:\n");
+ printf("\tUser Defined Disk Groups (DG) - This works in both modes\n");
+ printf ("\tIt is a work around Linux issues, where disks & partitions are mixed up in /proc files\n");
+ printf ("\t& drive driver developers use bizarre device names, making it trick to separate them.\n");
+ printf("\t-g Use this file to define the groups\n");
+ printf ("\t - On each line: group-name (space separated list)\n");
+ printf("\t - Example line: database sdb sdc sdd sde\n");
+ printf("\t - Up to 64 disk groups, 512 disks per line\n");
+ printf ("\t - Disks names can appear more than one group\n");
+ printf ("\t-g auto - Will generate a file called \"auto\" with just disks from \"lsblk|grep disk\" output\n");
+ printf("\t For Interactive use define the groups then type: g or G\n");
+ printf ("\t For Data Capture defining the groups switches on data collection\n");
+ printf("\n");
+ printf ("Data-Collect-Mode = spreadsheet format (i.e. comma separated values)\n");
+ printf ("\tNote: Use only one of f, F, R, x, X or z to switch on Data Collection mode\n");
+ printf ("\tNote: Make it the first argument then use other options to modify the defaults\n");
+ printf ("\tNote: Don't collect data that you don't want - it just makes the files too large\n");
+ printf ("\tNote: Too many snapshots = too much data and crashes Analyser and other tools\n");
+ printf ("\tNote: 500 to 800 snapshots make a good graph on a normal size screen\n");
+ printf ("\tRecommended normal minimal options: snapshots every 2 minutes all day: \n");
+ printf("\t\tSimple capture: nmon -f -s 120 -c 720\n");
+ printf("\t\tWith Top Procs: nmon -fT -s 120 -c 720\n");
+ printf ("\t\tSet the directory: nmon -fT -s 120 -c 720 -m /home/nag/nmon\n");
+ printf
+ ("\t\tCapture a busy hour: nmon -fT -s 5 -c 720 -m /home/nag/nmon\n");
+ printf("\n");
+ printf("For Data-Collect-Mode Options\n");
+ printf
+ ("\t-f spreadsheet output format [note: default -s300 -c288]\n");
+ printf("\t\t\t output file is _YYYYMMDD_HHMM.nmon\n");
+ printf("\t-F same as -f but user supplied filename\n");
+ printf("\t\t\t Not recommended as the default file name is perfect\n");
+ printf("\tThe other options in alphabetical order:\n");
+ printf("\t-a Include Accelerator GPU stats\n");
+ printf
+ ("\t-b Online only: for black and white mode (switch off colour)\n");
+ printf("\t-c The number of snapshots before nmon stops\n");
+ printf
+ ("\t-d To set the maximum number of disks [default 256]\n");
+ printf
+ ("\t Ignores disks if the systems has 100's of disk or the config is odd!\n");
+ printf
+ ("\t-D Use with -g to add the Disk Wait/Service Time & in-flight stats\n");
+ printf("\t-f and -F See above\n");
+ printf
+ ("\t-g User Defined Disk Groups (see above) - Data Capture: Generates BBBG & DG lines\n");
+ printf
+ ("\t-g auto See above but makes the file \"auto\" for you of just the disks like sda etc.\n");
+ printf("\t-h This help output\n");
+ printf
+ ("\t-I Set the ignore process & disks busy threshold (default 0.1%%)\n");
+ printf
+ ("\t Don't save or show proc/disk using less than this percent\n");
+ printf
+ ("\t-J Switch-off Journel Filesystem stats collection (can causes issues with automound NFS)\n");
+ printf
+ ("\t-l Disks per line in data capture to avoid spreadsheet width issues. Default 150. EMC=64.\n");
+ printf
+ ("\t-m nmon changes to this directory before saving to file\n");
+ printf("\t Useful when starting nmon via cron\n");
+ printf
+ ("\t-M Adds MHz stats for each CPU thread. Some POWER8 model CPU cores can be different frequencies\n");
+ printf
+ ("\t-N Include NFS Network File System for V2, V3 and V4\n");
+ printf
+ ("\t-p nmon outputs the PID when it starts. Useful in scripts to capture the PID for a later safe stop.\n");
+ printf
+ ("\t-r Use in a benchmark to record the run details for later analysis [default hostname]\n");
+ printf
+ ("\t-R Old rrdtool format used by some - may be removed in the future. If you use this email Nigel\n");
+ printf
+ ("\t-s Time between snap shots - with \"-c count\" decides duration of the data capture\n");
+ printf("\t-t Include Top Processes in the output\n");
+ printf
+ ("\t-T As -t plus it saves command line arguments in UARG section\n");
+ printf
+ ("\t-U Include the Linux 10 CPU utilisation stats (CPUUTIL lines in the file)\n");
+ printf("\t-V Print nmon version & exit immediately\n");
+ printf("\n");
+ printf("\tTo manually load nmon files into a spreadsheet:\n");
+ printf("\t\tsort -A *nmon >stats.csv\n");
+ printf("\t\tTransfer the stats.csv file to your PC\n");
+ printf
+ ("\t\tStart spreadsheet & then Open with type=comma-separated-value ASCII file\n");
+ printf("\t\tThis puts every datum in a different cell\n");
+ printf
+ ("\t\tNow select the data of one type (same 1st column) and graph it\n");
+ printf
+ ("\t\tThe nmon Analyser & other tools do not need the file sorted.\n");
+ printf("\n");
+ printf("Capacity Planning mode - use cron to run each day\n");
+ printf("\t-x Sensible spreadsheet output for one day\n");
+ printf
+ ("\t Every 15 mins for 1 day ( i.e. -ft -s 900 -c 96)\n");
+ printf("\t-X Sensible spreadsheet output for busy hour\n");
+ printf
+ ("\t Every 30 secs for 1 hour ( i.e. -ft -s 30 -c 120)\n");
+ printf
+ ("\t-z Like -x but the output saved in /var/perf/tmp assuming root user\n");
+ printf("\n");
+
+ printf("Interactive Mode Keys in Alphabetical Order\n");
+ printf
+ (" Start nmon then type the letters below to switch on & off particular stats\n");
+ printf(" The stats are always in the same order on-screen\n");
+ printf
+ (" To see more stats: make the font smaller or use two windows\n\n");
+ printf("\tKey --- Toggles on off to control what is displayed ---\n");
+#ifdef NVIDIA_GPU
+ printf("\ta = Accelerator from Nvidia GPUs\n");
+#endif /*NVIDIA_GPU */
+ printf
+ ("\tb = Black and white mode (or use -b command line option)\n");
+ printf
+ ("\tc = CPU Utilisation stats with bar graphs (CPU core threads)\n");
+ printf
+ ("\tC = CPU Utilisation as above but concise wide view (up to 192 CPUs)\n");
+ printf("\td = Disk I/O Busy%% & Graphs of Read and Write KB/s\n");
+ printf
+ ("\tD = Disk I/O Numbers including Transfers, Average Block Size & Peaks (type: 0 to reset)\n");
+ printf
+ ("\tg = User Defined Disk Groups (assumes -g when starting nmon)\n");
+ printf
+ ("\tG = Change Disk stats (d) to just disks (assumes -g auto when starting nmon)\n");
+ printf("\th = This help information\n");
+ printf("\tj = File Systems including Journal File Systems\n");
+ printf("\tJ = Reduces \"j\" output by removing unreal File Systems\n");
+ printf
+ ("\tk = Kernel stats Run Queue, context-switch, fork, Load Average & Uptime\n");
+ printf
+ ("\tl = Long term Total CPU (over 75 snapshots) via bar graphs\n");
+ printf("\tL = Large and =Huge memory page stats\n");
+ printf("\tm = Memory & Swap stats\n");
+ printf
+ ("\tM = MHz for machines with variable frequency 1st=Threads 2nd=Cores 3=Graphs\n");
+ printf
+ ("\tn = Network stats & errors (if no errors it disappears)\n");
+ printf("\tN = NFS - Network File System\n");
+ printf("\t 1st NFS V2 & V3, 2nd=NFS4-Client & 3rd=NFS4-Server\n");
+ printf
+ ("\to = Disk I/O Map (one character per disk pixels showing how busy it is)\n");
+ printf("\t Particularly good if you have 100's of disks \n");
+#ifdef PARTITIONS
+ printf("\tP = Partitions Disk I/O Stats\n");
+#endif
+#ifdef POWER
+ printf("\tp = PowerVM LPAR Stats from /proc/ppc64/lparcfg\n");
+#endif
+ printf("\tq = Quit\n");
+ printf
+ ("\tr = Resources: Machine type, name, cache details & OS version & Distro + LPAR\n");
+ printf
+ ("\tt = Top Processes: select the data & order 1=Basic, 3=Perf 4=Size 5=I/O=root only\n");
+ printf("\tu = Top Process with command line details\n");
+ printf("\tU = CPU utilisation stats - all 10 Linux stats:\n");
+ printf
+ ("\t user, user_nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice\n");
+ printf
+ ("\tv = Experimental Verbose mode - tries to make recommendations\n");
+ printf("\tV = Virtual Memory stats\n");
+ printf("\n");
+ printf("\tKey --- Other Interactive Controls ---\n");
+ printf("\t+ = Double the screen refresh time\n");
+ printf("\t- = Halves the screen refresh time\n");
+ printf
+ ("\t0 = Reset peak counts to zero (peak highlight with \">\")\n");
+ printf("\t1 = Top Processes mode 1 Nice, Priority, Status\n");
+ printf("\t3 = Top Processes mode 3 CPU, Memory, Faults\n");
+ printf("\t4 = Top Processes mode 4 as 3 but order by memory\n");
+ printf
+ ("\t5 = Top Processes mode 5 as 3 but order by I/O (if root user)\n");
+ printf("\t6 = Highlights 60%% row on Long Term CPU view\n");
+ printf("\t7 = Highlights 70%% row on Long Term CPU view\n");
+ printf("\t8 = Highlights 80%% row on Long Term CPU view\n");
+ printf("\t9 = Highlights 90%% row on Long Term CPU view\n");
+ printf
+ ("\t. = Minimum mode i.e. only busy disks and processes shown\n");
+ printf("\tspace = Refresh screen now\n");
+
+ printf("\n");
+ printf("Interactive Start-up Control\n");
+ printf
+ ("\tIf you find you always type the same toggles every time you start\n");
+ printf("\tthen place them in the NMON shell variable. For example:\n");
+ printf("\t export NMON=cmdrtn\n");
+
+ printf("\n");
+ printf("Other items for Interactive and Data Collection mode:\n");
+ printf
+ ("\ta) To limit the processes nmon lists (online and to a file)\n");
+ printf
+ ("\t either set NMONCMD0 to NMONCMD63 to the program names\n");
+ printf("\t or use -C cmd:cmd:cmd etc. example: -C ksh:vi:syncd\n");
+ printf("Other items for Data Collection mode:\n");
+ printf("\tb) To you want to stop nmon use: kill -USR2 \n");
+ printf("\tc) Use -p and nmon outputs the background process pid\n");
+ printf
+ ("\td) If you want to pipe nmon output to other commands use a FIFO:\n");
+ printf("\t mkfifo /tmp/mypipe\n");
+ printf("\t nmon -F /tmp/mypipe &\n");
+ printf("\t tail -f /tmp/mypipe\n");
+ printf("\te) If nmon fails please report it with:\n");
+ printf("\t 1) nmon version like: %s\n", VERSION);
+ printf
+ ("\t 2) the output of: cd /proc; cat cpuinfo meminfo partitions stat vmstat\n");
+ printf("\t 3) some clue of what you were doing\n");
+ printf
+ ("\t 4) I may ask you to run the debug version or collect data files\n");
+ printf
+ ("\tf) If box & line characters are letters then check: terminal emulator & $TERM\n");
+ printf
+ ("\tg) External Data Collectors - nmon will execute a command or script at each snapshot time\n");
+ printf
+ ("\t They must output to a different file which is merge afterwards with the nmon output\n");
+ printf("\t Set the following shell variables:\n");
+ printf
+ ("\t NMON_START = script to generate CVS Header test line explaining the columns\n");
+ printf
+ ("\t Generate: TabName,DataDescription,Column_name_and_units,Column_name_and_units ... \n");
+ printf
+ ("\t NMON_SNAP = script for each snapshots data, the parameter is the T0000 snapshot number\n");
+ printf("\t Generate: TabName,T00NN,Data,Data,Data ...\n");
+ printf
+ ("\t NMON_END = script to clean up or finalise the data\n");
+ printf
+ ("\t NMON_ONE_IN = call NMON_START less often (if it is heavy in CPU terms)\n");
+ printf
+ ("\t Once capture done: cat nmon-file data-file >merged-file ; ready for Analyser or other tools\n");
+ printf
+ ("\t The nmon Analyser will automatically do its best to graph the data on a new Tab sheet\n");
+ printf("\n");
+ printf
+ ("\tDeveloper: Nigel Griffiths See http://nmon.sourceforge.net\n");
+ printf("\tFeedback welcome - On the current release only\n");
+ printf("\tNo warranty given or implied. (C) Copyright 2009 Nigel Griffiths GPLv3\n");
+ exit(0);
+}
+
+#define JFSMAX 128
+#define LOAD 1
+#define UNLOAD 0
+#define JFSNAMELEN 64
+#define JFSTYPELEN 8
+
+struct jfs {
+ char name[JFSNAMELEN+1];
+ char device[JFSNAMELEN+1];
+ char type[JFSNAMELEN+1];
+ int fd;
+ int mounted;
+} jfs[JFSMAX];
+
+int jfses = 0;
+void jfs_load(int load)
+{
+ int i;
+ struct stat stat_buffer;
+ FILE *mfp; /* FILE pointer for mtab file */
+ struct mntent *mp; /* mnt point stats */
+ static int jfs_loaded = 0;
+
+ if (load == LOAD) {
+ if (jfs_loaded == 0) {
+ mfp = setmntent("/etc/mtab", "r");
+ for (i = 0; i < JFSMAX && (mp = getmntent(mfp)) != NULL; i++) {
+ strncpy(jfs[i].device, mp->mnt_fsname, JFSNAMELEN + 1);
+ strncpy(jfs[i].name, mp->mnt_dir, JFSNAMELEN + 1);
+ strncpy(jfs[i].type, mp->mnt_type, JFSTYPELEN + 1);
+ mp->mnt_fsname[JFSNAMELEN] = 0;
+ mp->mnt_dir[JFSNAMELEN] = 0;
+ mp->mnt_type[JFSTYPELEN] = 0;
+ }
+ endmntent(mfp);
+ jfs_loaded = 1;
+ jfses = i;
+ }
+
+ /* 1st or later time - just reopen the mount points */
+ for (jfses = 0, i = 0; i < JFSMAX && jfs[i].name[0] != 0; i++) {
+ if (stat(jfs[i].name, &stat_buffer) != -1) {
+ jfs[i].fd = open(jfs[i].name, O_RDONLY);
+ if (jfs[i].fd != -1) {
+ jfs[i].mounted = 1;
+ } else {
+ jfs[i].mounted = 0;
+ }
+ } else
+ jfs[i].mounted = 0;
+ }
+ for (jfses = 0, i = 0; i < JFSMAX && jfs[i].name[0] != 0; i++) {
+ if (jfs[i].mounted == 1)
+ jfses++;
+ }
+ } else { /* this is an unload request */
+ if (jfs_loaded) {
+ for (i = 0; i < JFSMAX && jfs[i].name[0] != 0; i++) {
+ if (jfs[i].fd != 0)
+ close(jfs[i].fd);
+ jfs[i].fd = 0;
+ }
+ }
+ }
+}
+
+/* We order this array rather than the actual process tables
+ * the index is the position in the process table and
+ * the size is the memory used in bytes
+ * the io is the storge I/O performed in the the last period in bytes
+ * the time is the CPU used in the last period in seconds
+ */
+struct topper {
+ int index;
+ int other;
+ double size;
+ double io;
+ int time;
+} *topper;
+int topper_size = 200;
+
+/* Routine used by qsort to order the processes by CPU usage */
+int cpu_compare(const void *a, const void *b)
+{
+ return (int) (((struct topper *) b)->time -
+ ((struct topper *) a)->time);
+}
+
+int size_compare(const void *a, const void *b)
+{
+ return (int) ((((struct topper *) b)->size -
+ ((struct topper *) a)->size));
+}
+
+int disk_compare(const void *a, const void *b)
+{
+ return (int) ((((struct topper *) b)->io - ((struct topper *) a)->io));
+}
+
+
+/* checkinput is the subroutine to handle user input */
+int checkinput(void)
+{
+ static int use_env = 1;
+ char buf[1024];
+ int bytes;
+ int chars;
+ int i;
+ char *p;
+
+ if (!cursed) /* not user input so stop with control-C */
+ return 0;
+ ioctl(fileno(stdin), FIONREAD, &bytes);
+
+ if (bytes > 0 || use_env) {
+ if (use_env) {
+ use_env = 0;
+ p = getenv("NMON");
+ if (p != 0) {
+ strncpy(buf, p, 1024);
+ buf[1024 - 1] = 0;
+ chars = strlen(buf);
+ } else
+ chars = 0;
+ } else {
+ if(bytes > 1024) { /* block over flowing the buffer */
+ bytes = 1023;
+ buf[1023]=0;
+ }
+ chars = read(fileno(stdin), buf, bytes);
+ }
+ if (chars > 0) {
+ welcome = 0;
+ for (i = 0; i < chars; i++) {
+ switch (buf[i]) {
+ case '1':
+ show_topmode = 1;
+ show_top = 1;
+ wclear(padtop);
+ break;
+/* case '2':
+ show_topmode = 2;
+ show_top = 1;
+ clear();
+ break;
+*/
+ case '3':
+ show_topmode = 3;
+ show_top = 1;
+ wclear(padtop);
+ break;
+ case '4':
+ show_topmode = 4;
+ show_top = 1;
+ wclear(padtop);
+ break;
+ case '5':
+ if (isroot) {
+ show_topmode = 5;
+ show_top = 1;
+ wclear(padtop);
+ }
+ break;
+ case '0':
+ for (i = 0; i < (max_cpus + 1); i++)
+ cpu_peak[i] = 0;
+ for (i = 0; i < networks; i++) {
+ net_read_peak[i] = 0.0;
+ net_write_peak[i] = 0.0;
+ }
+ for (i = 0; i < disks; i++) {
+ disk_busy_peak[i] = 0.0;
+ disk_rate_peak[i] = 0.0;
+ }
+ snap_clear();
+ aiocount_max = 0;
+ aiotime_max = 0.0;
+ aiorunning_max = 0;
+ huge_peak = 0;
+ break;
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ dotline = buf[i] - '0';
+ break;
+ case ' ': /* attempt to refresh the screen */
+ clear();
+ break;
+ case '+':
+ seconds = seconds * 2;
+ break;
+ case '-':
+ seconds = seconds / 2;
+ if (seconds < 1)
+ seconds = 1;
+ break;
+ case '.': /* limit output to processes and disks actually doing work */
+ if (show_all)
+ show_all = 0;
+ else {
+ show_all = 1;
+/* Switching to Nigel's favourite view is confusing to others
+ so disable this feature.
+ show_disk = SHOW_DISK_STATS;
+ show_top = 1;
+ show_topmode = 3;
+*/
+ }
+ wclear(paddisk);
+ break;
+ case '?':
+ case 'h':
+ case 'H':
+ if (show_help)
+ show_help = 0;
+ else {
+ show_help = 1;
+ show_verbose = 0;
+ }
+ wclear(padhelp);
+ break;
+/* alphabetic order from here */
+#ifdef NVIDIA_GPU
+ case 'a': /* Accelerator */
+ case 'E': /* Emily mode */
+ FLIP(show_gpu);
+ wclear(padgpu);
+ break;
+#endif /* NVIDIA_GPU */
+ case 'b':
+ FLIP(colour);
+ clear();
+ break;
+ case 'c':
+ FLIP(show_smp);
+ wclear(padsmp);
+ break;
+ case 'C':
+ FLIP(show_wide);
+ wclear(padwide);
+ break;
+ case 'D':
+ switch (show_disk) {
+ case SHOW_DISK_NONE:
+ show_disk = SHOW_DISK_STATS;
+ break;
+ case SHOW_DISK_STATS:
+ show_disk = SHOW_DISK_NONE;
+ break;
+ case SHOW_DISK_GRAPH:
+ show_disk = SHOW_DISK_STATS;
+ break;
+ }
+ wclear(paddisk);
+ break;
+ case 'd':
+ switch (show_disk) {
+ case SHOW_DISK_NONE:
+ show_disk = SHOW_DISK_GRAPH;
+ break;
+ case SHOW_DISK_STATS:
+ show_disk = SHOW_DISK_GRAPH;
+ break;
+ case SHOW_DISK_GRAPH:
+ show_disk = 0;
+ break;
+ }
+ wclear(paddisk);
+ break;
+
+ break;
+ case 'G':
+ if (auto_dgroup) {
+ FLIP(disk_only_mode);
+ clear();
+ }
+ break;
+ case 'g':
+ FLIP(show_dgroup);
+ wclear(paddg);
+ break;
+
+ case 'j':
+ FLIP(show_jfs);
+ jfs_load(show_jfs);
+ wclear(padjfs);
+ break;
+ case 'J':
+ FLIP(show_jfs_minimum);
+ wclear(padjfs);
+ break;
+ case 'k':
+ FLIP(show_kernel);
+ wclear(padker);
+ break;
+ case 'l':
+ FLIP(show_longterm);
+ wclear(padlong);
+ break;
+ case 'L':
+ FLIP(show_large);
+ wclear(padlarge);
+ break;
+ case 'm':
+ FLIP(show_memory);
+ wclear(padmem);
+ break;
+ case 'M':
+ show_mhz++;
+ if (show_mhz == 4)
+ show_mhz = 0;
+ wclear(padmhz);
+ break;
+ case 'n':
+ if (show_net) {
+ show_net = 0;
+ show_neterror = 0;
+ } else {
+ show_net = 1;
+ show_neterror = 3;
+ }
+ wclear(padnet);
+ break;
+ case 'N':
+ if (show_nfs == 0)
+ show_nfs = 1;
+ else if (show_nfs == 1)
+ show_nfs = 2;
+ else if (show_nfs == 2)
+ show_nfs = 3;
+ else if (show_nfs == 3)
+ show_nfs = 0;
+ nfs_clear = 1;
+ wclear(padnfs);
+ break;
+ case 'o':
+ FLIP(show_diskmap);
+ wclear(padmap);
+ break;
+#ifdef POWER
+ case 'p':
+ FLIP(show_lpar);
+ wclear(padlpar);
+ break;
+#endif
+ case 'r':
+ FLIP(show_res);
+ wclear(padres);
+ break;
+ case 't':
+ show_topmode = 3; /* Fall Through */
+ case 'T':
+ FLIP(show_top);
+ wclear(padtop);
+ break;
+ case 'v':
+ FLIP(show_verbose);
+ wclear(padverb);
+ break;
+ case 'u':
+ if (show_args == ARGS_NONE) {
+ args_load();
+ show_args = ARGS_ONLY;
+ show_top = 1;
+ if (show_topmode != 3 &&
+ show_topmode != 4 && show_topmode != 5)
+ show_topmode = 3;
+ } else
+ show_args = ARGS_NONE;
+ wclear(padtop);
+ break;
+ case 'U':
+ FLIP(show_util);
+ wclear(padutil);
+ break;
+ case 'V':
+ FLIP(show_vm);
+ wclear(padpage);
+ break;
+ case 'x':
+ case 'q':
+ nocbreak();
+ endwin();
+ exit(0);
+ default:
+ return 0;
+ }
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void go_background(int def_loops, int def_secs)
+{
+ cursed = 0;
+ if (maxloops == -1)
+ maxloops = def_loops;
+ if (seconds == -1)
+ seconds = def_secs;
+ show_res = 1;
+ show_smp = 1;
+ show_disk = SHOW_DISK_STATS;
+ show_jfs = 1;
+ show_memory = 1;
+ show_large = 1;
+ show_kernel = 1;
+ show_net = 1;
+ show_all = 1;
+ show_top = 0; /* top process */
+ show_topmode = 3;
+ show_lpar = 1;
+ show_vm = 1;
+}
+
+void proc_net()
+{
+ static FILE *fp = (FILE *) - 1;
+ char buf[1024];
+ int i = 0;
+ int ret;
+ unsigned long junk;
+
+ if (fp == (FILE *) - 1) {
+ if ((fp = fopen("/proc/net/dev", "r")) == NULL) {
+ error("failed to open - /proc/net/dev");
+ networks = 0;
+ return;
+ }
+ }
+ if (fgets(buf, 1024, fp) == NULL)
+ goto end; /* throw away the header lines */
+ if (fgets(buf, 1024, fp) == NULL)
+ goto end; /* throw away the header lines */
+/*
+Inter-| Receive | Transmit
+ face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
+ lo: 1956 30 0 0 0 0 0 0 1956 30 0 0 0 0 0 0
+ eth0: 0 0 0 0 0 0 0 0 458718 0 781 0 0 0 781 0
+ sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ eth1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+*/
+ for (i = 0; i < NETMAX; i++) {
+ if (fgets(buf, 1024, fp) == NULL)
+ break;
+ strip_spaces(buf);
+ /* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */
+ ret =
+ sscanf(&buf[0],
+ "%s %llu %llu %lu %lu %lu %lu %lu %lu %llu %llu %lu %lu %lu %lu %lu",
+ (char *) &p->ifnets[i].if_name, &p->ifnets[i].if_ibytes,
+ &p->ifnets[i].if_ipackets, &p->ifnets[i].if_ierrs,
+ &p->ifnets[i].if_idrop, &p->ifnets[i].if_ififo,
+ &p->ifnets[i].if_iframe, &junk, &junk,
+ &p->ifnets[i].if_obytes, &p->ifnets[i].if_opackets,
+ &p->ifnets[i].if_oerrs, &p->ifnets[i].if_odrop,
+ &p->ifnets[i].if_ofifo, &p->ifnets[i].if_ocolls,
+ &p->ifnets[i].if_ocarrier);
+ if (ret != 16)
+ fprintf(stderr, "sscanf wanted 16 returned = %d line=%s\n",
+ ret, (char *) buf);
+ }
+ end:
+ if (reread) {
+ fclose(fp);
+ fp = (FILE *) - 1;
+ } else
+ rewind(fp);
+ networks = i;
+}
+
+
+int proc_procsinfo(int pid, int index)
+{
+ FILE *fp;
+ char filename[64];
+ char buf[1024 * 4];
+ int size = 0;
+ int ret = 0;
+ int count = 0;
+ int i;
+
+ snprintf(filename, 64, "/proc/%d/stat", pid);
+ if ((fp = fopen(filename, "r")) == NULL) {
+ snprintf(buf, 1024 * 4, "failed to open file %s", filename);
+ error(buf);
+ return 0;
+ }
+ size = fread(buf, 1, 1024 - 1, fp);
+ fclose(fp);
+ if (size == -1) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "procsinfo read returned = %d assuming process stopped pid=%d\n",
+ ret, pid);
+#endif /*DEBUG*/
+ return 0;
+ }
+ ret = sscanf(buf, "%d (%s)",
+ &p->procs[index].pi_pid, &p->procs[index].pi_comm[0]);
+ if (ret != 2) {
+ fprintf(stderr, "procsinfo sscanf returned = %d line=%s\n", ret,
+ buf);
+ return 0;
+ }
+ p->procs[index].pi_comm[strlen(p->procs[index].pi_comm) - 1] = 0;
+
+ for (count = 0; count < size; count++) /* now look for ") " as dumb Infiniban driver includes "()" */
+ if (buf[count] == ')' && buf[count + 1] == ' ')
+ break;
+
+ if (count == size) {
+#ifdef DEBUG
+ fprintf(stderr, "procsinfo failed to find end of command buf=%s\n",
+ buf);
+#endif /*DEBUG*/
+ return 0;
+ }
+ count++;
+ count++;
+
+ ret = sscanf(&buf[count],
+#ifdef PRE_KERNEL_2_6_18
+ "%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d",
+#else
+ "%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu",
+#endif
+ &p->procs[index].pi_state,
+ &p->procs[index].pi_ppid,
+ &p->procs[index].pi_pgrp,
+ &p->procs[index].pi_session,
+ &p->procs[index].pi_tty_nr,
+ &p->procs[index].pi_tty_pgrp,
+ &p->procs[index].pi_flags,
+ &p->procs[index].pi_minflt,
+ &p->procs[index].pi_cmin_flt,
+ &p->procs[index].pi_majflt,
+ &p->procs[index].pi_cmaj_flt,
+ &p->procs[index].pi_utime,
+ &p->procs[index].pi_stime,
+ &p->procs[index].pi_cutime,
+ &p->procs[index].pi_cstime,
+ &p->procs[index].pi_pri, &p->procs[index].pi_nice,
+#ifdef PRE_KERNEL_2_6_18
+ &p->procs[index].junk,
+#else
+ &p->procs[index].pi_num_threads,
+#endif
+ &p->procs[index].pi_it_real_value,
+ &p->procs[index].pi_start_time,
+ &p->procs[index].pi_vsize,
+ &p->procs[index].pi_rss,
+ &p->procs[index].pi_rlim_cur,
+ &p->procs[index].pi_start_code,
+ &p->procs[index].pi_end_code,
+ &p->procs[index].pi_start_stack,
+ &p->procs[index].pi_esp,
+ &p->procs[index].pi_eip,
+ &p->procs[index].pi_pending_signal,
+ &p->procs[index].pi_blocked_sig,
+ &p->procs[index].pi_sigign,
+ &p->procs[index].pi_sigcatch,
+ &p->procs[index].pi_wchan,
+ &p->procs[index].pi_nswap,
+ &p->procs[index].pi_cnswap,
+ &p->procs[index].pi_exit_signal, &p->procs[index].pi_cpu
+#ifndef PRE_KERNEL_2_6_18
+ ,
+ &p->procs[index].pi_rt_priority,
+ &p->procs[index].pi_policy,
+ &p->procs[index].pi_delayacct_blkio_ticks
+#endif
+ );
+#ifdef PRE_KERNEL_2_6_18
+ if (ret != 37) {
+ fprintf(stderr,
+ "procsinfo2 sscanf wanted 37 returned = %d pid=%d line=%s\n",
+ ret, pid, buf);
+#else
+ if (ret != 40) {
+ fprintf(stderr,
+ "procsinfo2 sscanf wanted 40 returned = %d pid=%d line=%s\n",
+ ret, pid, buf);
+#endif
+ return 0;
+ }
+
+ snprintf(filename, 64, "/proc/%d/statm", pid);
+ if ((fp = fopen(filename, "r")) == NULL) {
+ snprintf(buf, 1024 * 4, "failed to open file %s", filename);
+ error(buf);
+ return 0;
+ }
+ size = fread(buf, 1, 1024 * 4 - 1, fp);
+ fclose(fp); /* close it even if the read failed, the file could have been removed
+ between open & read i.e. the device driver does not behave like a file */
+ if (size == -1) {
+ snprintf(buf, 1024 * 4, "failed to read file %s", filename);
+ error(buf);
+ return 0;
+ }
+
+ ret = sscanf(&buf[0], "%lu %lu %lu %lu %lu %lu %lu",
+ &p->procs[index].statm_size,
+ &p->procs[index].statm_resident,
+ &p->procs[index].statm_share,
+ &p->procs[index].statm_trs,
+ &p->procs[index].statm_lrs,
+ &p->procs[index].statm_drs, &p->procs[index].statm_dt);
+ if (ret != 7) {
+ fprintf(stderr, "sscanf wanted 7 returned = %d line=%s\n", ret,
+ buf);
+ return 0;
+ }
+ if (isroot) {
+ p->procs[index].read_io = 0;
+ p->procs[index].write_io = 0;
+ snprintf(filename, 64, "/proc/%d/io", pid);
+ if ((fp = fopen(filename, "r")) != NULL) {
+ for (i = 0; i < 6; i++) {
+ if (fgets(buf, 1024, fp) == NULL) {
+ break;
+ }
+ if (strncmp("read_bytes:", buf, 11) == 0)
+ sscanf(&buf[12], "%lld", &p->procs[index].read_io);
+ if (strncmp("write_bytes:", buf, 12) == 0)
+ sscanf(&buf[13], "%lld", &p->procs[index].write_io);
+ }
+ }
+
+ if (fp != NULL)
+ fclose(fp);
+ }
+ return 1;
+}
+
+#ifdef DEBUGPROC
+print_procs(int index)
+{
+ printf("procs[%d].pid =%d\n", index, procs[index].pi_pid);
+ printf("procs[%d].comm[0] =%s\n", index,
+ &procs[index].pi_comm[0]);
+ printf("procs[%d].state =%c\n", index, procs[index].pi_state);
+ printf("procs[%d].ppid =%d\n", index, procs[index].pi_ppid);
+ printf("procs[%d].pgrp =%d\n", index, procs[index].pi_pgrp);
+ printf("procs[%d].session =%d\n", index,
+ procs[index].pi_session);
+ printf("procs[%d].tty_nr =%d\n", index, procs[index].pi_tty_nr);
+ printf("procs[%d].tty_pgrp =%d\n", index,
+ procs[index].pi_tty_pgrp);
+ printf("procs[%d].flags =%lu\n", index, procs[index].pi_flags);
+ printf("procs[%d].minflt =%lu\n", index, procs[index].pi_minflt);
+ printf("procs[%d].cmin_flt =%lu\n", index,
+ procs[index].pi_cmin_flt);
+ printf("procs[%d].majflt =%lu\n", index, procs[index].pi_majflt);
+ printf("procs[%d].cmaj_flt =%lu\n", index,
+ procs[index].pi_cmaj_flt);
+ printf("procs[%d].utime =%lu\n", index, procs[index].pi_utime);
+ printf("procs[%d].stime =%lu\n", index, procs[index].pi_stime);
+ printf("procs[%d].cutime =%ld\n", index, procs[index].pi_cutime);
+ printf("procs[%d].cstime =%ld\n", index, procs[index].pi_cstime);
+ printf("procs[%d].pri =%d\n", index, procs[index].pi_pri);
+ printf("procs[%d].nice =%d\n", index, procs[index].pi_nice);
+#ifdef PRE_KERNEL_2_6_18
+ printf("procs[%d].junk =%d\n", index, procs[index].junk);
+#else
+ printf("procs[%d].num_threads =%ld\n", index,
+ procs[index].num_threads);
+#endif
+ printf("procs[%d].it_real_value =%lu\n", index,
+ procs[index].pi_it_real_value);
+ printf("procs[%d].start_time =%lu\n", index,
+ procs[index].pi_start_time);
+ printf("procs[%d].vsize =%lu\n", index, procs[index].pi_vsize);
+ printf("procs[%d].rss =%lu\n", index, procs[index].pi_rss);
+ printf("procs[%d].rlim_cur =%lu\n", index,
+ procs[index].pi_rlim_cur);
+ printf("procs[%d].start_code =%lu\n", index,
+ procs[index].pi_start_code);
+ printf("procs[%d].end_code =%lu\n", index,
+ procs[index].pi_end_code);
+ printf("procs[%d].start_stack =%lu\n", index,
+ procs[index].pi_start_stack);
+ printf("procs[%d].esp =%lu\n", index, procs[index].pi_esp);
+ printf("procs[%d].eip =%lu\n", index, procs[index].pi_eip);
+ printf("procs[%d].pending_signal=%lu\n", index,
+ procs[index].pi_pending_signal);
+ printf("procs[%d].blocked_sig =%lu\n", index,
+ procs[index].pi_blocked_sig);
+ printf("procs[%d].sigign =%lu\n", index,
+ procs[index].pi_sigign);
+ printf("procs[%d].sigcatch =%lu\n", index,
+ procs[index].pi_sigcatch);
+ printf("procs[%d].wchan =%lu\n", index, procs[index].pi_wchan);
+ printf("procs[%d].nswap =%lu\n", index, procs[index].pi_nswap);
+ printf("procs[%d].cnswap =%lu\n", index,
+ procs[index].pi_cnswap);
+ printf("procs[%d].exit_signal =%d\n", index,
+ procs[index].pi_exit_signal);
+ printf("procs[%d].cpu =%d\n", index, procs[index].pi_cpu);
+#ifndef PRE_KERNEL_2_6_18
+ printf("procs[%d].rt_priority =%lu\n", index,
+ procs[index].pi_rt_priority);
+ printf("procs[%d].policy =%lu\n", index,
+ procs[index].pi_policy);
+ printf("procs[%d].delayacct_blkio_ticks=%llu\n", index,
+ procs[index].pi_delayacct_blkio_ticks);
+#endif
+ printf("OK\n");
+}
+#endif /*DEBUG*/
+/* --- */
+int isnumbers(char *s)
+{
+ while (*s != 0) {
+ if (*s < '0' || *s > '9')
+ return 0;
+ s++;
+ }
+ return 1;
+}
+
+int getprocs(int records)
+{
+ struct dirent *dent;
+ DIR *procdir;
+ int count = 0;
+
+ if ((char *) (procdir = opendir("/proc")) == NULL) {
+ printf("opendir(/proc) failed");
+ return 0;
+ }
+ while ((char *) (dent = readdir(procdir)) != NULL) {
+ if (dent->d_type == 4) { /* is this a directlory */
+ /* mainframes report 0 = unknown every time !!!! */
+ if (isnumbers(dent->d_name)) {
+ if (records != 0) {
+ /* getting the details mode */
+ count = count + proc_procsinfo(atoi(dent->d_name), count);
+ if(count == records) {
+ break;
+ }
+ } else {
+ /* just counting the processes mode */
+ count++;
+ }
+ }
+ }
+ }
+ closedir(procdir);
+ return count;
+}
+
+/* --- */
+
+char cpu_line[] =
+ "---------------------------+-------------------------------------------------+";
+/* Start process as specified in cmd in a child process without waiting
+ * for completion
+ * not sure if want to prevent this funcitonality for root user
+ * when: CHLD_START, CHLD_SNAP or CHLD_END
+ * cmd: pointer to command string - assumed to be cleansed ....
+ * timestamp_type: 0 - T%04d, 1 - detailed time stamp
+ * loop: loop id (0 for CHLD_START)
+ * the_time: time to use for timestamp generation
+ */
+void child_start(int when,
+ char *cmd, int timestamp_type, int loop, time_t the_time)
+{
+ int i;
+ pid_t child_pid;
+ char time_stamp_str[64] = "";
+ char *when_info = "";
+ struct tm *tim; /* used to work out the hour/min/second */
+
+#ifdef DEBUG2
+ fprintf(fp, "child start when=%d cmd=%s time=%d loop=%d\n", when, cmd,
+ timestamp_type, loop);
+#endif
+ /* Validate parameter and initialize error text */
+ switch (when) {
+ case CHLD_START:
+ when_info = "nmon fork exec failure CHLD_START";
+ break;
+ case CHLD_END:
+ when_info = "nmon fork exec failure CHLD_END";
+ break;
+
+ case CHLD_SNAP:
+ /* check if old child has finished - otherwise we do nothing */
+ if (nmon_children[CHLD_SNAP] != -1) {
+ if (!cursed)
+ fprintf(fp,
+ "ERROR,T%04d, Starting snap command \"%s\" failed as previous child still running - killing it now\n",
+ loop, cmd);
+ kill(nmon_children[CHLD_SNAP], 9);
+ }
+
+ when_info = "nmon fork exec failure CHLD_SNAP";
+ break;
+ }
+
+
+ /* now fork off a child process. */
+ switch (child_pid = fork()) {
+ case -1: /* fork failed. */
+ perror(when_info);
+ return;
+
+ case 0: /* inside child process. */
+ /* create requested timestamp */
+ if (timestamp_type == 1) {
+ tim = localtime(&the_time);
+ snprintf(time_stamp_str, 64, "%02d:%02d:%02d,%02d,%02d,%04d",
+ tim->tm_hour, tim->tm_min, tim->tm_sec,
+ tim->tm_mday, tim->tm_mon + 1, tim->tm_year + 1900);
+ } else {
+ snprintf(time_stamp_str, 64, "T%04d", loop);
+ }
+
+ /* close all open file pointers except the defaults */
+ for (i = 3; i < 5; ++i)
+ close(i);
+
+ /* Now switch to the defined command */
+ execlp(cmd, cmd, time_stamp_str, (void *) 0);
+
+ /* If we get here the specified command could not be started */
+ perror(when_info);
+ exit(1); /* We can't do anything more */
+ /* never reached */
+
+ default: /* inside parent process. */
+ /* In father - remember child pid for future */
+ nmon_children[when] = child_pid;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int secs;
+ int cpu_idle;
+ int cpu_user;
+ int cpu_sys;
+ int cpu_wait;
+ int cpu_steal;
+ int current_procs = 0;
+ int adjusted_procs = 0;
+ int n = 0; /* reusable counters */
+ int i = 0;
+ int j = 0;
+ int k = 0;
+ int ret = 0;
+ int max_sorted;
+ int skipped;
+ int x = 0; /* curses row */
+ int y = 0; /* curses column */
+ double elapsed; /* actual seconds between screen updates */
+ double cpu_sum;
+ double ftmp;
+ int top_first_time = 1;
+ int disk_first_time = 1;
+ int nfs_first_time = 1;
+ int vm_first_time = 1;
+ int bbbr_line = 0;
+ double cpu_busy;
+#ifdef POWER
+ int lpar_first_time = 1;
+ long max_speed = 0;
+#endif /* POWER */
+ int smp_first_time = 1;
+ int wide_first_time = 1;
+ int proc_first_time = 1;
+ int first_key_pressed = 0;
+ pid_t childpid = -1;
+ int ralfmode = 0;
+ char pgrp[32];
+ struct tm *tim; /* used to work out the hour/min/second */
+ float total_busy; /* general totals */
+ float total_rbytes; /* general totals */
+ float total_wbytes;
+ float total_xfers;
+ struct utsname uts; /* UNIX name, version, etc */
+ double top_disk_busy = 0.0;
+ char *top_disk_name = "";
+ int disk_mb;
+ double disk_total;
+ double disk_busy;
+ double disk_read;
+ double disk_read_tmp;
+ double disk_write;
+ double disk_write_tmp;
+ double disk_size;
+ double disk_xfers;
+ double total_disk_read;
+ double total_disk_write;
+ double total_disk_xfers;
+ double readers;
+ double writers;
+
+ /* for popen on oslevel */
+ char *str_p;
+ int varperftmp = 0;
+ char *formatstring;
+ char *open_filename = 0;
+ char *user_filename = 0;
+ char user_filename_set = 0;
+ char using_stdout = 0;
+ struct statfs statfs_buffer;
+
+ float fs_size;
+ float fs_bsize;
+ float fs_free;
+ float fs_size_used;
+
+ char cmdstr[256];
+ long updays, uphours, upmins;
+ float v2c_total;
+ float v2s_total;
+ float v3c_total;
+ float v3s_total;
+ float v4c_total;
+ float v4s_total;
+ int errors = 0;
+
+ char *nmon_start = (char *) NULL;
+ char *nmon_end = (char *) NULL;
+ char *nmon_snap = (char *) NULL;
+ char *nmon_tmp = (char *) NULL;
+ int nmon_one_in = 1;
+ /* Flag what kind of time stamp we give to started children
+ * 0: "T%04d"
+ * 1: "hh:mm:ss,dd,mm,yyyy"
+ */
+ int time_stamp_type = 0;
+ long ticks = 100; /* Clock ticks per second used in /proc/stat cpu lines */
+ unsigned long pagesize = 1024 * 4; /* Default page size is 4 KB but newer servers compiled with 64 KB pages */
+ float average;
+ struct timeval nmon_tv; /* below is used to workout the nmon run, accumalate it and the
+ allow for in in the sleep time to reduce time drift */
+ double nmon_start_time = 0.0;
+ double nmon_end_time = 0.0;
+ double nmon_run_time = -1.0;
+ int seconds_over = 0;
+ float mhz;
+ float min_mhz;
+ float max_mhz;
+ float avg_mhz = 0.0;
+ unsigned long topsize;
+ char topsize_ch;
+ unsigned long toprset;
+ char toprset_ch;
+ unsigned long toptrs;
+ char toptrs_ch;
+ unsigned long topdrs;
+ char topdrs_ch;
+ unsigned long toplrs;
+ char toplrs_ch;
+ unsigned long topshare;
+ char topshare_ch;
+ unsigned long toprio;
+ char toprio_ch;
+ unsigned long topwio;
+ char topwio_ch;
+ long long tmpslab;
+ char * slabstr;
+ char truncated_command[257]; /* 256 +1 */
+
+
+#define MAXROWS 256
+#define MAXCOLS 150 /* changed to allow maximum column widths */
+#define BANNER(pad,string) {mvwhline(pad, 0, 0, ACS_HLINE,COLS-2); \
+ wmove(pad,0,0); \
+ wattron(pad,A_STANDOUT); \
+ wprintw(pad," "); \
+ wprintw(pad,string); \
+ wprintw(pad," "); \
+ wattroff(pad,A_STANDOUT); }
+
+#define DISPLAY(pad,rows) { \
+ if(x+2+(rows)>LINES)\
+ pnoutrefresh(pad, 0,0,x,1,LINES-2, COLS-2); \
+ else \
+ pnoutrefresh(pad, 0,0,x,1,x+rows+1,COLS-2); \
+ x=x+(rows); \
+ if(x+4>LINES) { \
+ mvwprintw(stdscr,LINES-1,10,"Warning: Some Statistics may not shown"); \
+ } \
+ }
+
+ /* check the user supplied options */
+ progname = argv[0];
+ for (i = (int) strlen(progname) - 1; i > 0; i--)
+ if (progname[i] == '/') {
+ progname = &progname[i + 1];
+ }
+
+ if (getenv("NMONDEBUG") != NULL)
+ debug = 1;
+ if (getenv("NMONERROR") != NULL)
+ error_on = 1;
+ if (getenv("NMONBUG1") != NULL)
+ reread = 1;
+
+/* External Data Collector Controls */
+ if ((nmon_start = getenv("NMON_START")) != NULL) {
+ nmon_start = check_call_string(nmon_start, "NMON_START");
+ }
+ if ((nmon_end = getenv("NMON_END")) != NULL) {
+ nmon_end = check_call_string(nmon_end, "NMON_END");
+ }
+ if ((nmon_tmp = getenv("NMON_ONE_IN")) != NULL) {
+ nmon_one_in = atoi(nmon_tmp);
+ if (errno != 0) {
+ fprintf(stderr,
+ "ERROR nmon: invalid NMON_ONE_IN shell variable\n");
+ nmon_one_in = 1;
+ }
+ }
+ if ((nmon_snap = getenv("NMON_SNAP")) != NULL) {
+ nmon_snap = check_call_string(nmon_snap, "NMON_SNAP");
+ }
+ if ((nmon_tmp = getenv("NMON_TIMESTAMP")) != NULL) {
+ time_stamp_type = atoi(nmon_tmp);
+ if (time_stamp_type != 0 && time_stamp_type != 1)
+ time_stamp_type = 1;
+ }
+#ifdef DEBUG2
+ printf("NMON_START=%s.\n", nmon_start);
+ printf("NMON_END=%s.\n", nmon_end);
+ printf("NMON_SNAP=%s.\n", nmon_snap);
+ printf("ONE_IN=%d.\n", nmon_one_in);
+ printf("TIMESTAMP=%d.\n", time_stamp_type);
+#endif
+
+#ifdef REREAD
+ reread = 1;
+#endif
+ for (i = 0; i < CMDMAX; i++) {
+ snprintf(cmdstr, 256, "NMONCMD%d", i);
+ cmdlist[i] = getenv(cmdstr);
+ if (cmdlist[i] != 0)
+ cmdfound = i + 1;
+ }
+ /* Setup long and short Hostname */
+ gethostname(hostname, sizeof(hostname));
+ strncpy(fullhostname, hostname, 256);
+ fullhostname[256 - 1] = 0;
+ for (i = 0; i < sizeof(hostname); i++)
+ if (hostname[i] == '.')
+ hostname[i] = 0;
+ if (run_name_set == 0) {
+ strncpy(run_name, hostname, 256);
+ run_name[256 - 1] = 0;
+ }
+ if (getuid() == 0)
+ isroot = 1;
+
+ /* Check the version of OS */
+ uname(&uts);
+ /* Get the clock ticks persecond for CPU counters in /proc/stat cpu stats */
+ ticks = sysconf(_SC_CLK_TCK);
+ if (ticks == -1 || ticks == 0)
+ ticks = 100;
+ /* Check if we have the large 64 KB memory page sizes compiled into the kernel */
+ if (sysconf(_SC_PAGESIZE) > 1024 * 4)
+ pagesize = sysconf(_SC_PAGESIZE);
+ proc_init();
+
+ while (-1 !=
+ (i =
+ getopt(argc, argv,
+ "?abc:C:Dd:EfF:g:hI:Jl:m:MNpr:Rs:tTUVxXz"))) {
+ switch (i) {
+ case '?':
+ hint();
+ exit(0);
+ case 'a': /* Acelerator */
+ case 'E': /* Emily */
+ show_gpu = 1;
+ break;
+ case 'b':
+ colour = 0;
+ break;
+ case 'c':
+ maxloops = atoi(optarg);
+ break;
+ case 'C': /* commandlist argument */
+ cmdlist[0] = MALLOC(strlen(optarg) + 1); /* create buffer */
+ strcpy(cmdlist[0], optarg);
+ if (cmdlist[0][0] != 0)
+ cmdfound = 1;
+ for (i = 0, j = 1; cmdlist[0][i] != 0; i++) {
+ if (cmdlist[0][i] == ':') {
+ cmdlist[0][i] = 0;
+ cmdlist[j] = &cmdlist[0][i + 1];
+ j++;
+ cmdfound = j;
+ if (j >= CMDMAX)
+ break;
+ }
+ }
+ break;
+ case 'd':
+ diskmax = atoi(optarg);
+ if (diskmax < DISKMIN) {
+ printf
+ ("nmon: ignoring -d %d option as the minimum is %d\n",
+ diskmax, DISKMIN);
+ diskmax = DISKMIN;
+ }
+ break;
+ case 'D':
+ extended_disk = 1;
+ break;
+ case 'F': /* background mode with user supplied filename */
+ user_filename = MALLOC(strlen(optarg) + 1);
+ strcpy(user_filename, optarg);
+ user_filename_set++;
+ go_background(288, 300);
+ break;
+ case 'f': /* background mode i.e. for spread sheet output */
+ go_background(288, 300);
+ break;
+ case 'g': /* disk groups */
+ show_dgroup = 1;
+ dgroup_loaded = 1;
+ dgroup_filename = optarg;
+ if (strncmp("auto", dgroup_filename, 5) == 0) {
+ auto_dgroup++;
+ printf
+ ("Generating disk group file from lsblk output to file: \"auto\"\n");
+#ifdef SLES113
+#define LSBLK_NO_TYPE /* define this to work around missing --output TYPE feature */
+#endif /* SLES113 */
+
+#ifdef LSBLK_NO_TYPE
+#define LSBLK_STRING "lsblk --nodeps --output NAME --noheadings | awk 'BEGIN {printf \"# This file created by: nmon -g auto\\n# It is an automatically generated disk-group file which excluses disk paritions\\n\" } { printf \"%s %s\\n\", $1, $1 }' >auto"
+#else
+#define LSBLK_STRING "lsblk --nodeps --output NAME,TYPE --raw | grep disk | awk 'BEGIN {printf \"# This file created by: nmon -g auto\\n# It is an automatically generated disk-group file which excluses disk paritions\\n\" } { printf \"%s %s\\n\", $1, $1 }' >auto"
+#endif /* LSBLK_NO_TYPE */
+ ret = system(LSBLK_STRING);
+ if (ret != 0) {
+ printf("Create auto file command was: %s\n", LSBLK_STRING);
+ printf("Creating auto file returned a status of %d\n", ret);
+ }
+ }
+ break;
+ case 'h':
+ help();
+ break;
+ case 'I':
+ ignore_procdisk_threshold = atof(optarg);
+ break;
+ case 'J':
+ show_jfs = 0;
+ break;
+ case 'l':
+ disks_per_line = atoi(optarg);
+ if (disks_per_line < 3 || disks_per_line > 250)
+ disks_per_line = 100;
+ break;
+ case 'm':
+ if (chdir(optarg) == -1) {
+ perror("changing directory failed");
+ printf("Directory attempted was:%s\n", optarg);
+ exit(993);
+ }
+ break;
+ case 'M': /* MHz */
+ show_mhz = 1;
+ break;
+ case 'N':
+ show_nfs = 1;
+ break;
+ case 'p':
+ ralfmode = 1;
+ break;
+ case 'R':
+ show_rrd = 1;
+ go_background(288, 300);
+ show_aaa = 0;
+ show_para = 0;
+ show_headings = 0;
+ break;
+ case 'r':
+ strncpy(run_name, optarg, 256);
+ run_name[256 - 1] = 0;
+ run_name_set++;
+ break;
+ case 's':
+ seconds = atoi(optarg);
+ break;
+ case 'T':
+ show_args = ARGS_ONLY; /* drop through */
+ case 't':
+ show_top = 1; /* put top process output in spreadsheet mode */
+ show_topmode = 3;
+ break;
+ case 'U':
+ show_util = 1;
+ break;
+ case 'V': /* nmon version */
+ printf("nmon version %s\n", VERSION);
+ exit(0);
+ break;
+ case 'x': /* background mode for 1 day capacity planning */
+ go_background(4 * 24, 15 * 60);
+ show_top = 1;
+ show_topmode = 3;
+ break;
+ case 'X': /* background mode for 1 hour capacity planning */
+ go_background(120, 30);
+ show_top = 1;
+ show_topmode = 3;
+ break;
+ case 'z': /* background mode for 1 day output to /var/perf/tmp */
+ varperftmp++;
+ go_background(4 * 24, 15 * 60);
+ break;
+ }
+ }
+ /* Set parameters if not set by above */
+ if (maxloops == -1)
+ maxloops = 9999999;
+ if (seconds == -1)
+ seconds = 2;
+ if (cursed)
+ show_dgroup = 0;
+
+ /* -D need -g filename */
+ if (extended_disk == 1 && show_dgroup == 0) {
+ printf
+ ("nmon: ignoring -D (extended disk stats) as -g filename is missing\n");
+ extended_disk = 0;
+ }
+#ifdef NVIDIA_GPU
+ if (cursed) {
+ gpu_init();
+ }
+#endif /* NVIDIA_GPU */
+
+ /* To get the pointers setup */
+ switcher();
+
+ /* Initialise the time stamps for the first loop */
+ p->time = doubletime();
+ q->time = doubletime();
+
+ find_release();
+
+ /* Determine number of active LOGICAL cpu - depends on SMT mode ! */
+ get_cpu_cnt();
+ max_cpus = old_cpus = cpus;
+#if X86 || ARM
+ get_intel_spec();
+#endif
+ proc_read(P_STAT);
+ proc_cpu();
+ proc_read(P_UPTIME);
+ proc_read(P_LOADAVG);
+ proc_kernel();
+ memcpy(&q->cpu_total, &p->cpu_total, sizeof(struct cpu_stat));
+
+ p->dk = MALLOC(sizeof(struct dsk_stat) * diskmax + 1);
+ q->dk = MALLOC(sizeof(struct dsk_stat) * diskmax + 1);
+ disk_busy_peak = MALLOC(sizeof(double) * diskmax);
+ disk_rate_peak = MALLOC(sizeof(double) * diskmax);
+ for (i = 0; i < diskmax; i++) {
+ disk_busy_peak[i] = 0.0;
+ disk_rate_peak[i] = 0.0;
+ }
+
+ cpu_peak = MALLOC(sizeof(double) * (CPUMAX + 1)); /* MAGIC */
+ for (i = 0; i < max_cpus + 1; i++)
+ cpu_peak[i] = 0.0;
+
+ current_procs = getprocs(0);
+ adjusted_procs = current_procs + 128; /*allows for more processes */
+ p->procs = MALLOC(sizeof(struct procsinfo) * adjusted_procs);
+ q->procs = MALLOC(sizeof(struct procsinfo) * adjusted_procs);
+ p->proc_records = adjusted_procs;
+ q->proc_records = adjusted_procs;
+ p->processes = 0;
+ q->processes = 0;
+
+ /* Initialise the top processes table */
+ topper_size = n;
+ topper = MALLOC(sizeof(struct topper) * topper_size); /* round up */
+
+ /* Get Disk Stats. */
+ proc_disk(0.0);
+ memcpy(q->dk, p->dk, sizeof(struct dsk_stat) * disks);
+
+ /* load dgroup - if required */
+ if (dgroup_loaded == 1) {
+ load_dgroup(p->dk);
+ }
+
+ /* Get Network Stats. */
+ proc_net();
+ memcpy(q->ifnets, p->ifnets, sizeof(struct net_stat) * networks);
+ for (i = 0; i < networks; i++) {
+ net_read_peak[i] = 0.0;
+ net_write_peak[i] = 0.0;
+ }
+
+ /* If we are running in spreadsheet mode initialize all other data sets as well
+ * so we do not get incorrect data for the first reported interval
+ */
+ if (!cursed) {
+ /* Get VM Stats */
+ read_vmstat();
+
+ /* Get Memory info */
+ proc_mem();
+
+#ifdef POWER
+ /* Get LPAR Stats */
+ proc_lparcfg();
+#endif
+ }
+ /* Set the pointer ready for the next round */
+ switcher();
+
+ /* Initialise signal handlers so we can tidy up curses on exit */
+ signal(SIGUSR1, interrupt);
+ signal(SIGUSR2, interrupt);
+ signal(SIGINT, interrupt);
+ signal(SIGWINCH, interrupt);
+ signal(SIGCHLD, interrupt);
+
+ /* Start Curses */
+ if (cursed) {
+ initscr();
+ cbreak();
+ move(0, 0);
+ refresh();
+ COLOUR colour = has_colors();
+ COLOUR start_color();
+ COLOUR init_pairs();
+ clear();
+#ifdef POWER
+ padlpar = newpad(11, MAXCOLS);
+#endif
+ padwelcome = newpad(24, MAXCOLS);
+ padmap = newpad(24, MAXCOLS);
+ padhelp = newpad(24, MAXCOLS);
+ padmem = newpad(20, MAXCOLS);
+ padlarge = newpad(20, MAXCOLS);
+ padpage = newpad(20, MAXCOLS);
+ padres = newpad(20, MAXCOLS);
+ padsmp = newpad(MAXROWS, MAXCOLS);
+ padutil = newpad(MAXROWS, MAXCOLS);
+ padlong = newpad(MAXROWS, MAXCOLS);
+ padwide = newpad(MAXROWS, MAXCOLS);
+ padmhz = newpad(24, MAXCOLS);
+ padgpu = newpad(10, MAXCOLS);
+ padnet = newpad(MAXROWS, MAXCOLS);
+ padneterr = newpad(MAXROWS, MAXCOLS);
+ paddisk = newpad(MAXROWS, MAXCOLS);
+ paddg = newpad(MAXROWS, MAXCOLS);
+ padjfs = newpad(MAXROWS, MAXCOLS);
+ padker = newpad(12, MAXCOLS);
+ padverb = newpad(8, MAXCOLS);
+ padnfs = newpad(25, MAXCOLS);
+ padtop = newpad(MAXROWS, MAXCOLS * 2);
+
+
+ } else {
+ /* Output the header lines for the spread sheet */
+ timer = time(0);
+ tim = localtime(&timer);
+ tim->tm_year += 1900 - 2000; /* read localtime() manual page!! */
+ tim->tm_mon += 1; /* because it is 0 to 11 */
+ if (varperftmp) {
+ if(strlen(hostname) > 1024 )
+ hostname[255] = 0;
+ open_filename = MALLOC(strlen(hostname) + 64); /* hostname plus directory size plus the number */
+ snprintf(open_filename, strlen(hostname) + 63, "/var/perf/tmp/%s_%02d.nmon", hostname,
+ tim->tm_mday);
+ }
+ else if (user_filename_set && user_filename != 0) {
+ open_filename = MALLOC(strlen(user_filename) + 1);
+ strcpy(open_filename, user_filename);
+ }
+ else {
+ open_filename = MALLOC(strlen(hostname) + 64);
+ snprintf(open_filename, strlen(hostname) + 63, "%s_%02d%02d%02d_%02d%02d.nmon",
+ hostname,
+ tim->tm_year,
+ tim->tm_mon, tim->tm_mday, tim->tm_hour, tim->tm_min);
+ }
+ if (!strncmp(open_filename, "stdout", 6)) {
+ using_stdout = 1;
+ if ((fp = fdopen(1, "w")) == 0) {
+ perror("nmon: failed to open standard output");
+ exit(41);
+ }
+ } else {
+ if ((fp = fopen(open_filename, "w")) == 0) {
+ perror("nmon: failed to open output file");
+ printf("nmon: output filename=%s\n", open_filename);
+ exit(42);
+ }
+ }
+ free(open_filename);
+ /* disconnect from terminal */
+ fflush(NULL);
+ if (!debug && (childpid = fork()) != 0) {
+ if (ralfmode)
+ printf("%d\n", childpid);
+ exit(0); /* parent returns OK */
+ }
+ if (!debug) {
+ close(0);
+ if(using_stdout == 0)
+ close(1);
+ close(2);
+ setpgrp(); /* become process group leader */
+ signal(SIGHUP, SIG_IGN); /* ignore hangups */
+ }
+ /* Do the nmon_start activity early on */
+ if (nmon_start) {
+ timer = time(0);
+ child_start(CHLD_START, nmon_start, time_stamp_type, 1, timer);
+ }
+
+ if (show_aaa) {
+ fprintf(fp, "AAA,progname,%s\n", progname);
+ fprintf(fp, "AAA,command,");
+ for (i = 0; i < argc; i++)
+ fprintf(fp, "%s ", argv[i]);
+ fprintf(fp, "\n");
+ fprintf(fp, "AAA,version,%s\n", VERSION);
+ fprintf(fp, "AAA,disks_per_line,%d\n", disks_per_line);
+ fprintf(fp, "AAA,max_disks,%d,set by -d option\n", diskmax);
+ fprintf(fp, "AAA,disks,%d,\n", disks);
+
+ fprintf(fp, "AAA,host,%s\n", hostname);
+ fprintf(fp, "AAA,user,%s\n", getenv("USER"));
+ fprintf(fp, "AAA,OS,Linux,%s,%s,%s\n", uts.release,
+ uts.version, uts.machine);
+ fprintf(fp, "AAA,runname,%s\n", run_name);
+ fprintf(fp, "AAA,time,%02d:%02d.%02d\n", tim->tm_hour,
+ tim->tm_min, tim->tm_sec);
+ fprintf(fp, "AAA,date,%02d-%3s-%02d\n", tim->tm_mday,
+ month[tim->tm_mon - 1], tim->tm_year + 2000);
+ fprintf(fp, "AAA,interval,%d\n", seconds);
+ fprintf(fp, "AAA,snapshots,%d\n", maxloops);
+#ifdef POWER
+ fprintf(fp, "AAA,cpus,%d,%d\n", cpus / lparcfg.smt_mode, cpus); /* physical CPU, logical CPU */
+ fprintf(fp, "AAA,CPU ID length,3\n"); /* Give analyzer a chance to easily find length of CPU number - 3 digits here! */
+#else
+ fprintf(fp, "AAA,cpus,%d\n", cpus);
+#endif
+#ifdef X86
+ fprintf(fp, "AAA,x86,VendorId,%s\n", vendor_ptr);
+ fprintf(fp, "AAA,x86,ModelName,%s\n", model_ptr);
+ fprintf(fp, "AAA,x86,MHz,%s\n", mhz_ptr);
+ fprintf(fp, "AAA,x86,bogomips,%s\n", bogo_ptr);
+ fprintf(fp, "AAA,x86,ProcessorChips,%d\n", processorchips);
+ fprintf(fp, "AAA,x86,Cores,%d\n", cores);
+ fprintf(fp, "AAA,x86,hyperthreads,%d\n", hyperthreads);
+ fprintf(fp, "AAA,x86,VirtualCPUs,%d\n", cpus);
+#endif
+#ifdef ARM
+ fprintf(fp, "AAA,ARM,VendorId,%s\n", vendor_ptr);
+ fprintf(fp, "AAA,ARM,ModelName,%s\n", model_ptr);
+ fprintf(fp, "AAA,ARM,MHz,%s\n", mhz_ptr);
+ fprintf(fp, "AAA,ARM,bogomips,%s\n", bogo_ptr);
+ fprintf(fp, "AAA,ARM,ProcessorChips,%d\n", processorchips);
+ fprintf(fp, "AAA,ARM,Cores,%d\n", cores);
+ fprintf(fp, "AAA,ARM,hyperthreads,%d\n", hyperthreads);
+ fprintf(fp, "AAA,ARM,VirtualCPUs,%d\n", cpus);
+#endif
+ fprintf(fp, "AAA,proc_stat_variables,%d\n", stat8);
+ fprintf(fp, "AAA,boottime,%s\n", boottime_str);
+
+ fprintf(fp,
+ "AAA,note0, Warning - use the UNIX sort command to order this file before loading into a spreadsheet\n");
+ fprintf(fp,
+ "AAA,note1, The First Column is simply to get the output sorted in the right order\n");
+ fprintf(fp,
+ "AAA,note2, The T0001-T9999 column is a snapshot number. To work out the actual time; see the ZZZ section at the end\n");
+ }
+ fflush(NULL);
+
+ for (i = 1; i <= cpus; i++)
+ fprintf(fp,
+ "CPU%03d,CPU %d %s,User%%,Sys%%,Wait%%,Idle%%,Steal%%\n",
+ i, i, run_name);
+ fprintf(fp,
+ "CPU_ALL,CPU Total %s,User%%,Sys%%,Wait%%,Idle%%,Steal%%,Busy,CPUs\n",
+ run_name);
+ if (show_mhz) {
+ fprintf(fp, "MHZ,Clock Speed (MHz) %s", run_name);
+ for (i = 1; i <= cpus; i++)
+ fprintf(fp, ",CPU%03d", i);
+ fprintf(fp, "\n");
+ }
+ fprintf(fp,
+ "MEM,Memory MB %s,memtotal,hightotal,lowtotal,swaptotal,memfree,highfree,lowfree,swapfree,memshared,cached,active,bigfree,buffers,swapcached,inactive\n",
+ run_name);
+
+#ifdef POWER
+ proc_lparcfg();
+ if (lparcfg.cmo_enabled)
+ fprintf(fp,
+ "MEMAMS,AMS %s,Poolid,Weight,Hypervisor-Page-in/s,HypervisorTime(seconds),not_available_1,not_available_2,not_available_3,Physical-Memory(MB),Page-Size(KB),Pool-Size(MB),Loan-Request(KB)\n",
+ run_name);
+
+#ifdef EXPERIMENTAL
+ fprintf(fp,
+ "MEMEXPERIMENTAL,New lparcfg numbers %s,DesEntCap,DesProcs,DesVarCapWt,DedDonMode,group,pool,entitled_memory,entitled_memory_group_number,unallocated_entitled_memory_weight,unallocated_io_mapping_entitlement\n",
+ run_name);
+#endif /* EXPERIMENTAL */
+#endif /* POWER */
+
+ fprintf(fp,
+ "PROC,Processes %s,Runnable,Blocked,pswitch,syscall,read,write,fork,exec,sem,msg\n",
+ run_name);
+/*
+ fprintf(fp,"PAGE,Paging %s,faults,pgin,pgout,pgsin,pgsout,reclaims,scans,cycles\n", run_name);
+ fprintf(fp,"FILE,File I/O %s,iget,namei,dirblk,readch,writech,ttyrawch,ttycanch,ttyoutch\n", run_name);
+*/
+
+
+ fprintf(fp, "NET,Network I/O %s", run_name);
+ for (i = 0; i < networks; i++)
+ fprintf(fp, ",%-2s-read-KB/s", (char *) p->ifnets[i].if_name);
+ for (i = 0; i < networks; i++)
+ fprintf(fp, ",%-2s-write-KB/s", (char *) p->ifnets[i].if_name);
+ fprintf(fp, "\n");
+ fprintf(fp, "NETPACKET,Network Packets %s", run_name);
+ for (i = 0; i < networks; i++)
+ fprintf(fp, ",%-2s-read/s", (char *) p->ifnets[i].if_name);
+ for (i = 0; i < networks; i++)
+ fprintf(fp, ",%-2s-write/s", (char *) p->ifnets[i].if_name);
+ /* iremoved as it is not below in the BUSY line fprintf(fp,"\n"); */
+#ifdef DEBUG
+ if (debug)
+ printf("disks=%d x%sx\n", (char *) disks, p->dk[0].dk_name);
+#endif /*DEBUG*/
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp, "\nDISKBUSY%s,Disk %%Busy %s", dskgrp(i),
+ run_name);
+ fprintf(fp, ",%s", (char *) p->dk[i].dk_name);
+ }
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp, "\nDISKREAD%s,Disk Read KB/s %s", dskgrp(i),
+ run_name);
+ fprintf(fp, ",%s", (char *) p->dk[i].dk_name);
+ }
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp, "\nDISKWRITE%s,Disk Write KB/s %s",
+ (char *) dskgrp(i), run_name);
+ fprintf(fp, ",%s", (char *) p->dk[i].dk_name);
+ }
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp, "\nDISKXFER%s,Disk transfers per second %s",
+ (char *) dskgrp(i), run_name);
+ fprintf(fp, ",%s", p->dk[i].dk_name);
+ }
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp, "\nDISKBSIZE%s,Disk Block Size %s", dskgrp(i),
+ run_name);
+ fprintf(fp, ",%s", (char *) p->dk[i].dk_name);
+ }
+ if (extended_disk == 1 && disk_mode == DISK_MODE_DISKSTATS) {
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp, "\nDISKREADS%s,Disk Rd/s %s", dskgrp(i),
+ run_name);
+ fprintf(fp, ",%s", (char *) p->dk[i].dk_name);
+ }
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp, "\nDISKWRITES%s,Disk Wrt/s %s", dskgrp(i),
+ run_name);
+ fprintf(fp, ",%s", (char *) p->dk[i].dk_name);
+ }
+ }
+
+ fprintf(fp, "\n");
+ list_dgroup(p->dk);
+ if(show_jfs) {
+ jfs_load(LOAD);
+ fprintf(fp, "JFSFILE,JFS Filespace %%Used %s", hostname);
+ for (k = 0; k < jfses; k++) {
+ if (jfs[k].mounted && strncmp(jfs[k].name, "/proc", 5)
+ && strncmp(jfs[k].name, "/sys", 4)
+ && strncmp(jfs[k].name, "/run/", 5)
+ && strncmp(jfs[k].name, "/dev/", 5)
+ && strncmp(jfs[k].name, "/var/lib/nfs/rpc", 16)
+ ) /* /proc gives invalid/insane values */
+ fprintf(fp, ",%s", jfs[k].name);
+ }
+ fprintf(fp, "\n");
+ jfs_load(UNLOAD);
+ }
+#ifdef POWER
+ if (proc_lparcfg() && (lparcfg.shared_processor_mode != 0 || lparcfg.DedDonMode > 0)
+ && power_vm_type == VM_POWERVM) {
+ fprintf(fp,
+ "LPAR,Shared CPU LPAR Stats %s,PhysicalCPU,capped,shared_processor_mode,system_potential_processors,system_active_processors,pool_capacity,MinEntCap,partition_entitled_capacity,partition_max_entitled_capacity,MinProcs,Logical CPU,partition_active_processors,partition_potential_processors,capacity_weight,unallocated_capacity_weight,BoundThrds,MinMem,unallocated_capacity,pool_idle_time,smt_mode\n",
+ hostname);
+
+ }
+#endif /*POWER*/
+ if (show_top) {
+ fprintf(fp, "TOP,%%CPU Utilisation\n");
+#ifdef PRE_KERNEL_2_6_18
+ fprintf(fp,
+ "TOP,+PID,Time,%%CPU,%%Usr,%%Sys,Size,ResSet,ResText,ResData,ShdLib,MinorFault,MajorFault,Command\n");
+#else
+ fprintf(fp,
+ "TOP,+PID,Time,%%CPU,%%Usr,%%Sys,Size,ResSet,ResText,ResData,ShdLib,MinorFault,MajorFault,Command,Threads,IOwaitTime\n");
+#endif
+ }
+ linux_bbbp("/etc/release", "/bin/cat /etc/*ease 2>/dev/null",
+ WARNING);
+ linux_bbbp("lsb_release", "/usr/bin/lsb_release -a 2>/dev/null",
+ WARNING);
+ linux_bbbp("fdisk-l", "/sbin/fdisk -l 2>/dev/null", WARNING);
+ linux_bbbp("lsblk", "/usr/bin/lsblk 2>/dev/null", WARNING);
+ linux_bbbp("lscpu", "/usr/bin/lscpu 2>/dev/null", WARNING);
+ linux_bbbp("lshw", "/usr/bin/lshw 2>/dev/null", WARNING);
+ linux_bbbp("/proc/cpuinfo", "/bin/cat /proc/cpuinfo 2>/dev/null",
+ WARNING);
+ linux_bbbp("/proc/meminfo", "/bin/cat /proc/meminfo 2>/dev/null",
+ WARNING);
+ linux_bbbp("/proc/stat", "/bin/cat /proc/stat 2>/dev/null",
+ WARNING);
+ linux_bbbp("/proc/version", "/bin/cat /proc/version 2>/dev/null",
+ WARNING);
+ linux_bbbp("/proc/net/dev", "/bin/cat /proc/net/dev 2>/dev/null",
+ WARNING);
+#ifdef POWER
+ /* PowerKVM useful information */
+ linux_bbbp("/proc/device-tree/host-model",
+ "/bin/cat /proc/device-tree/host-model 2>/dev/null", WARNING);
+ linux_bbbp("/proc/device-tree/host-serial",
+ "/bin/cat /proc/device-tree/host-serial 2>/dev/null", WARNING);
+ linux_bbbp("/proc/device-tree/ibm,partition-name",
+ "/bin/cat /proc/device-tree/ibm,partition-name 2>/dev/null", WARNING);
+
+ linux_bbbp("ppc64_utils - lscfg", "/usr/sbin/lscfg 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_utils - ls-vdev",
+ "/usr/sbin/ls-vdev 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_utils - ls-veth",
+ "/usr/sbin/ls-veth 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_utils - ls-vscsi",
+ "/usr/sbin/ls-vscsi 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_utils - lsmcode",
+ "/usr/sbin/lsmcode 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_cpu - smt",
+ "/usr/sbin/ppc64_cpu --smt 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_cpu - cores",
+ "/usr/sbin/ppc64_cpu --cores-present 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_cpu - DSCR",
+ "/usr/sbin/ppc64_cpu --dscr 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_cpu - snooze",
+ "/usr/sbin/ppc64_cpu --smt-snooze-delay 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_cpu - run-mode",
+ "/usr/sbin/ppc64_cpu --run-mode 2>/dev/null", WARNING);
+ linux_bbbp("ppc64_cpu - frequency",
+ "/usr/sbin/ppc64_cpu --frequency 2>/dev/null", WARNING);
+
+ linux_bbbp("bootlist -m nmonal -o",
+ "/usr/sbin/bootlist -m normal -o 2>/dev/null", WARNING);
+ linux_bbbp("lsslot", "/usr/sbin/lsslot 2>/dev/null", WARNING);
+ linux_bbbp("lparstat -i", "/usr/sbin/lparstat -i 2>/dev/null", WARNING);
+ linux_bbbp("lsdevinfo", "/usr/sbin/lsdevinfo 2>/dev/null", WARNING);
+ linux_bbbp("ls-vdev", "/usr/sbin/ls-vdev 2>/dev/null", WARNING);
+ linux_bbbp("ls-veth", "/usr/sbin/ls-veth 2>/dev/null", WARNING);
+ linux_bbbp("ls-vscsi", "/usr/sbin/ls-vscsi 2>/dev/null", WARNING);
+
+#endif
+ linux_bbbp("/proc/diskinfo", "/bin/cat /proc/diskinfo 2>/dev/null",
+ WARNING);
+ linux_bbbp("/proc/diskstats",
+ "/bin/cat /proc/diskstats 2>/dev/null", WARNING);
+
+ linux_bbbp("/sbin/multipath", "/sbin/multipath -l 2>/dev/null",
+ WARNING);
+ linux_bbbp("/dev/mapper", "ls -l /dev/mapper 2>/dev/null",
+ WARNING);
+ linux_bbbp("/dev/mpath", "ls -l /dev/mpath 2>/dev/null", WARNING);
+ linux_bbbp("/dev/dm-*", "ls -l /dev/dm-* 2>/dev/null", WARNING);
+ linux_bbbp("/dev/md*", "ls -l /dev/md* 2>/dev/null", WARNING);
+ linux_bbbp("/dev/sd*", "ls -l /dev/sd* 2>/dev/null", WARNING);
+ linux_bbbp("/proc/partitions",
+ "/bin/cat /proc/partitions 2>/dev/null", WARNING);
+ linux_bbbp("/proc/1/stat", "/bin/cat /proc/1/stat 2>/dev/null",
+ WARNING);
+#ifdef PRE_KERNEL_2_6_18
+ linux_bbbp("/proc/1/statm", "/bin/cat /proc/1/statm 2>/dev/null",
+ WARNING);
+#endif
+#ifdef MAINFRAME
+ linux_bbbp("/proc/sysinfo", "/bin/cat /proc/sysinfo 2>/dev/null",
+ WARNING);
+#endif
+ linux_bbbp("/proc/net/rpc/nfs",
+ "/bin/cat /proc/net/rpc/nfs 2>/dev/null", WARNING);
+ linux_bbbp("/proc/net/rpc/nfsd",
+ "/bin/cat /proc/net/rpc/nfsd 2>/dev/null", WARNING);
+ linux_bbbp("/proc/modules", "/bin/cat /proc/modules 2>/dev/null",
+ WARNING);
+ linux_bbbp("ifconfig", "/sbin/ifconfig 2>/dev/null", WARNING);
+ linux_bbbp("/bin/df-m", "/bin/df -m 2>/dev/null", WARNING);
+ linux_bbbp("/bin/mount", "/bin/mount 2>/dev/null", WARNING);
+ linux_bbbp("/etc/fstab", "/bin/cat /etc/fstab 2>/dev/null",
+ WARNING);
+ linux_bbbp("netstat -r", "/bin/netstat -r 2>/dev/null", WARNING);
+ linux_bbbp("uptime", "/usr/bin/uptime 2>/dev/null", WARNING);
+ linux_bbbp("getconf PAGESIZE",
+ "/usr/bin/getconf PAGESIZE 2>/dev/null", WARNING);
+
+#ifdef POWER
+ linux_bbbp("/proc/ppc64/lparcfg",
+ "/bin/cat /proc/ppc64/lparcfg 2>/dev/null", WARNING);
+ linux_bbbp("lscfg-v", "/usr/sbin/lscfg -v 2>/dev/null", WARNING);
+#endif
+ sleep(1); /* to get the first stats to cover this one second and avoids divide by zero issues */
+ }
+ /* To get the pointers setup */
+ /* Was already done earlier, DONT'T switch back here to the old pointer! - switcher(); */
+ /*checkinput(); */
+ clear();
+ fflush(NULL);
+#ifdef POWER
+ lparcfg.timebase = -1;
+#endif
+
+ /* Main loop of the code */
+ for (loop = 1;; loop++) {
+ /* Save the time and work out how long we were actually asleep
+ * Do this as early as possible and close to reading the CPU statistics in /proc/stat
+ */
+ p->time = doubletime();
+ elapsed = p->time - q->time;
+ timer = time(0);
+ tim = localtime(&timer);
+
+ /* Get current count of CPU
+ * As side effect /proc/stat is read
+ */
+ old_cpus = cpus;
+ get_cpu_cnt();
+#ifdef POWER
+ /* Always get lpar info as well so we can report physical CPU usage
+ * to make data more meaningful. Return value is ignored here, but
+ * remembered in proc_lparcfg() !
+ */
+ proc_lparcfg();
+#endif
+
+ if (loop <= 3) /* This stops the nmon causing the cpu peak at startup */
+ for (i = 0; i < max_cpus + 1; i++)
+ cpu_peak[i] = 0.0;
+
+ /* Reset the cursor position to top left */
+ y = x = 0;
+
+ if (cursed) { /* Top line */
+ box(stdscr, 0, 0);
+ mvprintw(x, 1, "nmon");
+ mvprintw(x, 6, "%s", VERSION);
+ if (flash_on)
+ mvprintw(x, 15, "[H for help]");
+ mvprintw(x, 30, "Hostname=%s", hostname);
+ mvprintw(x, 52, "Refresh=%2.0fsecs ", elapsed);
+ mvprintw(x, 70, "%02d:%02d.%02d",
+ tim->tm_hour, tim->tm_min, tim->tm_sec);
+ wnoutrefresh(stdscr);
+ x = x + 1;
+
+ if (welcome && getenv("NMON") == 0) {
+
+ COLOUR wattrset(padwelcome, COLOR_PAIR(2));
+ mvwprintw(padwelcome, x + 0, 3, "------------------------------");
+ mvwprintw(padwelcome, x + 1, 3, " _ __ _ __ ___ ___ _ __ ");
+ mvwprintw(padwelcome, x + 2, 3, "| '_ \\| '_ ` _ \\ / _ \\| '_ \\ ");
+ mvwprintw(padwelcome, x + 3, 3, "| | | | | | | | | (_) | | | | ");
+ mvwprintw(padwelcome, x + 4, 3, "|_| |_|_| |_| |_|\\___/|_| |_| ");
+ mvwprintw(padwelcome, x + 5, 3, " ");
+ mvwprintw(padwelcome, x + 6, 3, "------------------------------");
+
+ COLOUR wattrset(padwelcome, COLOR_PAIR(0));
+ mvwprintw(padwelcome, x + 1, 40, "For help type H or ...");
+ mvwprintw(padwelcome, x + 2, 40, " nmon -? - hint");
+ mvwprintw(padwelcome, x + 3, 40,
+ " nmon -h - full details");
+ mvwprintw(padwelcome, x + 5, 40,
+ "To stop nmon type q to Quit");
+ COLOUR wattrset(padwelcome, COLOR_PAIR(1));
+#ifdef POWER
+ get_cpu_cnt();
+ proc_read(P_CPUINFO);
+ /* find the highest MHz */
+ for(i=0; itm_hour, tim->tm_min, tim->tm_sec,
+ tim->tm_mday, month[tim->tm_mon],
+ tim->tm_year + 1900);
+ fflush(NULL);
+ }
+ if (show_verbose && cursed) {
+ BANNER(padverb, "Verbose Mode");
+ mvwprintw(padverb, 1, 0,
+ " Code Resource Stats Now\tWarn\tDanger ");
+ /* DISPLAY(padverb,7); */
+ /* move(x,0); */
+ x = x + 6;
+ }
+ if (show_help && cursed) {
+
+ COLOUR wattrset(padhelp, COLOR_PAIR(2));
+ BANNER(padhelp,
+ "HELP: Hit h to remove this Info Hit q to Quit");
+ mvwprintw(padhelp, 1, 1,
+ "Letters which toggle on/off statistics:");
+ mvwprintw(padhelp, 2, 1,
+ "h = This help | r = Resources OS & Proc");
+ mvwprintw(padhelp, 3, 1,
+ "c = CPU Util C = wide view | l = longer term CPU averages");
+ mvwprintw(padhelp, 4, 1,
+ "m = Memory & Swap L=Huge | V = Virtual Memory");
+ mvwprintw(padhelp, 5, 1,
+ "n = Network | N = NFS");
+ mvwprintw(padhelp, 6, 1,
+ "d = Disk I/O Graphs D=Stats | o = Disks %%Busy Map");
+ mvwprintw(padhelp, 7, 1,
+ "k = Kernel stats & loadavg | j = Filesystem Usage J=reduced");
+ mvwprintw(padhelp, 8, 1, "M = MHz by thread & CPU");
+#ifdef NVIDIA_GPU
+ mvwprintw(padhelp, 8, 39, "| a = Accelerator Nvidia GPU ");
+#else /*NVIDIA_GPU */
+#ifdef POWER
+ mvwprintw(padhelp, 8, 39, "| p = if(PowerVM) LPAR details");
+#endif /*POWER*/
+#endif /*NVIDIA_GPU */
+ mvwprintw(padhelp, 9, 1,
+ "t = TopProcess 1=Priority/Nice/State | u = TopProc with command line");
+ mvwprintw(padhelp, 10, 1,
+ " ReOrder by: 3=CPU 4=RAM 5=I/O | Hit u twice to update");
+ mvwprintw(padhelp, 11, 1,
+ "g = User Defined Disk Groups | G = with -g switches Disk graphs");
+ mvwprintw(padhelp, 12, 1,
+ " [start nmon with -g ] | to disk groups only");
+ mvwprintw(padhelp, 13, 39, "| b = black & white mode");
+ mvwprintw(padhelp, 14, 1,
+ "Other Controls: |");
+ mvwprintw(padhelp, 15, 1,
+ "+ = double the screen refresh time | 0 = reset peak marks (\">\") to zero");
+ mvwprintw(padhelp, 16, 1,
+ "- = half the screen refresh time | space refresh screen now");
+ mvwprintw(padhelp, 17, 1,
+ ". = Display only busy disks & CPU | q = Quit");
+/* mvwprintw(padhelp,18, 1, "v = Verbose Simple Checks - OK/Warnings/Danger"); */
+
+ mvwprintw(padhelp, 19, 1,
+ "(C) Copyright 2009 Nigel Griffiths | See http://nmon.sourceforge.net");
+ mvwprintw(padhelp, 20, 1, "Colour:");
+ for (i = 0; i < 13; i++) {
+ COLOUR wattrset(padhelp, COLOR_PAIR(i));
+ mvwprintw(padhelp, 20, 8 + i * 5, "#%d#", i);
+ }
+ COLOUR wattrset(padhelp, COLOR_PAIR(0));
+ DISPLAY(padhelp, 21);
+
+ }
+/* for debugging use only
+ if(error_on && errorstr[0] != 0) {
+ mvprintw(x, 0, "Error: %s ",errorstr);
+ x = x + 1;
+ }
+*/
+ if (show_res && cursed) {
+ proc_read(P_CPUINFO);
+ proc_read(P_VERSION);
+
+ BANNER(padres, "Resources Linux & Processor");
+ COLOUR wattrset(padres, COLOR_PAIR(2));
+ mvwprintw(padres, 1, 4, "Linux: %s", proc[P_VERSION].line[0]);
+ mvwprintw(padres, 2, 4, "Build: %s", proc[P_VERSION].line[1]);
+ mvwprintw(padres, 3, 4, "Release : %s", uts.release);
+ mvwprintw(padres, 4, 4, "Version : %s", uts.version);
+ COLOUR wattrset(padres, COLOR_PAIR(3));
+#ifdef POWER
+ mvwprintw(padres, 5, 4, "cpuinfo: %s",
+ proc[P_CPUINFO].line[1]);
+ mvwprintw(padres, 6, 4, "cpuinfo: %s",
+ proc[P_CPUINFO].line[2]);
+ mvwprintw(padres, 7, 4, "cpuinfo: %s",
+ proc[P_CPUINFO].line[3]);
+ mvwprintw(padres, 8, 4, "cpuinfo: %s %s",
+ proc[P_CPUINFO].line[proc[P_CPUINFO].lines - 2],
+ proc[P_CPUINFO].line[proc[P_CPUINFO].lines - 1]);
+ /* needs lparcfg to be already processed */
+ proc_lparcfg();
+ switch (power_vm_type) {
+ case VM_POWERKVM_GUEST:
+ mvwprintw(padres, 9, 20,
+ "PowerKVM Guest Physical CPU:%d & Virtual CPU (SMT):%d %s",
+ lparcfg.partition_active_processors, cpus,
+ lscpu.byte_order);
+ break;
+ case VM_POWERKVM_HOST:
+ mvwprintw(padres, 9, 20,
+ "PowerKVM Host Physical CPU:%d %s", cpus,
+ lscpu.byte_order);
+ break;
+ case VM_POWERVM:
+ mvwprintw(padres, 9, 20,
+ "PowerVM Physical CPU:%d & Logical CPU:%d %s",
+ lparcfg.partition_active_processors, cpus,
+ lscpu.byte_order);
+ break;
+ case VM_NATIVE:
+ mvwprintw(padres, 9, 20, "Native Mode Physical CPU:%d %s",
+ cpus, lscpu.byte_order);
+ break;
+ }
+#endif /* POWER */
+#ifdef MAINFRAME
+ mvwprintw(padres, 5, 4, "cpuinfo: %s",
+ proc[P_CPUINFO].line[1]);
+ mvwprintw(padres, 6, 4, "cpuinfo: %s",
+ proc[P_CPUINFO].line[2]);
+ mvwprintw(padres, 7, 4, "cpuinfo: %s",
+ proc[P_CPUINFO].line[3]);
+ mvwprintw(padres, 8, 4, "cpuinfo: %s",
+ proc[P_CPUINFO].line[4]);
+#endif/* MAINFRAME */
+#ifdef X86
+ mvwprintw(padres, 5, 4, "cpuinfo: Vendor=%s Model=%s", vendor_ptr, model_ptr);
+ mvwprintw(padres, 6, 4, "cpuinfo: Hz=%s bogomips=%s", mhz_ptr, bogo_ptr);
+
+ if (processorchips || cores || hyperthreads || cpus) {
+ mvwprintw(padres, 7, 4,
+ "cpuinfo: ProcessorChips=%d PhysicalCores=%d",
+ processorchips, cores);
+ mvwprintw(padres, 8, 4,
+ "cpuinfo: Hyperthreads =%d VirtualCPUs =%d",
+ hyperthreads, cpus);
+ }
+#endif /* X86 */
+#ifdef ARM
+ mvwprintw(padres, 5, 4, "cpuinfo: Vendor=%s Model=%s BogoMIPS=%s", vendor_ptr, model_ptr, bogo_ptr);
+ mvwprintw(padres, 6, 4, "lscpu: CPU=%d %s", lscpu.cpus, lscpu.byte_order);
+ mvwprintw(padres, 7, 4, "lscpu: Sockets=%d Cores=%d Thrds=%d", lscpu.sockets, lscpu.cores, lscpu.threads);
+ mvwprintw(padres, 8, 4, "lscpu: max=%d min=%d", lscpu.mhz_max, lscpu.mhz_min);
+
+#endif /* ARM */
+ mvwprintw(padres, 9, 4, "# of CPUs: %d", cpus);
+ COLOUR wattrset(padres, COLOR_PAIR(5));
+ mvwprintw(padres, 10, 4, "Machine : %s", uts.machine);
+ mvwprintw(padres, 11, 4, "Nodename : %s", uts.nodename);
+ COLOUR wattrset(padres, COLOR_PAIR(6));
+ mvwprintw(padres, 12, 4, "/etc/*ease[1]: %s", easy[0]);
+ mvwprintw(padres, 13, 4, "/etc/*ease[2]: %s", easy[1]);
+ mvwprintw(padres, 14, 4, "/etc/*ease[3]: %s", easy[2]);
+ mvwprintw(padres, 15, 4, "/etc/*ease[4]: %s", easy[3]);
+ COLOUR wattrset(padres, COLOR_PAIR(2));
+ mvwprintw(padres, 16, 4, "lsb_release: %s", lsb_release[0]);
+ mvwprintw(padres, 17, 4, "lsb_release: %s", lsb_release[1]);
+ mvwprintw(padres, 18, 4, "lsb_release: %s", lsb_release[2]);
+ mvwprintw(padres, 19, 4, "lsb_release: %s", lsb_release[3]);
+ COLOUR wattrset(padres, COLOR_PAIR(0));
+ DISPLAY(padres, 20);
+ }
+ if (show_longterm) {
+ proc_read(P_STAT);
+ proc_cpu();
+ cpu_user = RAWTOTAL(user) + RAWTOTAL(nice);
+ cpu_sys =
+ RAWTOTAL(sys) + RAWTOTAL(irq) + RAWTOTAL(softirq) ;
+ /* + RAWTOTAL(guest) + RAWTOTAL(guest_nice); these are in addition to the 100% */
+ cpu_wait = RAWTOTAL(wait);
+ cpu_idle = RAWTOTAL(idle);
+ cpu_steal = RAWTOTAL(steal);
+ /* DEBUG inject steal cpu_steal = cpu_sys; */
+ cpu_sum = cpu_idle + cpu_user + cpu_sys + cpu_wait + cpu_steal;
+
+ save_snap((double) cpu_user / (double) cpu_sum * 100.0,
+ (double) cpu_sys / (double) cpu_sum * 100.0,
+ (double) cpu_wait / (double) cpu_sum * 100.0,
+ (double) cpu_idle / (double) cpu_sum * 100.0,
+ (double) cpu_steal / (double) cpu_sum * 100.0);
+ plot_snap(padlong);
+ DISPLAY(padlong, MAX_SNAP_ROWS + 2);
+ }
+ if (show_smp || show_verbose || show_wide) {
+ proc_read(P_STAT);
+ proc_cpu();
+ if (cpus > max_cpus && !cursed) {
+ for (i = max_cpus + 1; i <= cpus; i++)
+ fprintf(fp,
+ "CPU%03d,CPU %d %s,User%%,Sys%%,Wait%%,Idle%%\n",
+ i, i, run_name);
+ max_cpus = cpus;
+ }
+ if (old_cpus != cpus) {
+ if (!cursed) {
+ if (bbbr_line == 0) {
+ fprintf(fp, "BBBR,0,Reconfig,action,old,new\n");
+ bbbr_line++;
+ }
+ fprintf(fp, "BBBR,%03d,%s,cpuchg,%d,%d\n", bbbr_line++,
+ LOOP, old_cpus, cpus);
+ } else {
+ /* wmove(padsmp,0,0); */
+ /* doesn't work CURSE wclrtobot(padsmp); */
+ /* Do BRUTE force overwrite of previous data */
+ if (cpus < old_cpus) {
+ for (i = cpus; i < old_cpus; i++)
+ mvwprintw(padsmp, i + 4, 0,
+ " ");
+ }
+ }
+ }
+ if (show_smp) {
+ if (cursed) {
+ BANNER(padsmp, "CPU Utilisation");
+
+ /* mvwprintw(padsmp,1, 0, cpu_line); */
+ /*
+ *mvwprintw(padsmp,2, 0, "CPU User%% Sys%% Wait%% Idle|0 |25 |50 |75 100|");
+ */
+ mvwprintw(padsmp, 1, 0, cpu_line);
+ mvwprintw(padsmp, 2, 0, "CPU ");
+ COLOUR wattrset(padsmp, COLOR_PAIR(2)); /* Green */
+ mvwprintw(padsmp, 2, 4, "User%%");
+ COLOUR wattrset(padsmp, COLOR_PAIR(1)); /* Red */
+ mvwprintw(padsmp, 2, 9, " Sys%%");
+ COLOUR wattrset(padsmp, COLOR_PAIR(4)); /* Blue */
+ mvwprintw(padsmp, 2, 15, " Wait%%");
+ if (p->cpu_total.steal != q->cpu_total.steal) {
+ COLOUR wattrset(padsmp, COLOR_PAIR(5));
+ mvwprintw(padsmp, 2, 22, "Steal");
+ } else {
+ COLOUR wattrset(padsmp, COLOR_PAIR(0));
+ mvwprintw(padsmp, 2, 22, " Idle");
+ }
+ COLOUR wattrset(padsmp, COLOR_PAIR(0));
+ mvwprintw(padsmp, 2, 27,
+ "|0 |25 |50 |75 100|");
+ } /* if (show_smp) AND if(cursed) */
+#ifdef POWER
+ /* Always get lpar info as well so we can report physical CPU usage
+ * to make data more meaningful
+ * This assumes that LPAR info is available in q and p !
+ */
+ if (proc_lparcfg() > 0) {
+ if (lparcfg.shared_processor_mode == 1) {
+ if (lparcfg.timebase == -1) {
+ lparcfg.timebase = 0;
+ proc_read(P_CPUINFO);
+ for (i = 0; i < proc[P_CPUINFO].lines - 1; i++) {
+ if (!strncmp
+ ("timebase", proc[P_CPUINFO].line[i],
+ 8)) {
+ sscanf(proc[P_CPUINFO].line[i],
+ "timebase : %lld",
+ &lparcfg.timebase);
+ break;
+ }
+ }
+ } else {
+ /* PowerKVM Host or Guest or Native have not Entitlement stats */
+ if (power_vm_type == VM_POWERVM)
+ mvwprintw(padsmp, 1, 30,
+ "EntitledCPU=% 6.3f",
+ (double) lparcfg.
+ partition_entitled_capacity /
+ 100.0);
+ /* Only if the calculation is working */
+ if (lparcfg.purr_diff != 0)
+ mvwprintw(padsmp, 1, 50,
+ "PhysicalCPUused=% 7.3f",
+ (double) lparcfg.purr_diff /
+ (double) lparcfg.timebase /
+ elapsed);
+ }
+ }
+ }
+#endif
+ for (i = 0; i < cpus; i++) {
+ cpu_user = RAW(user) + RAW(nice);
+ cpu_sys =
+ RAW(sys) + RAW(irq) + RAW(softirq);
+ /* + RAW(guest) + RAW(guest_nice); these are in addition to the 100% */
+ cpu_wait = RAW(wait);
+ cpu_idle = RAW(idle);
+ cpu_steal = RAW(steal);
+/* DEBUG inject steal cpu_steal = cpu_sys; */
+ cpu_sum =
+ cpu_idle + cpu_user + cpu_sys + cpu_wait +
+ cpu_steal;
+ /* Check if we had a CPU # change and have to set idle to 100 */
+ if (cpu_sum == 0)
+ cpu_sum = cpu_idle = 100.0;
+ if (smp_first_time && cursed) {
+ if (i == 0)
+ mvwprintw(padsmp, 3 + i, 27,
+ "| Please wait gathering CPU statistics");
+ else
+ mvwprintw(padsmp, 3 + i, 27, "|");
+ mvwprintw(padsmp, 3 + i, 77, "|");
+ } else {
+#ifdef POWER
+ /* lparcfg gathered above */
+ if (lparcfg.smt_mode > 1
+ && i % lparcfg.smt_mode == 0) {
+ mvwprintw(padsmp, 3 + i, 27, "*");
+ mvwprintw(padsmp, 3 + i, 77, "*");
+ }
+#endif
+ plot_smp(padsmp, i + 1, 3 + i,
+ (double) cpu_user / (double) cpu_sum *
+ 100.0,
+ (double) cpu_sys / (double) cpu_sum *
+ 100.0,
+ (double) cpu_wait / (double) cpu_sum *
+ 100.0,
+ (double) cpu_idle / (double) cpu_sum *
+ 100.0,
+ (double) cpu_steal / (double) cpu_sum *
+ 100.0);
+#ifdef POWER
+ /* lparcfg gathered above */
+ if (lparcfg.smt_mode > 1
+ && i % lparcfg.smt_mode == 0) {
+ mvwprintw(padsmp, 3 + i, 27, "*");
+ mvwprintw(padsmp, 3 + i, 77, "*");
+ }
+#endif
+
+ RRD fprintf(fp,
+ "rrdtool update cpu%02d.rrd %s:%.1f:%.1f:%.1f:%.1f\n",
+ i, LOOP,
+ (double) cpu_user / (double) cpu_sum *
+ 100.0,
+ (double) cpu_sys / (double) cpu_sum *
+ 100.0,
+ (double) cpu_wait / (double) cpu_sum *
+ 100.0,
+ (double) cpu_idle / (double) cpu_sum *
+ 100.0);
+ }
+ } /* for (i = 0; i < cpus; i++) */
+ CURSE mvwprintw(padsmp, i + 3, 0, cpu_line);
+#ifdef POWER
+ /* proc_lparcfg called above in previous ifdef
+ */
+ if (lparcfg.shared_processor_mode == 1) {
+ if (lparcfg.timebase == -1) {
+ lparcfg.timebase = 0;
+ proc_read(P_CPUINFO);
+ for (i = 0; i < proc[P_CPUINFO].lines - 1; i++) {
+ if (!strncmp
+ ("timebase", proc[P_CPUINFO].line[i], 8)) {
+ sscanf(proc[P_CPUINFO].line[i],
+ "timebase : %lld",
+ &lparcfg.timebase);
+ break;
+ }
+ }
+ } else {
+ mvwprintw(padsmp, i + 3, 29, "%s",
+ lparcfg.
+ shared_processor_mode ? "Shared" :
+ "Dedicated");
+ mvwprintw(padsmp, i + 3, 39, "|");
+ /* PowerKVM has no Capped concept */
+ if (power_vm_type == VM_POWERVM)
+ mvwprintw(padsmp, i + 3, 41, "%s",
+ lparcfg.
+ capped ? "--Capped" : "Uncapped");
+ mvwprintw(padsmp, i + 3, 51, "|");
+ mvwprintw(padsmp, i + 3, 54, "SMT=%d",
+ lparcfg.smt_mode);
+ mvwprintw(padsmp, i + 3, 64, "|");
+ mvwprintw(padsmp, i + 3, 67, "VP=%.0f",
+ (float) lparcfg.
+ partition_active_processors);
+ }
+ }
+#endif
+ cpu_user = RAWTOTAL(user) + RAWTOTAL(nice);
+ cpu_sys =
+ RAWTOTAL(sys) + RAWTOTAL(irq) + RAWTOTAL(softirq);
+ /* + RAWTOTAL(guest) + RAWTOTAL(guest_nice); these are in addition to the 100% */
+ cpu_wait = RAWTOTAL(wait);
+ cpu_idle = RAWTOTAL(idle);
+ cpu_steal = RAWTOTAL(steal);
+/* DEBUG inject steal cpu_steal = cpu_sys; */
+ cpu_sum =
+ cpu_idle + cpu_user + cpu_sys + cpu_wait + cpu_steal;
+
+ /* Check if we had a CPU # change and have to set idle to 100 */
+ if (cpu_sum == 0)
+ cpu_sum = cpu_idle = 100.0;
+
+ RRD fprintf(fp,
+ "rrdtool update cpu.rrd %s:%.1f:%.1f:%.1f:%.1f%.1f\n",
+ LOOP,
+ (double) cpu_user / (double) cpu_sum * 100.0,
+ (double) cpu_sys / (double) cpu_sum * 100.0,
+ (double) cpu_wait / (double) cpu_sum * 100.0,
+ (double) cpu_idle / (double) cpu_sum * 100.0,
+ (double) cpu_steal / (double) cpu_sum * 100.0);
+ if (cpus > 1 || !cursed) {
+ if (!smp_first_time || !cursed) {
+ plot_smp(padsmp, 0, 4 + i,
+ (double) cpu_user / (double) cpu_sum *
+ 100.0,
+ (double) cpu_sys / (double) cpu_sum *
+ 100.0,
+ (double) cpu_wait / (double) cpu_sum *
+ 100.0,
+ (double) cpu_idle / (double) cpu_sum *
+ 100.0,
+ (double) cpu_steal / (double) cpu_sum *
+ 100.0);
+ }
+
+ CURSE mvwprintw(padsmp, i + 5, 0, cpu_line);
+ i = i + 2;
+ } /* if (cpus > 1 || !cursed) */
+ smp_first_time = 0;
+ DISPLAY(padsmp, i + 4);
+ } /* if (show_smp) */
+ if (show_wide) {
+ if (cursed) {
+ int rows = 0;
+ BANNER(padwide, "CPU Utilisation Wide View");
+ char *wide1 =
+ "100%%-+--------+---------+---------+---------+---------+---------+-----+100%%";
+ char *wide2 =
+ " 90%%-| |-90%%";
+ char *wide3 =
+ " 80%%-| |-80%%";
+ char *wide4 =
+ " 70%%-| |-70%%";
+ char *wide5 =
+ " 60%%-| |-60%%";
+ char *wide6 =
+ " 50%%-| |-50%%";
+ char *wide7 =
+ " 40%%-| |-40%%";
+ char *wide8 =
+ " 30%%-| |-30%%";
+ char *wide9 =
+ " 20%%-| |-20%%";
+ char *wide10 =
+ " 10%%-| |-10%%";
+
+ mvwprintw(padwide, 1, 0, wide1);
+ mvwprintw(padwide, 2, 0, wide2);
+ mvwprintw(padwide, 3, 0, wide3);
+ mvwprintw(padwide, 4, 0, wide4);
+ mvwprintw(padwide, 5, 0, wide5);
+ mvwprintw(padwide, 6, 0, wide6);
+ mvwprintw(padwide, 7, 0, wide7);
+ mvwprintw(padwide, 8, 0, wide8);
+ mvwprintw(padwide, 9, 0, wide9);
+ mvwprintw(padwide, 10, 0, wide10);
+ mvwprintw(padwide, 11, 0,
+ " CPU +1--------+10-------+20-------+30-------+40-------+50-------+60--+--0%%");
+ mvwprintw(padwide, 1, 6, "CPU(s)=%d", cpus);
+ if (wide_first_time) {
+ mvwprintw(padwide, 3, 7,
+ " Please wait gathering CPU statistics");
+ } else {
+ for (i = 0; i < cpus && i < 64; i++) {
+ cpu_user = RAW(user) + RAW(nice);
+ cpu_sys =
+ RAW(sys) + RAW(irq) + RAW(softirq);
+ /* + RAW(guest) + RAW(guest_nice); these are in addition to the 100% */
+ cpu_sum = cpu_user + cpu_sys;
+ COLOUR wattrset(padwide, COLOR_PAIR(4)); /* blue */
+ if (i % 2) {
+ mvwprintw(padwide, 6, 6 + i, ".");
+ }
+ if (cpu_sum > 75) {
+ COLOUR wattrset(padwide, COLOR_PAIR(1)); /*red */
+ } else {
+ if (cpu_sum > 50) {
+ COLOUR wattrset(padwide, COLOR_PAIR(5)); /*magenta */
+ } else {
+ COLOUR wattrset(padwide, COLOR_PAIR(2)); /*green */
+ }
+ }
+ for (j = 1, k = 10; j < 10; j++, k--)
+ if (cpu_sum > j * 10.0)
+ mvwprintw(padwide, k, 6 + i, "#");
+ COLOUR wattrset(padwide, COLOR_PAIR(0)); /* white */
+ if (0.1 < cpu_sum && cpu_sum < 5.0)
+ mvwprintw(padwide, 10, 6 + i, ".");
+ if (5.1 <= cpu_sum && cpu_sum < 10.0)
+ mvwprintw(padwide, 10, 6 + i, "o");
+ }
+ if (cpus < 64)
+ for (j = 2; j <= 10; j++)
+ mvwprintw(padwide, j, 6 + i, "|");
+ rows = 12;
+ }
+ if (cpus > 63) {
+ mvwprintw(padwide, rows + 0, 0, wide1);
+ mvwprintw(padwide, rows + 1, 0, wide2);
+ mvwprintw(padwide, rows + 2, 0, wide3);
+ mvwprintw(padwide, rows + 3, 0, wide4);
+ mvwprintw(padwide, rows + 4, 0, wide5);
+ mvwprintw(padwide, rows + 5, 0, wide6);
+ mvwprintw(padwide, rows + 6, 0, wide7);
+ mvwprintw(padwide, rows + 7, 0, wide8);
+ mvwprintw(padwide, rows + 8, 0, wide9);
+ mvwprintw(padwide, rows + 9, 0, wide10);
+ mvwprintw(padwide, rows + 10, 0,
+ " CPU +65---+70-------+80-------+90-------+100------+110------+120-----+--0%%");
+ if (wide_first_time) {
+ mvwprintw(padwide, rows + 3, 7,
+ " Please wait gathering CPU statistics");
+ } else {
+ for (i = 64; i < cpus && i < 128; i++) {
+ cpu_user = RAW(user) + RAW(nice);
+ cpu_sys =
+ RAW(sys) + RAW(irq) + RAW(softirq);
+ /* + RAW(guest) + RAW(guest_nice); these are in addition to the 100% */
+ cpu_sum = cpu_user + cpu_sys;
+ COLOUR wattrset(padwide, COLOR_PAIR(4)); /* blue */
+ if (i % 2) {
+ mvwprintw(padwide, rows + 5,
+ 6 + i - 64, ".");
+ }
+ if (cpu_sum > 75) {
+ COLOUR wattrset(padwide, COLOR_PAIR(1)); /*red */
+ } else {
+ if (cpu_sum > 50) {
+ COLOUR wattrset(padwide, COLOR_PAIR(5)); /*magenta */
+ } else {
+ COLOUR wattrset(padwide, COLOR_PAIR(2)); /*green */
+ }
+ }
+ for (j = 1, k = rows + 9; j < 10; j++, k--)
+ if (cpu_sum > j * 10.0)
+ mvwprintw(padwide, k, 6 + i - 64,
+ "#");
+ COLOUR wattrset(padwide, COLOR_PAIR(0)); /* white */
+ if (0.1 < cpu_sum && cpu_sum < 5.0)
+ mvwprintw(padwide, rows + 9,
+ 6 + i - 64, ".");
+ if (5.1 <= cpu_sum && cpu_sum < 10.0)
+ mvwprintw(padwide, rows + 9,
+ 6 + i - 64, "o");
+ }
+
+ if (cpus < 128)
+ COLOUR wattrset(padwide, COLOR_PAIR(4)); /* blue */
+ for (j = rows; j <= rows + 9; j++)
+ mvwprintw(padwide, j, 6 + i - 64, "<");
+ COLOUR wattrset(padwide, COLOR_PAIR(0)); /* white */
+ }
+ rows = 23;
+ }
+ if (cpus > 127) {
+ mvwprintw(padwide, rows + 0, 0, wide1);
+ mvwprintw(padwide, rows + 1, 0, wide2);
+ mvwprintw(padwide, rows + 2, 0, wide3);
+ mvwprintw(padwide, rows + 3, 0, wide4);
+ mvwprintw(padwide, rows + 4, 0, wide5);
+ mvwprintw(padwide, rows + 5, 0, wide6);
+ mvwprintw(padwide, rows + 6, 0, wide7);
+ mvwprintw(padwide, rows + 7, 0, wide8);
+ mvwprintw(padwide, rows + 8, 0, wide9);
+ mvwprintw(padwide, rows + 9, 0, wide10);
+ mvwprintw(padwide, rows + 10, 0,
+ " CPU +129--------+140------+150------+160------+170------+180------+190--0%%");
+ if (wide_first_time) {
+ mvwprintw(padwide, rows + 3, 7,
+ " Please wait gathering CPU statistics");
+ } else {
+ for (i = 128; i < cpus && i < 196; i++) {
+ cpu_user = RAW(user) + RAW(nice);
+ cpu_sys =
+ RAW(sys) + RAW(irq) + RAW(softirq);
+ /* + RAW(guest) + RAW(guest_nice); these are in addition of the 100% */
+ cpu_sum = cpu_user + cpu_sys;
+ COLOUR wattrset(padwide, COLOR_PAIR(4)); /* blue */
+ if (i % 2) {
+ mvwprintw(padwide, rows + 5,
+ 6 + i - 128, ".");
+ }
+ if (cpu_sum > 75) {
+ COLOUR wattrset(padwide, COLOR_PAIR(1)); /*red */
+ } else {
+ if (cpu_sum > 50) {
+ COLOUR wattrset(padwide, COLOR_PAIR(5)); /*magenta */
+ } else {
+ COLOUR wattrset(padwide, COLOR_PAIR(2)); /*green */
+ }
+ }
+ for (j = 1, k = rows + 9; j < 10; j++, k--)
+ if (cpu_sum > j * 10.0)
+ mvwprintw(padwide, k, 6 + i - 128,
+ "#");
+ COLOUR wattrset(padwide, COLOR_PAIR(0)); /* white */
+ if (0.1 < cpu_sum && cpu_sum < 5.0)
+ mvwprintw(padwide, rows + 9,
+ 6 + i - 128, ".");
+ if (5.1 <= cpu_sum && cpu_sum < 10.0)
+ mvwprintw(padwide, rows + 9,
+ 6 + i - 128, "o");
+ }
+
+ if (cpus < 196)
+ COLOUR wattrset(padwide, COLOR_PAIR(4)); /* blue */
+ for (j = rows; j <= rows + 9; j++)
+ mvwprintw(padwide, j, 6 + i - 128, "<");
+ COLOUR wattrset(padwide, COLOR_PAIR(0)); /* white */
+ }
+ rows = 34;
+ }
+ wide_first_time = 0;
+ DISPLAY(padwide, rows);
+ }
+ proc_read(P_STAT);
+ proc_cpu();
+
+ if (show_verbose && cursed) {
+ cpu_user = RAWTOTAL(user) + RAWTOTAL(nice);
+ cpu_sys =
+ RAWTOTAL(sys) + RAWTOTAL(irq) + RAWTOTAL(softirq);
+ /* + RAWTOTAL(guest) + RAWTOTAL(guest_nice); these are in addition to the 100% */
+ cpu_wait = RAWTOTAL(wait);
+ cpu_idle = RAWTOTAL(idle) + RAWTOTAL(steal);
+ cpu_sum = cpu_idle + cpu_user + cpu_sys + cpu_wait;
+
+ cpu_busy =
+ (double) (cpu_user +
+ cpu_sys) / (double) cpu_sum *100.0;
+ mvwprintw(padverb, 2, 0,
+ " -> CPU %%busy %5.1f%%\t>80%%\t>90%% ",
+ cpu_busy);
+ if (cpu_busy > 90.0) {
+ COLOUR wattrset(padverb, COLOR_PAIR(1));
+ mvwprintw(padverb, 2, 0, " DANGER");
+ } else if (cpu_busy > 80.0) {
+ COLOUR wattrset(padverb, COLOR_PAIR(4));
+ mvwprintw(padverb, 2, 0, "Warning");
+ } else {
+ COLOUR wattrset(padverb, COLOR_PAIR(2));
+ mvwprintw(padverb, 2, 0, " OK");
+ }
+ COLOUR wattrset(padverb, COLOR_PAIR(0));
+ }
+
+ } /* if (cursed) */
+ } /* if (show_smp || show_verbose) */
+ if (show_util) {
+ proc_read(P_STAT);
+ proc_cpu();
+ if (cursed) {
+ BANNER(padutil, "CPU Utilisation Stats");
+ mvwprintw(padutil, 2, 0, "CPU");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 0, "%3d", i + 1);
+ mvwprintw(padutil, 1, 0, "ALL");
+ if (first_util) {
+ mvwprintw(padutil, 5, 27,
+ " Please wait gathering CPU statistics");
+ } else {
+ COLOUR wattrset(padutil, COLOR_PAIR(2)); /* Green */
+ mvwprintw(padutil, 2, 4, " User%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 4, "%7.1f",
+ RAW(user) / elapsed);
+ mvwprintw(padutil, 1, 4, "%7.1f",
+ RAWTOTAL(user) / elapsed);
+ mvwprintw(padutil, 2, 11, " Nice%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 11, "%7.1f",
+ RAW(nice) / elapsed);
+ mvwprintw(padutil, 1, 11, "%7.1f",
+ RAWTOTAL(nice) / elapsed);
+
+ COLOUR wattrset(padutil, COLOR_PAIR(1)); /* Red */
+ mvwprintw(padutil, 2, 18, " Sys%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 18, "%7.1f",
+ RAW(sys) / elapsed);
+ mvwprintw(padutil, 1, 18, "%7.1f",
+ RAWTOTAL(sys) / elapsed);
+
+ COLOUR wattrset(padutil, COLOR_PAIR(3)); /* Yellow */
+ mvwprintw(padutil, 2, 25, " Idle%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 25, "%7.1f",
+ RAW(idle) / elapsed);
+ mvwprintw(padutil, 1, 25, "%7.1f",
+ RAWTOTAL(idle) / elapsed);
+ mvwprintw(padutil, 2, 32, " Wait%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 32, "%7.1f",
+ RAW(wait) / elapsed);
+ mvwprintw(padutil, 1, 32, "%7.1f",
+ RAWTOTAL(wait) / elapsed);
+
+ COLOUR wattrset(padutil, COLOR_PAIR(1)); /* Red */
+ mvwprintw(padutil, 2, 39, " HWirq%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 39, "%7.1f",
+ RAW(irq) / elapsed);
+ mvwprintw(padutil, 1, 39, "%7.1f",
+ RAWTOTAL(irq) / elapsed);
+ mvwprintw(padutil, 2, 46, " SWirq%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 46, "%7.1f",
+ RAW(softirq) / elapsed);
+ mvwprintw(padutil, 1, 46, "%7.1f",
+ RAWTOTAL(softirq) / elapsed);
+
+ COLOUR wattrset(padutil, COLOR_PAIR(5)); /* Magenta */
+ mvwprintw(padutil, 2, 53, " Steal%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 53, "%7.1f",
+ RAW(steal) / elapsed);
+ mvwprintw(padutil, 1, 53, "%7.1f",
+ RAWTOTAL(steal) / elapsed);
+
+ COLOUR wattrset(padutil, COLOR_PAIR(6)); /* Cyan */
+ mvwprintw(padutil, 2, 60, " Guest%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 60, "%7.1f",
+ RAW(guest) / elapsed);
+ mvwprintw(padutil, 1, 60, "%7.1f",
+ RAWTOTAL(guest) / elapsed);
+ mvwprintw(padutil, 2, 67, " GuestNice%%");
+ for (i = 0; i < cpus; i++)
+ mvwprintw(padutil, 3 + i, 67, "%7.1f",
+ RAW(guest_nice) / elapsed);
+ mvwprintw(padutil, 1, 67, "%7.1f",
+ RAWTOTAL(guest_nice) / elapsed);
+ }
+ COLOUR wattrset(padutil, COLOR_PAIR(0));
+ DISPLAY(padutil, i + 3);
+ } else {
+ if (first_util) {
+ fprintf(fp,
+ "CPUUTIL_ALL,CPU Util Stats %s,User%%,Nice%%,Sys%%,Idle%%,Wait%%,Irq%%,Softirq%%,Steal%%,Guest%%,Guest_nice%%\n",
+ run_name);
+ for (i = 1; i <= cpus; i++)
+ fprintf(fp,
+ "CPUUTIL%03d,CPU Util Stats CPU%d %s,User%%,Nice%%,Sys%%,Idle%%,Wait%%,Irq%%,Softirq%%,Steal%%,Guest%%,Guest_nice%%\n",
+ i, i, run_name);
+ }
+ fprintf(fp,
+ "CPUUTIL_ALL,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n",
+ LOOP, RAWTOTAL(user) / elapsed,
+ RAWTOTAL(nice) / elapsed, RAWTOTAL(sys) / elapsed,
+ RAWTOTAL(idle) / elapsed, RAWTOTAL(wait) / elapsed,
+ RAWTOTAL(irq) / elapsed,
+ RAWTOTAL(softirq) / elapsed,
+ RAWTOTAL(steal) / elapsed,
+ RAWTOTAL(guest) / elapsed,
+ RAWTOTAL(guest_nice) / elapsed);
+ for (i = 0; i < cpus; i++) {
+ fprintf(fp,
+ "CPUUTIL%03d,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n",
+ i, LOOP, RAW(user) / elapsed,
+ RAW(nice) / elapsed, RAW(sys) / elapsed,
+ RAW(idle) / elapsed, RAW(wait) / elapsed,
+ RAW(irq) / elapsed, RAW(softirq) / elapsed,
+ RAW(steal) / elapsed, RAW(guest) / elapsed,
+ RAW(guest_nice) / elapsed);
+ }
+ }
+ first_util = 0;
+ }
+#ifdef POWER
+ if (show_lpar) {
+ if (lparcfg.timebase == -1) {
+ lparcfg.timebase = 0;
+ proc_read(P_CPUINFO);
+ for (i = 0; i < proc[P_CPUINFO].lines - 1; i++) {
+ if (!strncmp("timebase", proc[P_CPUINFO].line[i], 8)) {
+ sscanf(proc[P_CPUINFO].line[i], "timebase : %lld",
+ &lparcfg.timebase);
+ break;
+ }
+ }
+ }
+ ret = proc_lparcfg();
+ if (cursed) {
+ BANNER(padlpar, "PowerVM LPAR");
+ if (ret == 0) {
+ COLOUR wattrset(padlpar, COLOR_PAIR(1));
+ mvwprintw(padlpar, 2, 0,
+ "Reading data from /proc/ppc64/lparcfg failed");
+ mvwprintw(padlpar, 3, 0,
+ "This is probably a Native Virtual Machine");
+ COLOUR wattrset(padlpar, COLOR_PAIR(0));
+ } else
+ if (power_vm_type == VM_POWERKVM_HOST
+ || power_vm_type == VM_POWERKVM_GUEST) {
+ COLOUR wattrset(padlpar, COLOR_PAIR(5));
+ mvwprintw(padlpar, 2, 0,
+ "Reading data from /proc/ppc64/lparcfg mostly failed");
+ mvwprintw(padlpar, 3, 0,
+ "PowerKVM does not many of these stats");
+ COLOUR wattrset(padlpar, COLOR_PAIR(0));
+ } else {
+ mvwprintw(padlpar, 1, 0,
+ "LPAR=%d SerialNumber=%s Type=%s",
+ lparcfg.partition_id, lparcfg.serial_number,
+ lparcfg.system_type);
+ mvwprintw(padlpar, 2, 0,
+ "Flags: Shared-CPU=%-5s Capped=%-5s SMT-mode=%d",
+ lparcfg.
+ shared_processor_mode ? "true" : "false",
+ lparcfg.capped ? "true" : "false",
+ lparcfg.smt_mode);
+ COLOUR wattrset(padlpar, COLOR_PAIR(2));
+ mvwprintw(padlpar, 3, 0,
+ "Systems CPU Pool=%8.2f Active=%8.2f Total=%8.2f",
+ (float) lparcfg.pool_capacity / 100.0,
+ (float) lparcfg.system_active_processors,
+ (float) lparcfg.system_potential_processors);
+ COLOUR wattrset(padlpar, COLOR_PAIR(3));
+ mvwprintw(padlpar, 4, 0,
+ "LPARs CPU Min=%8.2f Entitlement=%8.2f Max=%8.2f",
+ lparcfg.MinEntCap / 100.0,
+ lparcfg.partition_entitled_capacity / 100.0,
+ lparcfg.partition_max_entitled_capacity /
+ 100.0);
+ COLOUR wattrset(padlpar, COLOR_PAIR(5));
+ mvwprintw(padlpar, 5, 0,
+ "Virtual CPU Min=%8.2f VP Now=%8.2f Max=%8.2f",
+ (float) lparcfg.MinProcs,
+ (float) lparcfg.partition_active_processors,
+ (float) lparcfg.
+ partition_potential_processors);
+ COLOUR wattrset(padlpar, COLOR_PAIR(6));
+ mvwprintw(padlpar, 6, 0,
+ "Memory Min=%8.2f Desired=%8.2f ",
+ (float) lparcfg.MinMem,
+ (float) lparcfg.DesMem);
+ COLOUR wattrset(padlpar, COLOR_PAIR(0));
+ mvwprintw(padlpar, 7, 0,
+ "Other Weight=%8.2f UnallocWeight=%8.2f Capacity=%8.2f",
+ (float) lparcfg.capacity_weight,
+ (float) lparcfg.unallocated_capacity_weight,
+ (float) lparcfg.CapInc / 100.0);
+
+ mvwprintw(padlpar, 8, 0,
+ " BoundThrds=%8.2f UnallocCapacity=%8.2f Increment",
+ (float) lparcfg.BoundThrds,
+ (float) lparcfg.unallocated_capacity);
+ if (lparcfg.purr_diff == 0 || lparcfg.timebase < 1) {
+ mvwprintw(padlpar, 9, 0,
+ "lparcfg: purr field always zero, upgrade to SLES9+sp1 or RHEL4+u1");
+ } else {
+ if (lpar_first_time) {
+ mvwprintw(padlpar, 9, 0,
+ "Please wait gathering data");
+
+ lpar_first_time = 0;
+ } else {
+ COLOUR wattrset(padlpar, COLOR_PAIR(1));
+ mvwprintw(padlpar, 9, 0,
+ "Physical CPU use=%8.3f ",
+ (double) lparcfg.purr_diff /
+ (double) lparcfg.timebase / elapsed);
+ if (lparcfg.pool_idle_time != NUMBER_NOT_VALID
+ && lparcfg.pool_idle_saved != 0)
+ mvwprintw(padlpar, 9, 29,
+ "PoolIdleTime=%8.2f",
+ (double) lparcfg.pool_idle_diff /
+ (double) lparcfg.timebase /
+ elapsed);
+ COLOUR wattrset(padlpar, COLOR_PAIR(0));
+ mvwprintw(padlpar, 9, 54, "[timebase=%lld]",
+ lparcfg.timebase);
+ }
+ }
+ }
+ DISPLAY(padlpar, 10);
+ } else {
+ /* Only print LPAR info to spreadsheet if in shared processor mode */
+ if (ret != 0 && (lparcfg.shared_processor_mode > 0 || lparcfg.DedDonMode > 0)
+ && power_vm_type == VM_POWERVM)
+ fprintf(fp, "LPAR,%s,%9.6f,%d,%d,%d,%d,%d,%.2f,%.2f,%.2f,%d,%d,%d,%d,%d,%d,%d,%d,%d,%.2f,%d\n", LOOP, (double) lparcfg.purr_diff / (double) lparcfg.timebase / elapsed, lparcfg.capped, lparcfg.shared_processor_mode, lparcfg.system_potential_processors, lparcfg.system_active_processors, lparcfg.pool_capacity /100, lparcfg.MinEntCap / 100.0, lparcfg.partition_entitled_capacity / 100.0, lparcfg.partition_max_entitled_capacity / 100.0, lparcfg.MinProcs, cpus, /* report logical CPU here so analyser graph CPU% vs VPs reports correctly */
+ lparcfg.partition_active_processors,
+ lparcfg.partition_potential_processors,
+ lparcfg.capacity_weight,
+ lparcfg.unallocated_capacity_weight,
+ lparcfg.BoundThrds,
+ lparcfg.MinMem,
+ lparcfg.unallocated_capacity,
+ (double) lparcfg.pool_idle_diff /
+ (double) lparcfg.timebase / elapsed,
+ lparcfg.smt_mode);
+ }
+ }
+#endif /*POWER*/
+#ifdef NVIDIA_GPU
+ if (show_gpu) {
+ if (!cursed && first_time_gpu)
+ gpu_init();
+ for (i = 0; i < gpu_devices; i++) {
+ if (cursed && first_time_gpu) {
+ if (nvmlDeviceGetName
+ (gpu_device[i], &gpu_name[i][0],
+ 1024) != NVML_SUCCESS)
+ strcpy(gpu_name[i], "NVML API Failed");
+ }
+ if (nvmlDeviceGetUtilizationRates
+ (gpu_device[i], &gpu_util[i]) != NVML_SUCCESS) {
+ gpu_util[i].gpu = 999;
+ gpu_util[i].memory = 999;
+ }
+ if (nvmlDeviceGetTemperature
+ (gpu_device[i], NVML_TEMPERATURE_GPU,
+ &gpu_temp[i]) != NVML_SUCCESS)
+ gpu_temp[i] = 999;
+ if (nvmlDeviceGetPowerUsage(gpu_device[i], &gpu_watts[i])
+ != NVML_SUCCESS)
+ gpu_watts[i] = 999000;
+ if (nvmlDeviceGetClockInfo
+ (gpu_device[i], NVML_CLOCK_GRAPHICS,
+ &gpu_clock[i]) != NVML_SUCCESS)
+ gpu_clock[i] = 999;
+ }
+ if (cursed) {
+ first_time_gpu = 0;
+ BANNER(padgpu, "NVIDIA GPU Accelerator");
+
+ mvwprintw(padgpu, 1, 1,
+ "Driver Version:%s NVML Version: %s",
+ gpu_driver_version, gpu_nvml_version);
+
+ mvwprintw(padgpu, 2, 1, "GPU");
+ mvwprintw(padgpu, 3, 1, "No.");
+ COLOUR wattrset(padgpu, COLOR_PAIR(1));
+ mvwprintw(padgpu, 3, 5, "GPU-MHz");
+ COLOUR wattrset(padgpu, COLOR_PAIR(2));
+ mvwprintw(padgpu, 2, 14, "GPU-Utilisation");
+ mvwprintw(padgpu, 3, 14, "Processor-Memory");
+ COLOUR wattrset(padgpu, COLOR_PAIR(3));
+ mvwprintw(padgpu, 2, 31, "Temperature");
+ mvwprintw(padgpu, 3, 31, " Centigrade");
+ COLOUR wattrset(padgpu, COLOR_PAIR(5));
+ mvwprintw(padgpu, 2, 44, "Power-Use");
+ mvwprintw(padgpu, 3, 44, " Watts");
+ COLOUR wattrset(padgpu, COLOR_PAIR(0));
+ mvwprintw(padgpu, 2, 55, "Name");
+
+ for (i = 0; i < gpu_devices; i++) {
+ mvwprintw(padgpu, 4 + i, 1, "%3d", i);
+ COLOUR wattrset(padgpu, COLOR_PAIR(1));
+ mvwprintw(padgpu, 4 + i, 5, "%7d", (int) gpu_clock[i]);
+ COLOUR wattrset(padgpu, COLOR_PAIR(2));
+ mvwprintw(padgpu, 4 + i, 14, "%7d%% %7d%%",
+ (int) gpu_util[i].gpu,
+ (int) gpu_util[i].memory);
+ COLOUR wattrset(padgpu, COLOR_PAIR(3));
+ mvwprintw(padgpu, 4 + i, 31, "%7d", (int) gpu_temp[i]);
+ COLOUR wattrset(padgpu, COLOR_PAIR(5));
+ mvwprintw(padgpu, 4 + i, 44, "%7.2f",
+ (int) gpu_watts[i] / 1000.0);
+ COLOUR wattrset(padgpu, COLOR_PAIR(0));
+ mvwprintw(padgpu, 4 + i, 55, "%-s", &gpu_name[i][0]);
+ }
+ DISPLAY(padgpu, 8);
+ } else {
+ if (!show_rrd) {
+ if (first_time_gpu) {
+ first_time_gpu = 0;
+ fprintf(fp,
+ "GPU_UTIL,NVidia GPU Utilisation Percent");
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",GPU%d", i + 1);
+ fprintf(fp, "\n");
+ fprintf(fp,
+ "GPU_MEM,NVidia Memory Utilisation Percent");
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",GPU%d", i + 1);
+ fprintf(fp, "\n");
+ fprintf(fp, "GPU_TEMP,NVidia Temperature C");
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",GPU%d", i + 1);
+ fprintf(fp, "\n");
+ fprintf(fp, "GPU_WATTS,NVidia Power Draw Watts");
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",GPU%d", i + 1);
+ fprintf(fp, "\n");
+ fprintf(fp, "GPU_MHZ,NVidia GPU MHz");
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",GPU%d", i + 1);
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "GPU_UTIL,%s", LOOP);
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",%d", (int) gpu_util[i].gpu);
+ fprintf(fp, "\n");
+ fprintf(fp, "GPU_MEM,%s", LOOP);
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",%d", (int) gpu_util[i].memory);
+ fprintf(fp, "\n");
+ fprintf(fp, "GPU_TEMP,%s", LOOP);
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",%d", (int) gpu_temp[i]);
+ fprintf(fp, "\n");
+ fprintf(fp, "GPU_WATTS,%s", LOOP);
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",%d", (int) gpu_watts[i] / 1000);
+ fprintf(fp, "\n");
+ fprintf(fp, "GPU_MHZ,%s", LOOP);
+ for (i = 0; i < gpu_devices; i++)
+ fprintf(fp, ",%d", (int) gpu_clock[i]);
+ fprintf(fp, "\n");
+ }
+ }
+ }
+#endif /*NVIDIA_GPU */
+ if (show_mhz) {
+ int padline, lineno, cpuno, col, thrds, cores;
+#ifdef POWER
+ char *clockstr = "clock ";
+#define DATACOL 9
+#else
+ char *clockstr = "cpu MHz";
+#define DATACOL 11
+#endif /* POWER */
+ proc_read(P_CPUINFO);
+
+ if (cursed) {
+ /*
+ 0123456789012345678
+ cpu MHz : 3336.183 Intel
+ clock : 3425.000000MHz Power
+ */
+ lscpu_init();
+#ifdef POWER
+ if (lparcfg.smt_mode > lscpu.threads)
+ thrds = lparcfg.smt_mode;
+ else
+#endif /*POWER*/
+ thrds = lscpu.threads;
+ if (thrds < 1)
+ thrds = 1;
+ BANNER(padmhz, "CPU MHz per Core and Thread");
+#ifdef POWER
+ mvwprintw(padmhz, 1, 10,
+ "lparcfgSMT=%d lscpu.threads=%d mode=%d [1=AllCPUs 2=Cores 3=Graphs]",
+ lparcfg.smt_mode, lscpu.threads, show_mhz);
+#else /*POWER */
+ mvwprintw(padmhz, 1, 10,
+ "lscpu.threads=%d mode=%d [1=AllCPUs 2=Cores 3=Graphs]",
+ lscpu.threads, show_mhz);
+#endif /*POWER */
+ if (show_mhz == 1)
+ mvwprintw(padmhz, 2, 1, "CPU MHz ");
+ else
+ mvwprintw(padmhz, 2, 1, "Core MHz ");
+ if (show_mhz == 3)
+ mvwprintw(padmhz, 2, 10,
+ "---------1---------2---------3---------4---------5---------6 GHz");
+
+ col = 0;
+ cpuno = 1;
+ cores = 0;
+ padline = 3;
+ min_mhz = 999999999999999999.0;
+ max_mhz = 0.0;
+ for (lineno = 0; lineno < proc[P_CPUINFO].lines; lineno++) {
+ if (strncmp
+ (clockstr, proc[P_CPUINFO].line[lineno],
+ strlen(clockstr)) == 0) {
+ if (show_mhz == 1
+ || ((show_mhz == 2 || show_mhz == 3)
+ && ((cpuno + 7) % thrds) == 0)) {
+ cores++;
+ mhz = 0.0;
+ sscanf(&proc[P_CPUINFO].line[lineno][DATACOL],
+ "%f", &mhz);
+ mvwprintw(padmhz, padline, col, "%3d=%4.0f",
+ (show_mhz != 1) ? cores : cpuno, mhz);
+ if (show_mhz == 3) {
+ if (mhz > avg_mhz) {
+ COLOUR wattrset(padmhz, COLOR_PAIR(1));
+ } else {
+ COLOUR wattrset(padmhz, COLOR_PAIR(2));
+ }
+ for (i = 1; i < mhz / 100; i++)
+ mvwprintw(padmhz, padline, col + 9 + i, "#");
+ COLOUR wattrset(padmhz, COLOR_PAIR(0));
+ for (; i < 60; i++)
+ mvwprintw(padmhz, padline, col + 9 + i, " ");
+ }
+ padline++;
+ if (padline > 22) {
+ padline = 3;
+ col = col + 9;
+ }
+ if (mhz != 0.0) {
+ if (mhz < min_mhz)
+ min_mhz = mhz;
+ if (mhz > max_mhz)
+ max_mhz = mhz;
+ }
+ }
+ cpuno++;
+ }
+ if (cpuno > 160)
+ break;
+ }
+ avg_mhz = (min_mhz + max_mhz) / 2;
+ if(cores >= 20)
+ lineno = 23;
+ else
+ lineno = cores+3;
+ DISPLAY(padmhz, lineno);
+ } else {
+ if (!show_rrd)
+ fprintf(fp, "MHZ,%s", LOOP);
+ for (lineno = 0; lineno < proc[P_CPUINFO].lines; lineno++) {
+ if (strncmp
+ (clockstr, proc[P_CPUINFO].line[lineno],
+ strlen(clockstr)) == 0) {
+ mhz = 0.0;
+ sscanf(&proc[P_CPUINFO].line[lineno][DATACOL],
+ "%f", &mhz);
+ if (!show_rrd)
+ fprintf(fp, ",%.0f", mhz);
+ }
+ }
+ if (!show_rrd)
+ fprintf(fp, "\n");
+ }
+ }
+ if (show_memory) {
+ proc_read(P_MEMINFO);
+ proc_mem();
+ if (cursed) {
+#define RAMCOL 16
+#define SWAPCOL 28
+#define HIGHCOL 45
+#define LOWCOL 60
+
+ BANNER(padmem, "Memory and Swap");
+
+ COLOUR wattrset(padmem, COLOR_PAIR(1));
+ mvwprintw(padmem, 1, 1, "PageSize:%dKB", pagesize / 1024);
+ COLOUR wattrset(padmem, COLOR_PAIR(0));
+ mvwprintw(padmem, 2, 1, "Total (MB)");
+ mvwprintw(padmem, 3, 1, "Free (MB)");
+ mvwprintw(padmem, 4, 1, "Free Percent");
+
+ COLOUR wattrset(padmem, COLOR_PAIR(2));
+ mvwprintw(padmem, 1, RAMCOL, "RAM-Memory");
+ mvwprintw(padmem, 2, RAMCOL, "%10.1f",
+ p->mem.memtotal / 1024.0);
+ mvwprintw(padmem, 3, RAMCOL, "%10.1f",
+ p->mem.memfree / 1024.0);
+ mvwprintw(padmem, 4, RAMCOL, "%10.1f%%",
+ p->mem.memfree ==
+ 0 ? 0.0 : 100.0 * (float) p->mem.memfree /
+ (float) p->mem.memtotal);
+ COLOUR wattrset(padmem, COLOR_PAIR(3));
+ mvwprintw(padmem, 1, SWAPCOL, "Swap-Space");
+ mvwprintw(padmem, 2, SWAPCOL, "%10.1f",
+ p->mem.swaptotal / 1024.0);
+ mvwprintw(padmem, 3, SWAPCOL, "%10.1f",
+ p->mem.swapfree / 1024.0);
+ mvwprintw(padmem, 4, SWAPCOL, "%10.1f%%",
+ p->mem.swapfree ==
+ 0 ? 0.0 : 100.0 * (float) p->mem.swapfree /
+ (float) p->mem.swaptotal);
+ COLOUR wattrset(padmem, COLOR_PAIR(4));
+ mvwprintw(padmem, 1, HIGHCOL, "High-Memory");
+ if (p->mem.hightotal > 0.0) {
+ mvwprintw(padmem, 2, HIGHCOL, "%8.1f",
+ p->mem.hightotal / 1024.0);
+ mvwprintw(padmem, 3, HIGHCOL, "%8.1f",
+ p->mem.highfree / 1024.0);
+ mvwprintw(padmem, 4, HIGHCOL, "%8.1f%%",
+ p->mem.highfree ==
+ 0 ? 0.0 : 100.0 * (float) p->mem.highfree /
+ (float) p->mem.hightotal);
+ } else
+ mvwprintw(padmem, 2, HIGHCOL, "- not in use");
+ COLOUR wattrset(padmem, COLOR_PAIR(6));
+ mvwprintw(padmem, 1, LOWCOL, " Low-Memory");
+ if (p->mem.lowtotal > 0.0) {
+ mvwprintw(padmem, 2, LOWCOL, "%8.1f",
+ p->mem.lowtotal / 1024.0);
+ mvwprintw(padmem, 3, LOWCOL, "%8.1f",
+ p->mem.lowfree / 1024.0);
+ mvwprintw(padmem, 4, LOWCOL, "%8.1f%%",
+ p->mem.lowfree ==
+ 0 ? 0.0 : 100.0 * (float) p->mem.lowfree /
+ (float) p->mem.lowtotal);
+ } else
+ mvwprintw(padmem, 2, LOWCOL, "- not in use");
+ COLOUR wattrset(padmem, COLOR_PAIR(5));
+
+
+ mvwprintw(padmem, 5, 1,
+ "Linux Kernel Internal Memory (MB)");
+#ifndef SMALLMEM
+ mvwprintw(padmem, 6, 1,
+ " Cached=%10.1f Active=%10.1f",
+ p->mem.cached / 1024.0, p->mem.active / 1024.0);
+#else
+ mvwprintw(padmem, 6, 1,
+ " Shared=%10.1f Cached=%10.1f Active=%10.1f",
+ p->mem.memshared / 1024.0,
+ p->mem.cached / 1024.0, p->mem.active / 1024.0);
+ mvwprintw(padmem, 5, 68, "MB");
+ mvwprintw(padmem, 6, 55, "bigfree=%10.1f",
+ p->mem.bigfree / 1024);
+#endif /*SMALLMEM*/
+ mvwprintw(padmem, 7, 1,
+ "Buffers=%10.1f Swapcached=%10.1f Inactive =%10.1f",
+ p->mem.buffers / 1024.0,
+ p->mem.swapcached / 1024.0,
+ p->mem.inactive / 1024.0);
+#ifndef SMALLMEM
+ mvwprintw(padmem, 8, 1,
+ "Dirty =%10.1f Writeback =%10.1f Mapped =%10.1f",
+ p->mem.dirty / 1024.0, p->mem.writeback / 1024.0,
+ p->mem.mapped / 1024.0);
+ mvwprintw(padmem, 9, 1,
+ "Slab =%10.1f Commit_AS =%10.1f PageTables=%10.1f",
+ p->mem.slab / 1024.0,
+ p->mem.committed_as / 1024.0,
+ p->mem.pagetables / 1024.0);
+#endif /*SMALLMEM */
+#ifdef POWER
+ if (!show_lpar) /* check if already called above */
+ proc_lparcfg();
+ if (lparcfg.cmo_enabled == 0)
+ mvwprintw(padmem, 10, 1, "AMS is not active");
+ else
+ mvwprintw(padmem, 10, 1,
+ "AMS id=%d Weight=%-3d pmem=%ldMB hpi=%.1f/s hpit=%.1f(sec) Pool=%ldMB Loan=%ldKB ",
+ (int) lparcfg.entitled_memory_pool_number,
+ (int) lparcfg.entitled_memory_weight,
+ (long) (lparcfg.backing_memory) / 1024 /
+ 1024,
+ (double) (lparcfg.cmo_faults_diff) / elapsed,
+ (double) (lparcfg.cmo_fault_time_usec_diff) /
+ 1000 / 1000 / elapsed,
+ (long) lparcfg.entitled_memory_pool_size /
+ 1024 / 1024,
+ (long) lparcfg.entitled_memory_loan_request /
+ 1024);
+
+ COLOUR wattrset(padmem, COLOR_PAIR(0));
+ DISPLAY(padmem, 11);
+#else /* POWER */
+ COLOUR wattrset(padmem, COLOR_PAIR(0));
+ DISPLAY(padmem, 10);
+#endif /* POWER */
+ } else {
+
+ if (show_rrd)
+ str_p =
+ "rrdtool update mem.rrd %s:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f\n";
+ else
+ str_p =
+ "MEM,%s,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f\n";
+ fprintf(fp, str_p, LOOP, p->mem.memtotal / 1024.0,
+ p->mem.hightotal / 1024.0,
+ p->mem.lowtotal / 1024.0,
+ p->mem.swaptotal / 1024.0, p->mem.memfree / 1024.0,
+ p->mem.highfree / 1024.0, p->mem.lowfree / 1024.0,
+ p->mem.swapfree / 1024.0,
+ p->mem.memshared / 1024.0, p->mem.cached / 1024.0,
+ p->mem.active / 1024.0,
+#ifndef SMALLMEM
+ -1.0,
+#else
+ p->mem.bigfree / 1024.0,
+#endif /*SMALLMEM*/
+ p->mem.buffers / 1024.0,
+ p->mem.swapcached / 1024.0,
+ p->mem.inactive / 1024.0);
+#ifdef POWER
+ if (lparcfg.cmo_enabled != 0) {
+ if (!show_rrd)
+ fprintf(fp,
+ "MEMAMS,%s,%d,%d,%.1f,%.3lf,0,0,0,%.1f,%ld,%ld,%ld\n",
+ LOOP,
+ (int) lparcfg.entitled_memory_pool_number,
+ (int) lparcfg.entitled_memory_weight,
+ (float) (lparcfg.cmo_faults_diff) /
+ elapsed,
+ (float) (lparcfg.
+ cmo_fault_time_usec_diff) / 1000 /
+ 1000 / elapsed,
+ /* three zeros here */
+ (float) (lparcfg.backing_memory) / 1024 /
+ 1024, lparcfg.cmo_page_size / 1024,
+ lparcfg.entitled_memory_pool_size / 1024 /
+ 1024,
+ lparcfg.entitled_memory_loan_request /
+ 1024);
+ }
+#ifdef EXPERIMENTAL
+ if (!show_rrd)
+ fprintf(fp,
+ "MEMEXPERIMENTAL,%s,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld\n",
+ LOOP, (long) lparcfg.DesEntCap,
+ (long) lparcfg.DesProcs,
+ (long) lparcfg.DesVarCapWt,
+ (long) lparcfg.DedDonMode,
+ (long) lparcfg.group, (long) lparcfg.pool,
+ (long) lparcfg.entitled_memory,
+ (long) lparcfg.entitled_memory_group_number,
+ (long) lparcfg.
+ unallocated_entitled_memory_weight,
+ (long) lparcfg.
+ unallocated_io_mapping_entitlement);
+#endif /* EXPERIMENTAL */
+#endif /* POWER */
+ }
+/* for testing large page
+ p->mem.hugefree = 250;
+ p->mem.hugetotal = 1000;
+ p->mem.hugesize = 16*1024;
+*/
+ }
+#ifndef SMALLMEM
+ if (show_large) {
+ proc_read(P_MEMINFO);
+ proc_mem();
+ if (cursed) {
+ BANNER(padlarge, "Large (Huge) Page");
+ if (p->mem.hugetotal > 0) {
+ if (p->mem.hugetotal - p->mem.hugefree > huge_peak)
+ huge_peak = p->mem.hugetotal - p->mem.hugefree;
+ mvwprintw(padlarge, 1, 1,
+ "Total Pages=%7ld 100.0%% Huge Page Size =%ld KB",
+ p->mem.hugetotal, p->mem.hugesize);
+ mvwprintw(padlarge, 2, 1,
+ "Used Pages=%7ld %5.1f%% Used Pages Peak=%-8ld",
+ (long) (p->mem.hugetotal - p->mem.hugefree),
+ (p->mem.hugetotal -
+ p->mem.hugefree) /
+ (float) p->mem.hugetotal * 100.0, huge_peak);
+ mvwprintw(padlarge, 3, 1, "Free Pages=%7ld %5.1f%%",
+ p->mem.hugefree,
+ p->mem.hugefree / (float) p->mem.hugetotal *
+ 100.0);
+ } else {
+ mvwprintw(padlarge, 1, 1, " There are no Huge Pages");
+ mvwprintw(padlarge, 2, 1, " - see /proc/meminfo");
+ }
+ DISPLAY(padlarge, 4);
+ } else {
+ if (p->mem.hugetotal > 0) {
+ if (first_huge == 1) {
+ first_huge = 0;
+ fprintf(fp,
+ "HUGEPAGES,Huge Page Use %s,HugeTotal,HugeFree,HugeSizeMB\n",
+ run_name);
+ }
+ fprintf(fp, "HUGEPAGES,%s,%ld,%ld,%.1f\n",
+ LOOP,
+ p->mem.hugetotal,
+ p->mem.hugefree, p->mem.hugesize / 1024.0);
+ }
+ }
+ }
+#endif /* SMALLMEM */
+ if (show_vm) {
+#define VMDELTA(variable) (p->vm.variable - q->vm.variable)
+#define VMCOUNT(variable) (p->vm.variable )
+ ret = read_vmstat();
+ if (cursed) {
+ BANNER(padpage, "Virtual Memory");
+
+ COLOUR wattrset(padpage, COLOR_PAIR(6));
+ if (ret < 0) {
+ mvwprintw(padpage, 2, 2,
+ "Virtual Memory stats not supported with this kernel");
+ mvwprintw(padpage, 3, 2,
+ "/proc/vmstat only seems to appear in 2.6 onwards");
+
+ } else {
+ if (vm_first_time) {
+ mvwprintw(padpage, 2, 2,
+ "Please wait - collecting data");
+ vm_first_time = 0;
+ } else {
+ mvwprintw(padpage, 1, 0,
+ "nr_dirty =%9lld pgpgin =%8lld",
+ VMCOUNT(nr_dirty), VMDELTA(pgpgin));
+ mvwprintw(padpage, 2, 0,
+ "nr_writeback=%9lld pgpgout =%8lld",
+ VMCOUNT(nr_writeback), VMDELTA(pgpgout));
+ mvwprintw(padpage, 3, 0,
+ "nr_unstable =%9lld pgpswpin =%8lld",
+ VMCOUNT(nr_unstable), VMDELTA(pswpin));
+ mvwprintw(padpage, 4, 0,
+ "nr_table_pgs=%9lld pgpswpout =%8lld",
+ VMCOUNT(nr_page_table_pages),
+ VMDELTA(pswpout));
+ mvwprintw(padpage, 5, 0,
+ "nr_mapped =%9lld pgfree =%8lld",
+ VMCOUNT(nr_mapped), VMDELTA(pgfree));
+ if(VMCOUNT(nr_slab) != -1 ) { /* older nr_slab only */
+ mvwprintw(padpage, 6, 0,
+ "nr_slab =%9lld pgactivate =%8lld",
+ VMCOUNT(nr_slab), VMDELTA(pgactivate));
+ mvwprintw(padpage, 7, 0,
+ " pgdeactivate=%8lld",
+ VMDELTA(pgdeactivate));
+ } else { /*new nr_slab_reclaimable / nr_slab_unreclaimable Kernel 2.6.19+ */
+ mvwprintw(padpage, 6, 0,
+ "slab_reclaim=%9lld pgactivate =%8lld",
+ VMCOUNT(nr_slab_reclaimable), VMDELTA(pgactivate));
+ mvwprintw(padpage, 7, 0,
+ "slab_unreclm=%9lld pgdeactivate=%8lld",
+ VMCOUNT(nr_slab_unreclaimable), VMDELTA(pgdeactivate));
+ }
+ mvwprintw(padpage, 8, 0,
+ "allocstall =%9lld pgfault =%8lld kswapd_steal =%7lld",
+ VMDELTA(allocstall), VMDELTA(pgfault),
+ VMDELTA(kswapd_steal));
+ mvwprintw(padpage, 9, 0,
+ "pageoutrun =%9lld pgmajfault =%8lld kswapd_inodesteal=%7lld",
+ VMDELTA(pageoutrun), VMDELTA(pgmajfault),
+ VMDELTA(kswapd_inodesteal));
+ mvwprintw(padpage, 10, 0,
+ "slabs_scanned=%8lld pgrotated =%8lld pginodesteal =%7lld",
+ VMDELTA(slabs_scanned),
+ VMDELTA(pgrotated),
+ VMDELTA(pginodesteal));
+
+
+
+ mvwprintw(padpage, 1, 46,
+ " High Normal DMA");
+ mvwprintw(padpage, 2, 46,
+ "alloc %7lld%7lld%7lld",
+ VMDELTA(pgalloc_high),
+ VMDELTA(pgalloc_normal),
+ VMDELTA(pgalloc_dma));
+ mvwprintw(padpage, 3, 46,
+ "refill %7lld%7lld%7lld",
+ VMDELTA(pgrefill_high),
+ VMDELTA(pgrefill_normal),
+ VMDELTA(pgrefill_dma));
+ mvwprintw(padpage, 4, 46,
+ "steal %7lld%7lld%7lld",
+ VMDELTA(pgsteal_high),
+ VMDELTA(pgsteal_normal),
+ VMDELTA(pgsteal_dma));
+ mvwprintw(padpage, 5, 46,
+ "scan_kswapd%7lld%7lld%7lld",
+ VMDELTA(pgscan_kswapd_high),
+ VMDELTA(pgscan_kswapd_normal),
+ VMDELTA(pgscan_kswapd_dma));
+ mvwprintw(padpage, 6, 46,
+ "scan_direct%7lld%7lld%7lld",
+ VMDELTA(pgscan_direct_high),
+ VMDELTA(pgscan_direct_normal),
+ VMDELTA(pgscan_direct_dma));
+ }
+ }
+ COLOUR wattrset(padpage, COLOR_PAIR(0));
+ DISPLAY(padpage, 11);
+ } else {
+ if (ret < 0) {
+ show_vm = 0;
+ } else if (vm_first_time) {
+ vm_first_time = 0;
+ if(VMCOUNT(nr_slab) == -1 )
+ slabstr = "nr_slab_reclaimable";
+ else
+ slabstr = "nr_slab";
+ fprintf(fp,
+ "VM,Paging and Virtual Memory,nr_dirty,nr_writeback,nr_unstable,nr_page_table_pages,nr_mapped,%s,pgpgin,pgpgout,pswpin,pswpout,pgfree,pgactivate,pgdeactivate,pgfault,pgmajfault,pginodesteal,slabs_scanned,kswapd_steal,kswapd_inodesteal,pageoutrun,allocstall,pgrotated,pgalloc_high,pgalloc_normal,pgalloc_dma,pgrefill_high,pgrefill_normal,pgrefill_dma,pgsteal_high,pgsteal_normal,pgsteal_dma,pgscan_kswapd_high,pgscan_kswapd_normal,pgscan_kswapd_dma,pgscan_direct_high,pgscan_direct_normal,pgscan_direct_dma\n", slabstr);
+ }
+ if (show_rrd)
+ str_p = "rrdtool update vm.rrd %s"
+ ":%lld:%lld:%lld:%lld:%lld"
+ ":%lld:%lld:%lld:%lld:%lld"
+ ":%lld:%lld:%lld:%lld:%lld"
+ ":%lld:%lld:%lld:%lld:%lld"
+ ":%lld:%lld:%lld:%lld:%lld"
+ ":%lld:%lld:%lld:%lld:%lld"
+ ":%lld:%lld:%lld:%lld:%lld" ":%lld:%lld\n";
+ else
+ str_p = "VM,%s"
+ ",%lld,%lld,%lld,%lld,%lld"
+ ",%lld,%lld,%lld,%lld,%lld"
+ ",%lld,%lld,%lld,%lld,%lld"
+ ",%lld,%lld,%lld,%lld,%lld"
+ ",%lld,%lld,%lld,%lld,%lld"
+ ",%lld,%lld,%lld,%lld,%lld"
+ ",%lld,%lld,%lld,%lld,%lld" ",%lld,%lld\n";
+ if(VMCOUNT(nr_slab) != -1)
+ tmpslab = VMCOUNT(nr_slab);
+ else
+ tmpslab = VMCOUNT(nr_slab_reclaimable);
+ fprintf(fp, str_p,
+ LOOP,
+ VMCOUNT(nr_dirty),
+ VMCOUNT(nr_writeback),
+ VMCOUNT(nr_unstable),
+ VMCOUNT(nr_page_table_pages),
+ VMCOUNT(nr_mapped),
+ tmpslab,
+ VMDELTA(pgpgin),
+ VMDELTA(pgpgout),
+ VMDELTA(pswpin),
+ VMDELTA(pswpout),
+ VMDELTA(pgfree),
+ VMDELTA(pgactivate),
+ VMDELTA(pgdeactivate),
+ VMDELTA(pgfault),
+ VMDELTA(pgmajfault),
+ VMDELTA(pginodesteal),
+ VMDELTA(slabs_scanned),
+ VMDELTA(kswapd_steal),
+ VMDELTA(kswapd_inodesteal),
+ VMDELTA(pageoutrun),
+ VMDELTA(allocstall),
+ VMDELTA(pgrotated),
+ VMDELTA(pgalloc_high),
+ VMDELTA(pgalloc_normal),
+ VMDELTA(pgalloc_dma),
+ VMDELTA(pgrefill_high),
+ VMDELTA(pgrefill_normal),
+ VMDELTA(pgrefill_dma),
+ VMDELTA(pgsteal_high),
+ VMDELTA(pgsteal_normal),
+ VMDELTA(pgsteal_dma),
+ VMDELTA(pgscan_kswapd_high),
+ VMDELTA(pgscan_kswapd_normal),
+ VMDELTA(pgscan_kswapd_dma),
+ VMDELTA(pgscan_direct_high),
+ VMDELTA(pgscan_direct_normal),
+ VMDELTA(pgscan_direct_dma));
+ }
+ }
+ if (show_kernel) {
+ proc_read(P_STAT);
+ proc_cpu();
+ proc_read(P_UPTIME);
+ proc_read(P_LOADAVG);
+ proc_kernel();
+ if (cursed) {
+ BANNER(padker, "Kernel and Load Average");
+#define MORECOL 21
+#define LOADCOL 41
+#define BOOTCOL 55
+ COLOUR wattrset(padker, COLOR_PAIR(1));
+ mvwprintw(padker, 1, 0, "Global-CPU-Stats---->");
+ mvwprintw(padker, 2, 0, " /proc/stat line 1");
+ mvwprintw(padker, 3, 0, "%ld ticks per second", ticks);
+ mvwprintw(padker, 4, 0, "100%%=1 CPUcoreThread");
+ COLOUR wattrset(padker, COLOR_PAIR(2));
+ mvwprintw(padker, 5, 0, "%8lld RunQueue",
+ p->cpu_total.running);
+ mvwprintw(padker, 6, 0, "%8lld Blocked",
+ p->cpu_total.blocked);
+ mvwprintw(padker, 7, 0, "%10.1f Context",
+ (float) (p->cpu_total.ctxt -
+ q->cpu_total.ctxt) / elapsed);
+ mvwprintw(padker, 8, 0, " Switch");
+ mvwprintw(padker, 9, 0, "%10.1f Forks",
+ (float) (p->cpu_total.procs -
+ q->cpu_total.procs) / elapsed);
+ mvwprintw(padker, 10, 0, "%10.1f Interrupts",
+ (float) (p->cpu_total.intr -
+ q->cpu_total.intr) / elapsed);
+
+ COLOUR wattrset(padker, COLOR_PAIR(1));
+ mvwprintw(padker, 1, MORECOL, "%8.1f%% user",
+ (float) (RAWTOTAL(user)) / elapsed);
+ mvwprintw(padker, 2, MORECOL, "%8.1f%% user_nice",
+ (float) (RAWTOTAL(nice)) / elapsed);
+ mvwprintw(padker, 3, MORECOL, "%8.1f%% system",
+ (float) (RAWTOTAL(sys)) / elapsed);
+ mvwprintw(padker, 4, MORECOL, "%8.1f%% idle",
+ (float) (RAWTOTAL(idle)) / elapsed);
+ mvwprintw(padker, 5, MORECOL, "%8.1f%% iowait",
+ (float) (RAWTOTAL(wait)) / elapsed);
+ mvwprintw(padker, 6, MORECOL, "%8.1f%% irq",
+ (float) (RAWTOTAL(irq)) / elapsed);
+ mvwprintw(padker, 7, MORECOL, "%8.1f%% softirq",
+ (float) (RAWTOTAL(softirq)) / elapsed);
+ mvwprintw(padker, 8, MORECOL, "%8.1f%% steal",
+ (float) (RAWTOTAL(steal)) / elapsed);
+ mvwprintw(padker, 9, MORECOL, "%8.1f%% guest",
+ (float) (RAWTOTAL(guest)) / elapsed);
+ mvwprintw(padker, 10, MORECOL, "%8.1f%% guest_nice",
+ (float) (RAWTOTAL(guest_nice)) / elapsed);
+
+ COLOUR wattrset(padker, COLOR_PAIR(3));
+ mvwprintw(padker, 1, LOADCOL, "Load Average");
+ mvwprintw(padker, 2, LOADCOL, " 1 mins %5.2f",
+ (float) p->cpu_total.mins1);
+ mvwprintw(padker, 3, LOADCOL, " 5 mins %5.2f",
+ (float) p->cpu_total.mins5);
+ mvwprintw(padker, 4, LOADCOL, "15 mins %5.2f",
+ (float) p->cpu_total.mins15);
+
+
+ COLOUR wattrset(padker, COLOR_PAIR(5));
+ mvwprintw(padker, 1, BOOTCOL, "CPU use since boottime");
+
+ updays = p->cpu_total.uptime / 60 / 60 / 24;
+ uphours =
+ (p->cpu_total.uptime -
+ updays * 60 * 60 * 24) / 60 / 60;
+ upmins =
+ (p->cpu_total.uptime - updays * 60 * 60 * 24 -
+ uphours * 60 * 60) / 60;
+ mvwprintw(padker, 2, BOOTCOL, "Uptime Days Hours Mins");
+ mvwprintw(padker, 3, BOOTCOL, "Uptime %4ld %5ld %4ld",
+ updays, uphours, upmins);
+
+ updays = p->cpu_total.idletime / 60 / 60 / 24 / cpus;
+ uphours =
+ (p->cpu_total.idletime -
+ updays * 60 * 60 * 24) / 60 / 60 / cpus;
+ upmins =
+ (p->cpu_total.idletime - updays * 60 * 60 * 24 -
+ uphours * 60 * 60) / 60 / cpus;
+ mvwprintw(padker, 4, BOOTCOL, "Idle %4ld %5ld %4ld",
+ updays, uphours, upmins);
+
+ average =
+ (p->cpu_total.uptime -
+ p->cpu_total.idletime) / p->cpu_total.uptime * 100.0;
+ if (average > 0.0)
+ mvwprintw(padker, 5, BOOTCOL,
+ "Average Busy Uptimee=%6.2f%%", average);
+ else
+ mvwprintw(padker, 5, BOOTCOL, "Uptime has overflowed");
+ mvwprintw(padker, 7, BOOTCOL, "%d CPU core threads", cpus);
+ mvwprintw(padker, 9, BOOTCOL, "Boot time %d", boottime);
+ mvwprintw(padker,10, BOOTCOL, "%s", boottime_str);
+ COLOUR wattrset(padker, COLOR_PAIR(0));
+ DISPLAY(padker, 11);
+ } else {
+ if (proc_first_time) {
+ q->cpu_total.ctxt = p->cpu_total.ctxt;
+ q->cpu_total.procs = p->cpu_total.procs;
+ proc_first_time = 0;
+ }
+ if (show_rrd)
+ str_p = /* LOOP 1 2 3 4 5 6 7 8 9 */
+ "rrdtool update proc.rrd %s:%.0f:%.0f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f\n";
+ else
+ str_p = /* LOOP 1 2 3 4 5 6 7 8 9 */
+ "PROC,%s,%.0f,%.0f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f\n";
+
+ /* These "-1"'s looks bad but it keeps the nmon for AIX format */
+ /* The stats are not available in Linux . . . unless you know better! */
+ fprintf(fp, str_p, LOOP,
+ (float) p->cpu_total.running, /*1 runqueue */
+ (float) p->cpu_total.blocked, /*2 swapin (# of processes waiting for IO completion */
+ (float) (p->cpu_total.ctxt - q->cpu_total.ctxt) / elapsed, /*3 pswitch */
+ -1.0, /*4 syscall */
+ -1.0, /*4 read */
+ -1.0, /*5 write */
+ (float) (p->cpu_total.procs - q->cpu_total.procs) / elapsed, /*6 fork */
+ -1.0, /*7 exec */
+ -1.0, /*8 sem */
+ -1.0); /*9 msg */
+ }
+ }
+
+ if (show_nfs) {
+ proc_read(P_NFS);
+ proc_read(P_NFSD);
+ proc_nfs();
+
+ if (cursed) {
+ if (nfs_first_time) {
+ memcpy(&q->nfs, &p->nfs, sizeof(struct nfs_stat));
+ nfs_first_time = 0;
+ }
+ if (nfs_clear) {
+ nfs_clear = 0;
+ for (i = 0; i < 25; i++)
+ mvwprintw(padnfs, i, 0,
+ " ");
+ }
+ BANNER(padnfs,
+ "Network Filesystem (NFS) I/O Operations per second");
+ if (show_nfs == 1) {
+ if (nfs_v2c_found || nfs_v2s_found)
+ mvwprintw(padnfs, 1, 0,
+ " Version 2 Client Server");
+ else
+ mvwprintw(padnfs, 1, 0, " Version 2 not active");
+
+ if (nfs_v3c_found || nfs_v3s_found)
+ mvwprintw(padnfs, 1, 41,
+ "Version 3 Client Server");
+ else
+ mvwprintw(padnfs, 1, 41, " Version 3 not active");
+ }
+ if (show_nfs == 2) {
+ if (nfs_v4c_found)
+ mvwprintw(padnfs, 1, 0,
+ " Version 4 Client (%d Stats found)",
+ nfs_v4c_names_count);
+ else
+ mvwprintw(padnfs, 1, 0,
+ " Version 4 Client side not active");
+ }
+ if (show_nfs == 3) {
+ if (nfs_v4s_found)
+ mvwprintw(padnfs, 1, 0,
+ " Version 4 Server (%d Stats found)",
+ nfs_v4s_names_count);
+ else
+ mvwprintw(padnfs, 1, 0,
+ " Version 4 Server side not active");
+ }
+#define NFS_TOTAL(member) (double)(p->member)
+#define NFS_DELTA(member) (((double)(p->member - q->member)/elapsed))
+ v2c_total = 0;
+ v2s_total = 0;
+ v3c_total = 0;
+ v3s_total = 0;
+ v4c_total = 0;
+ v4s_total = 0;
+ if (nfs_v3c_found || nfs_v3s_found) {
+ for (i = 0; i < 18; i++) { /* NFS V2 Client & Server */
+ if (show_nfs == 1)
+ mvwprintw(padnfs, 2 + i, 3, "%12s %8.1f %8.1f",
+ nfs_v2_names[i],
+ NFS_DELTA(nfs.v2c[i]),
+ NFS_DELTA(nfs.v2s[i]));
+ v2c_total += NFS_DELTA(nfs.v2c[i]);
+ v2s_total += NFS_DELTA(nfs.v2s[i]);
+ }
+ }
+ if (nfs_v3c_found || nfs_v3s_found) {
+ for (i = 0; i < 22; i++) { /* NFS V3 Client & Server */
+ if (show_nfs == 1)
+ mvwprintw(padnfs, 2 + i, 41,
+ "%12s %8.1f %8.1f", nfs_v3_names[i],
+ NFS_DELTA(nfs.v3c[i]),
+ NFS_DELTA(nfs.v3s[i]));
+ v3c_total += NFS_DELTA(nfs.v3c[i]);
+ v3s_total += NFS_DELTA(nfs.v3s[i]);
+ }
+ }
+
+ if (nfs_v4c_found) {
+ for (i = 0; i < 18; i++) { /* NFS V4 Client */
+ if (show_nfs == 2) {
+ mvwprintw(padnfs, 2 + i, 0, "%12s%7.1f",
+ nfs_v4c_names[i],
+ NFS_DELTA(nfs.v4c[i]));
+ }
+ v4c_total += NFS_DELTA(nfs.v4c[i]);
+ }
+ for (i = 18; i < 35; i++) { /* NFS V4 Client */
+ if (show_nfs == 2) {
+ mvwprintw(padnfs, 2 + i - 18, 20, "%12s%7.1f",
+ nfs_v4c_names[i],
+ NFS_DELTA(nfs.v4c[i]));
+ }
+ v4c_total += NFS_DELTA(nfs.v4c[i]);
+ }
+ }
+
+ if (nfs_v4s_found) {
+ for (i = 0; i < 18; i++) { /* NFS V4 Server */
+ if (show_nfs == 3) {
+ mvwprintw(padnfs, 2 + i, 0, "%12s%7.1f",
+ nfs_v4s_names[i],
+ NFS_DELTA(nfs.v4s[i]));
+ }
+ v4s_total += NFS_DELTA(nfs.v4s[i]);
+ }
+ for (i = 18; i < 36; i++) { /* NFS V4 Server */
+ if (show_nfs == 3) {
+ mvwprintw(padnfs, 2 + i - 18, 19, "%12s%7.1f",
+ nfs_v4s_names[i],
+ NFS_DELTA(nfs.v4s[i]));
+ }
+ v4s_total += NFS_DELTA(nfs.v4s[i]);
+ }
+ for (i = 36; i < 54 && i < nfs_v4s_names_count; i++) { /* NFS V4 Server */
+ if (show_nfs == 3) {
+ mvwprintw(padnfs, 2 + i - 36, 39, "%12s%7.1f",
+ nfs_v4s_names[i],
+ NFS_DELTA(nfs.v4s[i]));
+ }
+ v4s_total += NFS_DELTA(nfs.v4s[i]);
+ }
+ for (i = 54; i <= 70 && i < nfs_v4s_names_count; i++) { /* NFS V4 Server */
+ if (show_nfs == 3) {
+ mvwprintw(padnfs, 2 + i - 54, 59, "%12s%7.1f",
+ nfs_v4s_names[i],
+ NFS_DELTA(nfs.v4s[i]));
+ }
+ v4s_total += NFS_DELTA(nfs.v4s[i]);
+ }
+ }
+ mvwprintw(padnfs, 2 + 18, 1,
+ "--NFS-Totals->---Client----Server--");
+ /* if(nfs_v2c_found || nfs_v2s_found) */
+ mvwprintw(padnfs, 2 + 19, 1, "NFSv2 Totals->%9.1f %9.1f",
+ v2c_total, v2s_total);
+ /* if(nfs_v3c_found || nfs_v3s_found) */
+ mvwprintw(padnfs, 2 + 20, 1, "NFSv3 Totals->%9.1f %9.1f",
+ v3c_total, v3s_total);
+ /* if(nfs_v4c_found || nfs_v4s_found) */
+ mvwprintw(padnfs, 2 + 21, 1, "NFSv4 Totals->%9.1f %9.1f",
+ v4c_total, v4s_total);
+
+ DISPLAY(padnfs, 24);
+ } else {
+ if (nfs_first_time && !show_rrd) {
+ if (nfs_v2c_found) {
+ fprintf(fp, "NFSCLIV2,NFS Client v2");
+ for (i = 0; i < 18; i++)
+ fprintf(fp, ",%s", nfs_v2_names[i]);
+ fprintf(fp, "\n");
+ }
+ if (nfs_v2s_found) {
+ fprintf(fp, "NFSSVRV2,NFS Server v2");
+ for (i = 0; i < 18; i++)
+ fprintf(fp, ",%s", nfs_v2_names[i]);
+ fprintf(fp, "\n");
+ }
+
+ if (nfs_v3c_found) {
+ fprintf(fp, "NFSCLIV3,NFS Client v3");
+ for (i = 0; i < 22; i++)
+ fprintf(fp, ",%s", nfs_v3_names[i]);
+ fprintf(fp, "\n");
+ }
+ if (nfs_v3s_found) {
+ fprintf(fp, "NFSSVRV3,NFS Server v3");
+ for (i = 0; i < 22; i++)
+ fprintf(fp, ",%s", nfs_v3_names[i]);
+ fprintf(fp, "\n");
+ }
+
+ if (nfs_v4c_found) {
+ fprintf(fp, "NFSCLIV4,NFS Client v4");
+ for (i = 0; i < nfs_v4c_names_count; i++)
+ fprintf(fp, ",%s", nfs_v4c_names[i]);
+ fprintf(fp, "\n");
+ }
+ if (nfs_v4s_found) {
+ fprintf(fp, "NFSSVRV4,NFS Server v4");
+ for (i = 0; i < nfs_v4s_names_count; i++)
+ fprintf(fp, ",%s", nfs_v4s_names[i]);
+ fprintf(fp, "\n");
+ }
+ memcpy(&q->nfs, &p->nfs, sizeof(struct nfs_stat));
+ nfs_first_time = 0;
+ }
+ if (nfs_v2c_found) {
+ fprintf(fp,
+ show_rrd ? "rrdtool update nfscliv2.rrd %s" :
+ "NFSCLIV2,%s", LOOP);
+ for (i = 0; i < 18; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ (double) NFS_DELTA(nfs.v2c[i]));
+ }
+ fprintf(fp, "\n");
+ }
+ if (nfs_v2s_found) {
+ fprintf(fp,
+ show_rrd ? "rrdtool update nfsvrv2.rrd %s" :
+ "NFSSVRV2,%s", LOOP);
+ for (i = 0; i < 18; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ (double) NFS_DELTA(nfs.v2s[i]));
+ }
+ fprintf(fp, "\n");
+ }
+ if (nfs_v3c_found) {
+ fprintf(fp,
+ show_rrd ? "rrdtool update nfscliv3.rrd %s" :
+ "NFSCLIV3,%s", LOOP);
+ for (i = 0; i < 22; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ (double) NFS_DELTA(nfs.v3c[i]));
+ }
+ fprintf(fp, "\n");
+ }
+ if (nfs_v3s_found) {
+ fprintf(fp,
+ show_rrd ? "rrdtool update nfsvrv3.rrd %s" :
+ "NFSSVRV3,%s", LOOP);
+ for (i = 0; i < 22; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ (double) NFS_DELTA(nfs.v3s[i]));
+ }
+ fprintf(fp, "\n");
+ }
+
+ if (nfs_v4c_found) {
+ fprintf(fp,
+ show_rrd ? "rrdtool update nfscliv4.rrd %s" :
+ "NFSCLIV4,%s", LOOP);
+ for (i = 0; i < nfs_v4c_names_count; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ (double) NFS_DELTA(nfs.v4c[i]));
+ }
+ fprintf(fp, "\n");
+ }
+ if (nfs_v4s_found) {
+ fprintf(fp,
+ show_rrd ? "rrdtool update nfsvrv4.rrd %s" :
+ "NFSSVRV4,%s", LOOP);
+ for (i = 0; i < nfs_v4c_names_count; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ (double) NFS_DELTA(nfs.v4s[i]));
+ }
+ fprintf(fp, "\n");
+ }
+ }
+ }
+ if (show_net) {
+ if (cursed) {
+ BANNER(padnet, "Network I/O");
+#define RKB 9
+#define TKB 19
+#define PIN 30
+#define POUT 37
+#define SIN 45
+#define SOUT 52
+#define PKHEAD 60
+#define PKIN 66
+#define PKOUT 71
+/*
+ 1 2 3 4 5 6 7
+ 01234567890123456789012345678901234567890123456789012345678901234567890123456789
+ mvwprintw(padnet,1, 0, "I/F Name Recv=KB/s Trans=KB/s packin packout insize outsize Peak->Recv Trans");
+*/
+ COLOUR wattrset(padnet, COLOR_PAIR(0));
+ mvwprintw(padnet, 1, 0, "I/F Name");
+ COLOUR wattrset(padnet, COLOR_PAIR(2));
+ mvwprintw(padnet, 1, RKB, "Recv=KB/s");
+ COLOUR wattrset(padnet, COLOR_PAIR(3));
+ mvwprintw(padnet, 1, TKB, "Trans=KB/s");
+ COLOUR wattrset(padnet, COLOR_PAIR(2));
+ mvwprintw(padnet, 1, PIN, "packin");
+ COLOUR wattrset(padnet, COLOR_PAIR(3));
+ mvwprintw(padnet, 1, POUT, "packout");
+ COLOUR wattrset(padnet, COLOR_PAIR(2));
+ mvwprintw(padnet, 1, SIN, "insize");
+ COLOUR wattrset(padnet, COLOR_PAIR(3));
+ mvwprintw(padnet, 1, SOUT, "outsize");
+ COLOUR wattrset(padnet, COLOR_PAIR(0));
+ mvwprintw(padnet, 1, PKHEAD, "Peak->");
+ COLOUR wattrset(padnet, COLOR_PAIR(2));
+ mvwprintw(padnet, 1, PKIN, "Recv");
+ COLOUR wattrset(padnet, COLOR_PAIR(3));
+ mvwprintw(padnet, 1, PKOUT, "Trans");
+ COLOUR wattrset(padnet, COLOR_PAIR(0));
+ }
+ proc_net();
+ for (i = 0; i < networks; i++) {
+
+#define IFDELTA(member) ((float)( (q->ifnets[i].member > p->ifnets[i].member) ? 0 : (p->ifnets[i].member - q->ifnets[i].member)/elapsed) )
+#define IFDELTA_ZERO(member1,member2) ((IFDELTA(member1) == 0) || (IFDELTA(member2)== 0)? 0.0 : IFDELTA(member1)/IFDELTA(member2) )
+
+ if (net_read_peak[i] < IFDELTA(if_ibytes) / 1024.0)
+ net_read_peak[i] = IFDELTA(if_ibytes) / 1024.0;
+ if (net_write_peak[i] < IFDELTA(if_obytes) / 1024.0)
+ net_write_peak[i] = IFDELTA(if_obytes) / 1024.0;
+/*
+ 1 2 3 4 5 6 7
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+I/F Name Recv=KB/s Trans=KB/s packin packout insize outsize Peak->Recv Trans
+ eth3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
+ lo 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
+ eth2 0.5 0.2 8.5 0.5 64.0 314.0 53.4 24.6
+ eth1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
+ eth0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
+*/
+ if (cursed) {
+ COLOUR wattrset(padnet, COLOR_PAIR(0));
+ mvwprintw(padnet, 2 + i, 0, "%8s",
+ &p->ifnets[i].if_name[0]);
+ COLOUR wattrset(padnet, COLOR_PAIR(2));
+ mvwprintw(padnet, 2 + i, RKB, "%8.1f",
+ IFDELTA(if_ibytes) / 1024.0);
+ COLOUR wattrset(padnet, COLOR_PAIR(3));
+ mvwprintw(padnet, 2 + i, TKB, "%8.1f",
+ IFDELTA(if_obytes) / 1024.0);
+ COLOUR wattrset(padnet, COLOR_PAIR(2));
+ mvwprintw(padnet, 2 + i, PIN, "%7.1f",
+ IFDELTA(if_ipackets));
+ COLOUR wattrset(padnet, COLOR_PAIR(3));
+ mvwprintw(padnet, 2 + i, POUT, "%7.1f",
+ IFDELTA(if_opackets));
+ COLOUR wattrset(padnet, COLOR_PAIR(2));
+ mvwprintw(padnet, 2 + i, SIN, "%7.1f",
+ IFDELTA_ZERO(if_ibytes, if_ipackets));
+ COLOUR wattrset(padnet, COLOR_PAIR(3));
+ mvwprintw(padnet, 2 + i, SOUT, "%7.1f",
+ IFDELTA_ZERO(if_obytes, if_opackets));
+ COLOUR wattrset(padnet, COLOR_PAIR(2));
+ mvwprintw(padnet, 2 + i, PKIN - 4, "%8.1f",
+ net_read_peak[i]);
+ COLOUR wattrset(padnet, COLOR_PAIR(3));
+ mvwprintw(padnet, 2 + i, PKOUT, "%8.1f",
+ net_write_peak[i]);
+ }
+ }
+ DISPLAY(padnet, networks + 2);
+ if (!cursed) {
+ fprintf(fp,
+ show_rrd ? "rrdtool update net.rrd %s" : "NET,%s",
+ LOOP);
+ for (i = 0; i < networks; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ IFDELTA(if_ibytes) / 1024.0);
+ }
+ for (i = 0; i < networks; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ IFDELTA(if_obytes) / 1024.0);
+ }
+ fprintf(fp, "\n");
+ fprintf(fp,
+ show_rrd ? "rrdtool update netpacket.rrd %s" :
+ "NETPACKET,%s", LOOP);
+ for (i = 0; i < networks; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ IFDELTA(if_ipackets));
+ }
+ for (i = 0; i < networks; i++) {
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ IFDELTA(if_opackets));
+ }
+ fprintf(fp, "\n");
+ }
+ }
+ errors = 0;
+ for (i = 0; i < networks; i++) {
+ errors += p->ifnets[i].if_ierrs - q->ifnets[i].if_ierrs
+ + p->ifnets[i].if_oerrs - q->ifnets[i].if_oerrs
+ + p->ifnets[i].if_ocolls - q->ifnets[i].if_ocolls;
+ }
+ if (errors)
+ show_neterror = 3;
+ if (show_neterror) {
+ if (cursed) {
+ BANNER(padneterr, "Network Error Counters");
+ mvwprintw(padneterr, 1, 0,
+ "I/F Name iErrors iDrop iOverrun iFrame oErrors oDrop oOverrun oCarrier oColls ");
+ }
+ for (i = 0; i < networks; i++) {
+ CURSE mvwprintw(padneterr, 2 + i, 0,
+ "%8s %7lu %7lu %7lu %7lu %7lu %7lu %7lu %7lu %7lu",
+ &p->ifnets[i].if_name[0],
+ p->ifnets[i].if_ierrs,
+ p->ifnets[i].if_idrop,
+ p->ifnets[i].if_ififo,
+ p->ifnets[i].if_iframe,
+ p->ifnets[i].if_oerrs,
+ p->ifnets[i].if_odrop,
+ p->ifnets[i].if_ofifo,
+ p->ifnets[i].if_ocarrier,
+ p->ifnets[i].if_ocolls);
+
+ }
+ DISPLAY(padneterr, networks + 2);
+ if (show_neterror > 0)
+ show_neterror--;
+ }
+
+ if (show_jfs) {
+ if (cursed) {
+ BANNER(padjfs, "File Systems");
+ mvwprintw(padjfs, 1, 0, "Filesystem SizeMB FreeMB Use%% Type MountPoint");
+
+ for (k =0, j = 0; k < JFSMAX && j < jfses; k++) {
+ fs_size = 0;
+ fs_bsize = 0;
+ fs_free = 0;
+ fs_size_used = 100.0;
+ if (jfs[k].mounted == 0)
+ continue;
+ if (!strncmp(jfs[k].name, "/proc/", 6) /* sub directorys have to be fake too */
+ ||!strncmp(jfs[k].name, "/sys/", 5)
+ || !strncmp(jfs[k].name, "/dev/", 5)
+ || !strncmp(jfs[k].name, "/proc", 6) /* one more than the string to ensure the NULL */
+ ||!strncmp(jfs[k].name, "/sys", 5)
+ || !strncmp(jfs[k].name, "/dev", 5)
+ || !strncmp(jfs[i].name, "/var/lib/nfs/rpc", 16)
+ || !strncmp(jfs[k].name, "/rpc_pipe", 10)
+ ) { /* /proc gives invalid/insane values */
+ if(show_jfs_minimum) /* just skip outputing this JFS */
+ continue;
+ mvwprintw(padjfs, 2 + j, 0, "%-14s", jfs[k].name);
+ mvwprintw(padjfs, 2 + j, 27, "-");
+ mvwprintw(padjfs, 2 + j, 35, "-");
+ mvwprintw(padjfs, 2 + j, 41, "-");
+ COLOUR wattrset(padjfs, COLOR_PAIR(4));
+ mvwprintw(padjfs, 2 + j, 43, "%-8s not a real filesystem", jfs[k].type);
+ COLOUR wattrset(padjfs, COLOR_PAIR(0));
+ } else {
+ statfs_buffer.f_blocks = 0;
+ if ((ret =
+ fstatfs(jfs[k].fd,
+ &statfs_buffer)) != -1) {
+ if (statfs_buffer.f_blocks != 0) {
+ /* older Linux seemed to always report in 4KB blocks but
+ newer Linux release use the f_bsize block sizes but
+ the man statfs docs the field as the natural I/O size so
+ the blocks reported here are ambigous in size */
+ if (statfs_buffer.f_bsize == 0)
+ fs_bsize = 4.0 * 1024.0;
+ else
+ fs_bsize = statfs_buffer.f_bsize;
+ /* convert blocks to MB */
+ fs_size =
+ (float) statfs_buffer.f_blocks *
+ fs_bsize / 1024.0 / 1024.0;
+
+ /* find the best size info available f_bavail is like df reports
+ otherwise use f_bsize (this includes inode blocks) */
+ if (statfs_buffer.f_bavail == 0)
+ fs_free =
+ (float) statfs_buffer.f_bfree *
+ fs_bsize / 1024.0 / 1024.0;
+ else
+ fs_free =
+ (float) statfs_buffer.
+ f_bavail * fs_bsize / 1024.0 /
+ 1024.0;
+
+ /* this is a percentage */
+ fs_size_used =
+ (fs_size -
+ (float) statfs_buffer.f_bfree *
+ fs_bsize / 1024.0 / 1024.0) /
+ fs_size * 100.0;
+ /* try to get the same number as df using kludge */
+ /*fs_size_used += 1.0; */
+ if (fs_size_used > 100.0)
+ fs_size_used = 100.0;
+
+ if ((i = strlen(jfs[k].device)) < 20)
+ str_p = &jfs[k].device[0];
+ else {
+ str_p = &jfs[k].device[i - 20];
+ }
+ mvwprintw(padjfs, 2 + j, 0,
+ "%-20s %7.0f %7.0f %4.0f%% %-8s %s",
+ str_p, fs_size, fs_free,
+ ceil(fs_size_used),
+ jfs[k].type, jfs[k].name);
+
+ } else {
+ mvwprintw(padjfs, 2 + j, 0, "%s",
+ jfs[k].name);
+ COLOUR wattrset(padjfs, COLOR_PAIR(5));
+ mvwprintw(padjfs, 2 + j, 43,
+ "%-8s size=zero blocks!",
+ jfs[k].type);
+ COLOUR wattrset(padjfs, COLOR_PAIR(0));
+ }
+ } else {
+ mvwprintw(padjfs, 2 + j, 0, "%s",
+ jfs[k].name);
+ COLOUR wattrset(padjfs, COLOR_PAIR(3));
+ mvwprintw(padjfs, 2 + j, 43,
+ "%-8s statfs failed",
+ jfs[k].type);
+ COLOUR wattrset(padjfs, COLOR_PAIR(0));
+ }
+ }
+ j++;
+ }
+ DISPLAY(padjfs, 2 + j);
+ } else {
+ jfs_load(LOAD);
+ fprintf(fp,
+ show_rrd ? "rrdtool update jfsfile.rrd %s" :
+ "JFSFILE,%s", LOOP);
+ for (k = 0; k < jfses; k++) {
+ if (jfs[k].mounted && strncmp(jfs[k].name, "/proc", 5)
+ && strncmp(jfs[k].name, "/sys", 4)
+ && strncmp(jfs[k].name, "/dev/", 5)
+ && strncmp(jfs[k].name, "/run/", 5)
+ && strncmp(jfs[k].name, "/var/lib/nfs/rpc", 16)
+ ) { /* /proc gives invalid/insane values */
+ if (fstatfs(jfs[k].fd, &statfs_buffer) != -1) {
+ if (statfs_buffer.f_bsize == 0)
+ fs_bsize = 4.0 * 1024.0;
+ else
+ fs_bsize = statfs_buffer.f_bsize;
+ /* convert blocks to MB */
+ fs_size =
+ (float) statfs_buffer.f_blocks * fs_bsize /
+ 1024.0 / 1024.0;
+
+ /* find the best size info available f_bavail is like df reports
+ otherwise use f_bsize (this includes inode blocks) */
+ if (statfs_buffer.f_bavail == 0)
+ fs_free =
+ (float) statfs_buffer.f_bfree *
+ fs_bsize / 1024.0 / 1024.0;
+ else
+ fs_free =
+ (float) statfs_buffer.f_bavail *
+ fs_bsize / 1024.0 / 1024.0;
+
+
+
+ if (fs_size <= 0.0 || fs_bsize <= 0.0) /* some pseudo filesystems have zero size but we get a -nan result */
+ fs_size_used = 0.0;
+ else
+ fs_size_used =
+ (fs_size -
+ (float) statfs_buffer.f_bfree *
+ fs_bsize / 1024.0 / 1024.0) /
+ fs_size * 100.0;
+
+ if (fs_size_used > 100.0)
+ fs_size_used = 100.0;
+
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ fs_size_used);
+ } else
+ fprintf(fp, show_rrd ? ":U" : ",0.0");
+ }
+ }
+ fprintf(fp, "\n");
+ jfs_load(UNLOAD);
+ }
+ }
+
+ if (show_disk || show_verbose || show_diskmap || show_dgroup) {
+ proc_read(P_STAT);
+ proc_disk(elapsed);
+ }
+ if (show_diskmap) {
+ BANNER(padmap, "Disk %%Busy Map");
+ mvwprintw(padmap, 0, 18,
+ "Key: @=90 #=80 X=70 8=60 O=50 0=40 o=30 +=20 -=10 .=5 _=0%%");
+ mvwprintw(padmap, 1, 0,
+ " Disk No. 1 2 3 4 5 6 ");
+ if (disk_first_time) {
+ disk_first_time = 0;
+ mvwprintw(padmap, 2, 0,
+ "Please wait - collecting disk data");
+ } else {
+ mvwprintw(padmap, 2, 0,
+ "Disks=%-4d 0123456789012345678901234567890123456789012345678901234567890123",
+ disks);
+ mvwprintw(padmap, 3, 0, "disk 0 to 63 ");
+ for (i = 0; i < disks; i++) {
+ disk_busy = DKDELTA(dk_time) / elapsed;
+ disk_read = DKDELTA(dk_rkb) / elapsed;
+ disk_write = DKDELTA(dk_wkb) / elapsed;
+ /* ensure boundaries */
+ if (disk_busy < 0)
+ disk_busy = 0;
+ else if (disk_busy > 99)
+ disk_busy = 99;
+
+#define MAPWRAP 64
+ mvwprintw(padmap, 3 + (int) (i / MAPWRAP),
+ 13 + (i % MAPWRAP), "%c",
+ disk_busy_map_ch[(int) disk_busy]);
+ }
+ }
+ DISPLAY(padmap, 4 + disks / MAPWRAP);
+ }
+ if (show_verbose) {
+ top_disk_busy = 0.0;
+ top_disk_name = "";
+ for (i = 0, k = 0; i < disks; i++) {
+ disk_busy = DKDELTA(dk_time) / elapsed;
+ if (disk_busy > top_disk_busy) {
+ top_disk_busy = disk_busy;
+ top_disk_name = p->dk[i].dk_name;
+ }
+ }
+ if (top_disk_busy > 80.0) {
+ COLOUR wattrset(padverb, COLOR_PAIR(1));
+ mvwprintw(padverb, 3, 0, " DANGER");
+ } else if (top_disk_busy > 60.0) {
+ COLOUR wattrset(padverb, COLOR_PAIR(4));
+ mvwprintw(padverb, 3, 0, "Warning");
+ } else {
+ COLOUR wattrset(padverb, COLOR_PAIR(2));
+ mvwprintw(padverb, 3, 0, " OK");
+ }
+ COLOUR wattrset(padverb, COLOR_PAIR(0));
+ mvwprintw(padverb, 3, 8,
+ "-> Top Disk %8s %%busy %5.1f%%\t>40%%\t>60%% ",
+ top_disk_name, top_disk_busy);
+ move(x, 0);
+ }
+ if (show_disk) {
+ if (cursed) {
+ if (show_disk) {
+ BANNER(paddisk, "Disk I/O");
+ switch (disk_mode) {
+ case DISK_MODE_PARTITIONS:
+ mvwprintw(paddisk, 0, 12, "/proc/partitions");
+ break;
+ case DISK_MODE_DISKSTATS:
+ mvwprintw(paddisk, 0, 12, "/proc/diskstats");
+ break;
+ case DISK_MODE_IO:
+ mvwprintw(paddisk, 0, 12, "/proc/stat+disk_io");
+ break;
+ }
+ mvwprintw(paddisk, 0, 31, "mostly in KB/s");
+ mvwprintw(paddisk, 0, 50,
+ "Warning:contains duplicates");
+ switch (show_disk) {
+ case SHOW_DISK_STATS:
+ mvwprintw(paddisk, 1, 0, "DiskName Busy");
+ COLOUR wattrset(paddisk, COLOR_PAIR(6));
+ mvwprintw(paddisk, 1, 17, "Read");
+ COLOUR wattrset(paddisk, COLOR_PAIR(3));
+ mvwprintw(paddisk, 1, 25, "Write");
+ COLOUR wattrset(paddisk, COLOR_PAIR(0));
+ mvwprintw(paddisk, 1, 37,
+ "Xfers Size Peak%% Peak=R+W InFlight ");
+ break;
+ case SHOW_DISK_GRAPH:
+ mvwprintw(paddisk, 1, 0, "DiskName Busy ");
+ COLOUR wattrset(paddisk, COLOR_PAIR(6));
+ mvwprintw(paddisk, 1, 15, "Read ");
+ COLOUR wattrset(paddisk, COLOR_PAIR(3));
+ mvwprintw(paddisk, 1, 20, "Write");
+ COLOUR wattrset(paddisk, COLOR_PAIR(0));
+ mvwprintw(paddisk, 1, 25,
+ "KB|0 |25 |50 |75 100|");
+ break;
+ }
+ }
+ if (disk_first_time) {
+ disk_first_time = 0;
+ mvwprintw(paddisk, 2, 0,
+ "Please wait - collecting disk data");
+ } else {
+ total_disk_read = 0.0;
+ total_disk_write = 0.0;
+ total_disk_xfers = 0.0;
+ disk_mb = 0;
+ for (i = 0, k = 0; i < disks; i++) {
+ disk_read = DKDELTA(dk_rkb) / elapsed;
+ disk_write = DKDELTA(dk_wkb) / elapsed;
+ if ((show_disk == SHOW_DISK_GRAPH)
+ && (disk_read > 9999.9
+ || disk_write > 9999.9)) {
+ disk_mb = 1;
+ COLOUR wattrset(paddisk, COLOR_PAIR(1));
+ mvwprintw(paddisk, 1, 25, "MB");
+ COLOUR wattrset(paddisk, COLOR_PAIR(0));
+ break;
+ }
+ }
+ for (i = 0, k = 0; i < disks; i++) {
+ if (disk_only_mode
+ && is_dgroup_name(p->dk[i].dk_name) == 0)
+ continue;
+
+/*
+ if(p->dk[i].dk_name[0] == 'h')
+ continue;
+*/
+ disk_busy = DKDELTA(dk_time) / elapsed;
+ disk_read = DKDELTA(dk_rkb) / elapsed;
+ disk_write = DKDELTA(dk_wkb) / elapsed;
+ disk_xfers = DKDELTA(dk_xfers);
+
+ total_disk_read += disk_read;
+ total_disk_write += disk_write;
+ total_disk_xfers += disk_xfers;
+
+ if (disk_busy_peak[i] < disk_busy)
+ disk_busy_peak[i] = disk_busy;
+ if (disk_rate_peak[i] < (disk_read + disk_write))
+ disk_rate_peak[i] = disk_read + disk_write;
+ if (!show_all && disk_busy < 1)
+ continue;
+
+ if (strlen(p->dk[i].dk_name) > 8)
+ str_p =
+ &p->dk[i].
+ dk_name[strlen(p->dk[i].dk_name) - 8];
+ else
+ str_p = &p->dk[i].dk_name[0];
+
+ if (show_disk == SHOW_DISK_STATS) {
+ /* output disks stats */
+ mvwprintw(paddisk, 2 + k, 0, "%-8s%4.0f%%",
+ str_p, disk_busy);
+ COLOUR wattrset(paddisk, COLOR_PAIR(6));
+ mvwprintw(paddisk, 2 + k, 13, "%9.1f",
+ disk_read);
+ COLOUR wattrset(paddisk, COLOR_PAIR(3));
+ mvwprintw(paddisk, 2 + k, 22, "%9.1fKB/s",
+ disk_write);
+ COLOUR wattrset(paddisk, COLOR_PAIR(5));
+ mvwprintw(paddisk, 2 + k, 36, "%6.1f", disk_xfers / elapsed);
+ COLOUR wattrset(paddisk, COLOR_PAIR(4));
+ mvwprintw(paddisk, 2 + k, 43, "%5.1fKB",
+ disk_xfers == 0.0 ? 0.0 : (DKDELTA(dk_rkb) + DKDELTA(dk_wkb)) / disk_xfers);
+ COLOUR wattrset(paddisk, COLOR_PAIR(2));
+ mvwprintw(paddisk, 2 + k, 52,
+ "%3.0f%% %9.1fKB/s",
+ disk_busy_peak[i],
+ disk_rate_peak[i]);
+ COLOUR wattrset(paddisk, COLOR_PAIR(3));
+ mvwprintw(paddisk, 2 + k, 70, "%3d", p->dk[i].dk_inflight);
+ COLOUR wattrset(paddisk, COLOR_PAIR(0));
+ k++;
+ }
+ if (show_disk == SHOW_DISK_GRAPH) {
+ /* output disk bar graphs */
+ if (disk_mb) {
+ disk_read_tmp = disk_read / 1024.0;
+ disk_write_tmp = disk_write / 1024.0;
+ } else {
+ disk_read_tmp = disk_read;
+ disk_write_tmp = disk_write;
+ }
+
+ mvwprintw(paddisk, 2 + k, 0, "%-8s %3.0f%%",
+ str_p, disk_busy);
+ COLOUR wattrset(paddisk, COLOR_PAIR(6));
+ mvwprintw(paddisk, 2 + k, 13, "%7.1f",
+ disk_read_tmp);
+ COLOUR wattrset(paddisk, COLOR_PAIR(3));
+ mvwprintw(paddisk, 2 + k, 20, "%7.1f",
+ disk_write_tmp);
+ COLOUR wattrset(paddisk, COLOR_PAIR(0));
+
+ mvwprintw(paddisk, 2 + k, 27,
+ "| ");
+ wmove(paddisk, 2 + k, 28);
+ if (disk_busy > 100)
+ disk_busy = 100;
+ if (disk_busy > 0.0
+ && (disk_write + disk_read) > 0.1) {
+ /* 50 columns in the disk graph area so divide % by two */
+ readers =
+ disk_busy * disk_read / (disk_write +
+ disk_read) /
+ 2;
+ writers =
+ disk_busy * disk_write / (disk_write +
+ disk_read) /
+ 2;
+ if (readers + writers > 50) {
+ readers = 0;
+ writers = 0;
+ }
+ /* don't go beyond row 78 i.e. j = 28 + 50 */
+ for (j = 0; j < readers && j < 50; j++) {
+ COLOUR wattrset(paddisk,
+ COLOR_PAIR(12));
+ wprintw(paddisk, "R");
+ COLOUR wattrset(paddisk,
+ COLOR_PAIR(0));
+ }
+ for (; j < readers + writers && j < 50;
+ j++) {
+ COLOUR wattrset(paddisk,
+ COLOR_PAIR(11));
+ wprintw(paddisk, "W");
+ COLOUR wattrset(paddisk,
+ COLOR_PAIR(0));
+ }
+ for (j = disk_busy; j < 50; j++)
+ wprintw(paddisk, " ");
+ } else {
+ for (j = 0; j < 50; j++)
+ wprintw(paddisk, " ");
+ if (p->dk[i].dk_time == 0.0)
+ mvwprintw(paddisk, 2 + k, 27,
+ "| disk busy not available");
+ }
+ if (disk_busy_peak[i] > 100)
+ disk_busy_peak[i] = 100;
+
+ mvwprintw(paddisk, 2 + i, 77, "|");
+ /* check rounding has not got the peak ">" over the 100% */
+ j = 28 + (int) (disk_busy_peak[i] / 2);
+ if (j > 77)
+ j = 77;
+ mvwprintw(paddisk, 2 + i, j, ">");
+ k++;
+ }
+ }
+ mvwprintw(paddisk, 2 + k, 0,
+ "Totals Read-MB/s=%-8.1f Writes-MB/s=%-8.1f Transfers/sec=%-8.1f",
+ total_disk_read / 1024.0,
+ total_disk_write / 1024.0,
+ total_disk_xfers / elapsed);
+
+ }
+ DISPLAY(paddisk, 3 + k);
+ } else {
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp,
+ show_rrd ?
+ "%srrdtool update diskbusy%s.rrd %s" :
+ "%sDISKBUSY%s,%s", i == 0 ? "" : "\n",
+ dskgrp(i), LOOP);
+ /* check percentage is correct */
+ ftmp = DKDELTA(dk_time) / elapsed;
+ if (ftmp > 100.0 || ftmp < 0.0)
+ fprintf(fp, show_rrd ? ":U" : ",101.00");
+ else
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ DKDELTA(dk_time) / elapsed);
+ }
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp,
+ show_rrd ?
+ "\nrrdtool update diskread%s.rrd %s" :
+ "\nDISKREAD%s,%s", dskgrp(i), LOOP);
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ DKDELTA(dk_rkb) / elapsed);
+ }
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp,
+ show_rrd ?
+ "\nrrdtool update diskwrite%s.rrd %s" :
+ "\nDISKWRITE%s,%s", dskgrp(i), LOOP);
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ DKDELTA(dk_wkb) / elapsed);
+ }
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp,
+ show_rrd ?
+ "\nrrdtool update diskxfer%s.rrd %s" :
+ "\nDISKXFER%s,%s", dskgrp(i), LOOP);
+ disk_xfers = DKDELTA(dk_xfers);
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ disk_xfers / elapsed);
+ }
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i))
+ fprintf(fp,
+ show_rrd ?
+ "\nrrdtool update diskbsize%s.rrd %s" :
+ "\nDISKBSIZE%s,%s", dskgrp(i), LOOP);
+ disk_xfers = DKDELTA(dk_xfers);
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ disk_xfers == 0.0 ? 0.0 :
+ (DKDELTA(dk_rkb) +
+ DKDELTA(dk_wkb)) / disk_xfers);
+ }
+
+ if (extended_disk == 1 && disk_mode == DISK_MODE_DISKSTATS) {
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i)) {
+ fprintf(fp, "\nDISKREADS%s,%s", dskgrp(i),
+ LOOP);
+ }
+ disk_read = DKDELTA(dk_reads);
+ fprintf(fp, ",%.1f", disk_read / elapsed);
+ }
+
+ for (i = 0; i < disks; i++) {
+ if (NEWDISKGROUP(i)) {
+ fprintf(fp, "\nDISKWRITES%s,%s", dskgrp(i),
+ LOOP);
+ }
+ disk_write = DKDELTA(dk_writes);
+ fprintf(fp, ",%.1f", disk_write / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ }
+ }
+ if ((show_dgroup || (!cursed && dgroup_loaded))) {
+ if (cursed) {
+ BANNER(paddg, "Disk Group I/O");
+ if (dgroup_loaded != 2 || dgroup_total_disks == 0) {
+ mvwprintw(paddg, 1, 1,
+ "No Disk Groups found use -g groupfile when starting nmon");
+ } else if (disk_first_time) {
+ disk_first_time = 0;
+ mvwprintw(paddg, 1, 1,
+ "Please wait - collecting disk data");
+ } else {
+ mvwprintw(paddg, 1, 1,
+ "Name Disks AvgBusy | TotalMB/s xfers/s BlockSizeKB");
+ COLOUR wattrset(paddg, COLOR_PAIR(6));
+ mvwprintw(paddg, 1, 29, "Read-KB/s");
+ COLOUR wattrset(paddg, COLOR_PAIR(3));
+ mvwprintw(paddg, 1, 39, "Write");
+ COLOUR wattrset(paddg, COLOR_PAIR(0));
+ total_busy = 0.0;
+ total_rbytes = 0.0;
+ total_wbytes = 0.0;
+ total_xfers = 0.0;
+ for (k = n = 0; k < dgroup_total_groups; k++) {
+/*
+ if (dgroup_name[k] == 0 )
+ continue;
+*/
+ disk_busy = 0.0;
+ disk_read = 0.0;
+ disk_write = 0.0;
+ disk_xfers = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_busy += DKDELTA(dk_time) / elapsed;
+/*
+ disk_read += DKDELTA(dk_reads) * p->dk[i].dk_bsize / 1024.0 /elapsed;
+ disk_write += DKDELTA(dk_writes) * p->dk[i].dk_bsize / 1024.0 /elapsed;
+*/
+ disk_read += DKDELTA(dk_rkb) / elapsed;
+ disk_write += DKDELTA(dk_wkb) / elapsed;
+ disk_xfers += DKDELTA(dk_xfers) / elapsed;
+ }
+ }
+ if (dgroup_disks[k] == 0)
+ disk_busy = 0.0;
+ else
+ disk_busy = disk_busy / dgroup_disks[k];
+ total_busy += disk_busy;
+ total_rbytes += disk_read;
+ total_wbytes += disk_write;
+ total_xfers += disk_xfers;
+/* if (!show_all && (disk_read < 1.0 && disk_write < 1.0))
+ continue;
+*/
+ if ((disk_read + disk_write) == 0
+ || disk_xfers == 0)
+ disk_size = 0.0;
+ else
+ disk_size =
+ ((float) disk_read +
+ (float) disk_write) / (float) disk_xfers;
+ mvwprintw(paddg, n + 2, 1, "%-14s %3d %5.1f%% | %6.1f %9.1f %6.1f ", dgroup_name[k], dgroup_disks[k], disk_busy, (disk_read + disk_write) / 1024, /* in MB */
+ disk_xfers, disk_size);
+ COLOUR wattrset(paddg, COLOR_PAIR(6));
+ mvwprintw(paddg, n + 2, 29, "%9.1f", disk_read);
+ COLOUR wattrset(paddg, COLOR_PAIR(3));
+ mvwprintw(paddg, n + 2, 39, "%-9.1f", disk_write);
+ COLOUR wattrset(paddg, COLOR_PAIR(0));
+ n++;
+ }
+ mvwprintw(paddg, n + 2, 1, "Groups=%2d TOTALS %3d %5.1f%% %9.1f|%-9.1f %6.1f %9.1f", n, dgroup_total_disks, total_busy / dgroup_total_disks, total_rbytes, total_wbytes, (((double) total_rbytes + (double) total_wbytes)) / 1024, /* in MB */
+ total_xfers);
+ }
+ DISPLAY(paddg, 3 + dgroup_total_groups);
+ } else {
+ if (dgroup_loaded == 2) {
+ fprintf(fp,
+ show_rrd ? "rrdtool update dgbusy.rdd %s" :
+ "DGBUSY,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total +=
+ DKDELTA(dk_time) / elapsed;
+ }
+ }
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ (float) (disk_total /
+ dgroup_disks[k]));
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp,
+ show_rrd ? "rrdtool update dgread.rdd %s" :
+ "DGREAD,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+/*
+ disk_total += DKDELTA(dk_reads) * p->dk[i].dk_bsize / 1024.0;
+*/
+ disk_total += DKDELTA(dk_rkb);
+ }
+ }
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp,
+ show_rrd ? "rrdtool update dgwrite.rdd %s" :
+ "DGWRITE,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+/*
+ disk_total += DKDELTA(dk_writes) * p->dk[i].dk_bsize / 1024.0;
+*/
+ disk_total += DKDELTA(dk_wkb);
+ }
+ }
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp,
+ show_rrd ? "rrdtool update dgbsize.rdd %s" :
+ "DGSIZE,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_write = 0.0;
+ disk_xfers = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+/*
+ disk_write += (DKDELTA(dk_reads) + DKDELTA(dk_writes) ) * p->dk[i].dk_bsize / 1024.0;
+*/
+ disk_write +=
+ (DKDELTA(dk_rkb) +
+ DKDELTA(dk_wkb));
+ disk_xfers += DKDELTA(dk_xfers);
+ }
+ }
+ if (disk_write == 0.0 || disk_xfers == 0.0)
+ disk_size = 0.0;
+ else
+ disk_size = disk_write / disk_xfers;
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ disk_size);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp,
+ show_rrd ? "rrdtool update dgxfer.rdd %s" :
+ "DGXFER,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total += DKDELTA(dk_xfers);
+ }
+ }
+ fprintf(fp, show_rrd ? ":%.1f" : ",%.1f",
+ disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+
+ if (extended_disk == 1
+ && disk_mode == DISK_MODE_DISKSTATS) {
+ fprintf(fp, "DGREADS,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total += DKDELTA(dk_reads);
+ }
+ }
+ fprintf(fp, ",%.1f", disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGREADMERGE,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total += DKDELTA(dk_rmerge);
+ }
+ }
+ fprintf(fp, ",%.1f", disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGREADSERV,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total += DKDELTA(dk_rmsec);
+ }
+ }
+ fprintf(fp, ",%.1f", disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGWRITES,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total += DKDELTA(dk_writes);
+ }
+ }
+ fprintf(fp, ",%.1f", disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGWRITEMERGE,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total += DKDELTA(dk_wmerge);
+ }
+ }
+ fprintf(fp, ",%.1f", disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGWRITESERV,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total += DKDELTA(dk_wmsec);
+ }
+ }
+ fprintf(fp, ",%.1f", disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGINFLIGHT,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total += p->dk[i].dk_inflight;
+ }
+ }
+ fprintf(fp, ",%.1f", disk_total);
+ }
+ }
+ fprintf(fp, "\n");
+ fprintf(fp, "DGBACKLOG,%s", LOOP);
+ for (k = 0; k < dgroup_total_groups; k++) {
+ if (dgroup_name[k] != 0) {
+ disk_total = 0.0;
+ for (j = 0; j < dgroup_disks[k]; j++) {
+ i = dgroup_data[k * DGROUPITEMS + j];
+ if (i != -1) {
+ disk_total += DKDELTA(dk_backlog);
+ }
+ }
+ fprintf(fp, ",%.1f", disk_total / elapsed);
+ }
+ }
+ fprintf(fp, "\n");
+ } /* if( extended_disk == 1 && disk_mode == DISK_MODE_DISKSTATS */
+ } /* if (dgroup_loaded == 2) */
+ } /* else from if(cursed) */
+ }
+ /* if ((show_dgroup || (!cursed && dgroup_loaded))) */
+ if (show_top) {
+ wmove(padtop, 1, 1);
+ wclrtobot(padtop);
+ /* Get the details of the running processes */
+ skipped = 0;
+ current_procs = getprocs(0);
+ if (current_procs > p->proc_records) {
+ adjusted_procs = current_procs + 128; /* allow for growth in the number of processes in the mean time */
+ p->procs = REALLOC(p->procs, sizeof(struct procsinfo) * adjusted_procs);
+ p->proc_records = adjusted_procs;
+ }
+
+ p->processes = getprocs(p->proc_records);
+
+ if (topper_size < p->processes) {
+ topper = REALLOC(topper, sizeof(struct topper) * (p->processes +1));/* add one to avoid overrun */
+ topper_size = p->processes;
+ }
+ /* Sort the processes by CPU utilisation */
+ for (i = 0, max_sorted = 0; i < p->processes; i++) {
+ /* move forward in the previous array to find a match */
+ for (j = 0; j < q->processes; j++) {
+ if (p->procs[i].pi_pid == q->procs[j].pi_pid) { /* found a match */
+ topper[max_sorted].index = i;
+ topper[max_sorted].other = j;
+ topper[max_sorted].time =
+ TIMEDELTA(pi_utime, i, j) + TIMEDELTA(pi_stime, i, j);
+ topper[max_sorted].size =
+ p->procs[i].statm_resident;
+ if (isroot && cursed) /* we don't sort on this in data capture */
+ topper[max_sorted].io =
+ IODELTA(read_io, i, j) + IODELTA(write_io, i, j);
+
+ max_sorted++;
+ break;
+ }
+ }
+ }
+ switch (show_topmode) {
+ default:
+ case 3:
+ qsort((void *) &topper[0], max_sorted,
+ sizeof(struct topper), &cpu_compare);
+ break;
+ case 4:
+ qsort((void *) &topper[0], max_sorted,
+ sizeof(struct topper), &size_compare);
+ break;
+ case 5:
+ qsort((void *) &topper[0], max_sorted,
+ sizeof(struct topper), &disk_compare);
+ break;
+ }
+ CURSE BANNER(padtop, "Top Processes");
+ if (isroot) {
+ formatstring = "Procs=%d-mode=%d-1=Base 3=Perf 4=Size 5=I/O u=Args";
+ } else {
+ formatstring = "Procs=%d-mode=%d-1=Base 3=Perf 4=Size 5=I/O[RootOnly] u=Args";
+ }
+ CURSE mvwprintw(padtop, 0, 15, formatstring, p->processes, show_topmode);
+ if (cursed && top_first_time) {
+ top_first_time = 0;
+ mvwprintw(padtop, 1, 1,
+ "Please wait - information being collected");
+ } else {
+ switch (show_topmode) {
+ case 1: /* Basic */
+ if(cursed) {
+ mvwprintw(padtop, 1, 1,
+ " PID PPID Pgrp Nice Prior Status Proc-Flag Command");
+ for (j = 0; j < max_sorted; j++) {
+ i = topper[j].index;
+ if (p->procs[i].pi_pgrp == p->procs[i].pi_pid)
+ strcpy(pgrp, "none");
+ else
+ snprintf(&pgrp[0], 32, "%d", p->procs[i].pi_pgrp);
+ /* skip over processes with 0 CPU */
+ if (!show_all
+ && (topper[j].time / elapsed <
+ ignore_procdisk_threshold) && !cmdfound)
+ break;
+ if (x + j + 2 - skipped > LINES + 2) /* +2 to for safety :-) */
+ break;
+ mvwprintw(padtop, j + 2 - skipped, 1, "%7d %7d %6s",
+ p->procs[i].pi_pid,
+ p->procs[i].pi_ppid,
+ pgrp);
+ COLOUR wattrset(padtop, COLOR_PAIR(5));
+ mvwprintw(padtop, j + 2 - skipped, 24, "%4d %4d",
+ p->procs[i].pi_nice,
+ p->procs[i].pi_pri);
+ if (topper[j].time * 100 / elapsed) {
+ COLOUR wattrset(padtop, COLOR_PAIR(1));
+ } else {
+ COLOUR wattrset(padtop, COLOR_PAIR(2));
+ }
+ mvwprintw(padtop, j + 2 - skipped, 35, "%9s",
+ (topper[j].time * 100 / elapsed) ? "Running " : get_state(p->procs[i].pi_state));
+
+ COLOUR wattrset(padtop, COLOR_PAIR(6));
+ mvwprintw(padtop, j + 2 - skipped, 45, "0x%08x",
+ p->procs[i].pi_flags);
+ COLOUR wattrset(padtop, COLOR_PAIR(1));
+ mvwprintw(padtop, j + 2 - skipped, 54, "%1s",
+ (p->procs[i].pi_tty_nr ? "F" : " "));
+ COLOUR wattrset(padtop, COLOR_PAIR(3));
+ mvwprintw(padtop, j + 2 - skipped, 57, "%-32s", p->procs[i].pi_comm);
+ COLOUR wattrset(padtop, COLOR_PAIR(0));
+ }
+ }
+ break;
+ case 3:
+ case 4:
+ case 5:
+
+ if (show_args == ARGS_ONLY) {
+ formatstring =
+ " PID %%CPU ResSize Command ";
+ } else if (COLS > 119) {
+ if (show_topmode == 5)
+ formatstring =
+ " PID %%CPU Size Res Res Res Res Shared StorageKB Command";
+ else
+ formatstring =
+ " PID %%CPU Size Res Res Res Res Shared Faults Faults Command";
+ } else {
+ if (show_topmode == 5)
+ formatstring =
+ " PID %%CPU Size Res Res Res Res Shared StorageKB Command";
+ else
+ formatstring =
+ " PID %%CPU Size Res Res Res Res Shared Faults Command";
+ }
+ CURSE mvwprintw(padtop, 1, y, formatstring);
+
+ if (show_args == ARGS_ONLY) {
+ formatstring =
+ " Used KB ";
+ } else if (COLS > 119) {
+ if (show_topmode == 5)
+ formatstring =
+ " Used KB Set Text Data Lib KB Read Write";
+ else
+ formatstring =
+ " Used KB Set Text Data Lib KB Min Maj";
+ } else {
+ if (show_topmode == 5)
+ formatstring =
+ " Used KB Set Text Data Lib KB ReadWrite ";
+ else
+ formatstring =
+ " Used KB Set Text Data Lib KB Min Maj ";
+ }
+ CURSE mvwprintw(padtop, 2, 1, formatstring);
+ for (j = 0; j < max_sorted; j++) {
+ i = topper[j].index;
+ if (!show_all) {
+ /* skip processes with zero CPU/io */
+ if (show_topmode == 3
+ && (topper[j].time / elapsed) <
+ ignore_procdisk_threshold && !cmdfound)
+ break;
+ if (show_topmode == 5
+ && (topper[j].io < ignore_io_threshold
+ && !cmdfound))
+ break;
+ }
+ if (cursed) {
+ if (x + j + 3 - skipped > LINES + 2) /* +2 to for safety :-) XYZXYZ */
+ break;
+ if (cmdfound && !cmdcheck(p->procs[i].pi_comm)) {
+ skipped++;
+ continue;
+ }
+ if (show_args == ARGS_ONLY) {
+
+ mvwprintw(padtop, j + 3 - skipped, 1, "%7d", p->procs[i].pi_pid);
+ COLOUR wattrset(padtop, COLOR_PAIR(1));
+ mvwprintw(padtop, j + 3 - skipped, 9, "%5.1f", topper[j].time / elapsed);
+ COLOUR wattrset(padtop, COLOR_PAIR(2));
+ mvwprintw(padtop, j + 3 - skipped, 16, "%7lu", p->procs[i].statm_resident * pagesize / 1024); /* in KB */
+ COLOUR wattrset(padtop, COLOR_PAIR(3));
+ strncpy( truncated_command, args_lookup(p->procs[i].pi_pid, p->procs[i].pi_comm), 256);
+ truncated_command[255] = 0; /* worst longest case */
+ truncated_command[COLS - 24 - 2] = 0;
+
+ mvwprintw(padtop, j + 3 - skipped, 24, "%-120s", truncated_command);
+ COLOUR wattrset(padtop, COLOR_PAIR(0));
+ } else {
+ topsize = p->procs[i].statm_size * pagesize / 1024UL; /* in KB */
+ topsize_ch = ' ';
+ toprset = p->procs[i].statm_resident * pagesize / 1024UL; /* in KB */
+ toprset_ch = ' ';
+ toptrs = p->procs[i].statm_trs * pagesize / 1024UL; /* in KB */
+ toptrs_ch = ' ';
+ topdrs = p->procs[i].statm_drs * pagesize / 1024UL; /* in KB */
+ topdrs_ch = ' ';
+ toplrs = p->procs[i].statm_lrs * pagesize / 1024UL; /* in KB */
+ toplrs_ch = ' ';
+ topshare = p->procs[i].statm_share * pagesize / 1024UL; /* in KB */
+ topshare_ch = ' ';
+ toprio = (int) (COUNTDELTA(read_io) / elapsed / 1024);
+ toprio_ch = ' ';
+ topwio = (int) (COUNTDELTA(write_io) / elapsed / 1024);
+ topwio_ch = ' ';
+/*
+ if (COLS > 119)
+ formatstring = "%8d %8.1f %9lu%c%9lu%c%9lu%c%9lu%c%9lu%c%9lu%c%8d%c%8d%c%-32s";
+ else {
+ formatstring = "%7d %5.1f %5lu%c%5lu%c%5lu%c%5lu%c%5lu%c%5lu%c%4d%c%4d%c%-32s";
+*/
+ if (COLS < 119) {
+ if(topsize > 99999UL) {
+ topsize = topsize / 1024UL;
+ topsize_ch = 'm';
+ }
+ if(toprset > 99999UL) {
+ toprset = toprset / 1024UL;
+ toprset_ch = 'm';
+ }
+ if(toptrs > 99999UL) {
+ toptrs = toptrs / 1024UL;
+ toptrs_ch = 'm';
+ }
+ if(topdrs > 99999UL) {
+ topdrs = topdrs / 1024UL;
+ topdrs_ch = 'm';
+ }
+ if(toptrs > 99999UL) {
+ toplrs = toplrs / 1024UL;
+ toplrs_ch = 'm';
+ }
+ if(toptrs > 99999UL) {
+ topshare = topshare / 1024UL;
+ topshare_ch = 'm';
+ }
+ if(toprio > 99999UL) {
+ toprio = toprio / 1024UL;
+ topwio_ch = 'm';
+ }
+ if(topwio > 99999UL) {
+ topwio = topwio / 1024UL;
+ topwio_ch = 'm';
+ }
+ /* now repeat incase we get many tens of GB sizes */
+ if(topsize > 99999UL) {
+ topsize = topsize / 1024UL;
+ topsize_ch = 'g';
+ }
+ if(toprset > 99999UL) {
+ toprset = toprset / 1024UL;
+ toprset_ch = 'g';
+ }
+ if(toptrs > 99999UL) {
+ toptrs = toptrs / 1024UL;
+ toptrs_ch = 'g';
+ }
+ if(topdrs > 99999UL) {
+ topdrs = topdrs / 1024UL;
+ topdrs_ch = 'g';
+ }
+ if(toptrs > 99999UL) {
+ toplrs = toplrs / 1024UL;
+ toplrs_ch = 'g';
+ }
+ if(toptrs > 99999UL) {
+ topshare = topshare / 1024UL;
+ topshare_ch = 'g';
+ }
+ if(toprio > 99999UL) {
+ toprio = toprio / 1024UL;
+ topwio_ch = 'g';
+ }
+ if(topwio > 99999UL) {
+ topwio = topwio / 1024UL;
+ topwio_ch = 'g';
+ }
+ }
+
+ mvwprintw(padtop, j + 3 - skipped, 1, (COLS>119)?"%8d":"%7d", p->procs[i].pi_pid);
+
+ COLOUR wattrset(padtop, COLOR_PAIR(1));
+ mvwprintw(padtop, j + 3 - skipped, (COLS >119)?10:9, (COLS>119)?"%8.1f":"%5.1f", topper[j].time / elapsed);
+
+ COLOUR wattrset(padtop, COLOR_PAIR(2));
+ mvwprintw(padtop, j + 3 - skipped, (COLS >119)?19:15,
+ (COLS>119)?"%9lu%c%9lu%c%9lu%c%9lu%c%9lu%c%9lu%c":"%5lu%c%5lu%c%5lu%c%5lu%c%5lu%c%5lu%c",
+ topsize, topsize_ch,
+ toprset, toprset_ch,
+ toptrs, toptrs_ch,
+ topdrs, topdrs_ch,
+ toplrs, toplrs_ch,
+ topshare, topshare_ch);
+
+ if(show_topmode == 5) {
+ COLOUR wattrset(padtop, COLOR_PAIR(5));
+ mvwprintw(padtop, j + 3 - skipped, (COLS >119)?79:51, (COLS>119)?"%8d%c%8d%c":"%4d%c%4d%c",
+ (int)toprio, toprio_ch, (int)topwio, topwio_ch);
+ } else {
+ COLOUR wattrset(padtop, COLOR_PAIR(6));
+ mvwprintw(padtop, j + 3 - skipped, (COLS >119)?79:51, (COLS>119)?"%8d %8d":"%4d %4d",
+ (int) (COUNTDELTA(pi_minflt) / elapsed), (int) (COUNTDELTA(pi_majflt) / elapsed) );
+ }
+ COLOUR wattrset(padtop, COLOR_PAIR(3));
+ mvwprintw(padtop, j + 3 - skipped, (COLS >119)?97:61, "%-32s", p->procs[i].pi_comm);
+ COLOUR wattrset(padtop, COLOR_PAIR(0));
+ }
+ } else {
+ if ((cmdfound && cmdcheck(p->procs[i].pi_comm))
+ || (!cmdfound
+ && ((topper[j].time / elapsed) >
+ ignore_procdisk_threshold))) {
+#ifdef PRE_KERNEL_2_6_18
+ fprintf(fp,
+ "TOP,%07d,%s,%.2f,%.2f,%.2f,%lu,%lu,%lu,%lu,%lu,%d,%d,%s\n",
+#else
+ fprintf(fp,
+ "TOP,%07d,%s,%.2f,%.2f,%.2f,%lu,%lu,%lu,%lu,%lu,%d,%d,%s,%ld,%llu\n",
+#endif
+ /* 1 */ p->procs[i].pi_pid,
+ /* 2 */ LOOP,
+ /* 3 */ topper[j].time / elapsed,
+ /* 4 */ TIMEDELTA(pi_utime, i, topper[j]. other) / elapsed,
+ /* 5 */ TIMEDELTA(pi_stime, i, topper[j]. other) / elapsed,
+ /* 6 */ p->procs[i].statm_size * pagesize / 1024UL, /* in KB */
+ /* 7 */ p->procs[i].statm_resident * pagesize / 1024UL, /* in KB */
+ /* 8 */ p->procs[i].statm_trs * pagesize / 1024UL, /* in KB */
+ /* 9 */ p->procs[i].statm_drs * pagesize / 1024UL, /* in KB */
+ /* 10 */ p->procs[i].statm_share * pagesize / 1024UL, /* in KB */
+ /* 11 */ (int) (COUNTDELTA(pi_minflt) / elapsed),
+ /* 12 */ (int) (COUNTDELTA(pi_majflt) / elapsed),
+ /* 13 */ p->procs[i].pi_comm
+#ifdef PRE_KERNEL_2_6_18
+ );
+#else
+ ,
+ p->procs[i].pi_num_threads, COUNTDELTA(pi_delayacct_blkio_ticks)
+ );
+#endif
+
+ if (show_args)
+ args_output(p->procs[i].pi_pid, loop,
+ p->procs[i].pi_comm);
+
+ } else
+ skipped++;
+ }
+ }
+ break;
+ }
+ }
+ DISPLAY(padtop, 3 + j);
+ }
+
+ if (cursed) {
+ if (show_verbose) {
+ y = x;
+ x = 1;
+ DISPLAY(padverb, 4);
+ x = y;
+ }
+ /* underline the end of the stats area border */
+ if (x < LINES - 2)
+ mvwhline(stdscr, x, 1, ACS_HLINE, COLS - 2);
+
+ wmove(stdscr, 0, 0);
+ wrefresh(stdscr);
+ doupdate();
+
+ for (i = 0; i < seconds; i++) {
+ sleep(1);
+ if (checkinput())
+ break;
+ }
+ if (x < LINES - 2)
+ mvwhline(stdscr, x, 1, ' ', COLS - 2);
+ if (first_key_pressed == 0) {
+ first_key_pressed = 1;
+ wmove(stdscr, 0, 0);
+ wclear(stdscr);
+ wmove(stdscr, 0, 0);
+ wclrtobot(stdscr);
+ wrefresh(stdscr);
+ doupdate();
+ }
+
+ } else {
+ fflush(NULL);
+
+ gettimeofday(&nmon_tv, 0);
+ nmon_end_time =
+ (double) nmon_tv.tv_sec +
+ (double) nmon_tv.tv_usec * 1.0e-6;
+ if (nmon_run_time < 0.0) {
+ nmon_start_time = nmon_end_time;
+ nmon_run_time = 0.0;
+ }
+ nmon_run_time += (nmon_end_time - nmon_start_time);
+ if (nmon_run_time < 1.0) {
+ secs = seconds; /* sleep for the requested number of seconds */
+ } else {
+ seconds_over = (int) nmon_run_time; /* reduce the sleep time by whole number of seconds */
+ secs = seconds - seconds_over;
+ nmon_run_time -= (double) seconds_over;
+ }
+ if (secs < 1) /* sanity check in case CPUs are flat out and nmon taking far to long to complete */
+ secs = 1;
+
+ redo:
+ errno = 0;
+ ret = sleep(secs);
+ if ((ret != 0 || errno != 0) && loop != maxloops) {
+ fprintf(fp,
+ "ERROR,%s, sleep interrupted, sleep(%d seconds), return value=%d",
+ LOOP, secs, ret);
+ fprintf(fp, ", errno=%d\n", errno);
+ secs = ret;
+ goto redo;
+ }
+ gettimeofday(&nmon_tv, 0);
+ nmon_start_time =
+ (double) nmon_tv.tv_sec +
+ (double) nmon_tv.tv_usec * 1.0e-6;
+ }
+
+ switcher();
+
+ if (loop >= maxloops) {
+ CURSE endwin();
+ if (nmon_end) {
+ child_start(CHLD_END, nmon_end, time_stamp_type, loop,
+ timer);
+ /* Give the end - processing some time - 5s for now */
+ sleep(5);
+ }
+
+ fflush(NULL);
+ exit(0);
+ }
+ }
+}
diff --git a/source/SlackBuild/nmon/nmon.SlackBuild b/source/SlackBuild/nmon/nmon.SlackBuild
new file mode 100755
index 00000000..6df43aa3
--- /dev/null
+++ b/source/SlackBuild/nmon/nmon.SlackBuild
@@ -0,0 +1,88 @@
+#!/bin/sh
+
+# Slackware build script for nmon
+
+# Copyright 2014 Georgi Kolev, Bulgaria
+# All rights reserved.
+#
+# Redistribution and use of this script, with or without modification, is
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of this script must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+PRGNAM=nmon
+VERSION=${VERSION:-16m}
+BUILD=${BUILD:-1}
+TAG=${TAG:-_SBo}
+
+if [ -z "$ARCH" ]; then
+ case "$( uname -m )" in
+ i?86) ARCH=i486 ;;
+ arm*) ARCH=arm ;;
+ *) ARCH=$( uname -m ) ;;
+ esac
+fi
+
+CWD=$(pwd)
+TMP=${TMP:-/tmp/SBo}
+PKG=$TMP/package-$PRGNAM
+OUTPUT=${OUTPUT:-/tmp}
+
+if [ "$ARCH" = "i486" ]; then
+ SLKCFLAGS="-g -O2 -march=i486 -mtune=i686 -D JFS -D GETUSER -Wall -D LARGEMEM -lncurses -g -D X86"
+ LIBDIRSUFFIX=""
+elif [ "$ARCH" = "i686" ]; then
+ SLKCFLAGS="-g -O2 -march=i686 -mtune=i686 -D JFS -D GETUSER -Wall -D LARGEMEM -lncurses -g -D X86"
+ LIBDIRSUFFIX=""
+elif [ "$ARCH" = "x86_64" ]; then
+ SLKCFLAGS="-g -O3 -Wall -lncurses -lm -D X86"
+ LIBDIRSUFFIX="64"
+else
+ SLKCFLAGS="-g -O2 -D JFS -D GETUSER -Wall -D LARGEMEM -lncurses -g -D X86"
+ LIBDIRSUFFIX=""
+fi
+
+set -eux
+
+rm -rf $PKG
+mkdir -p $TMP $PKG $OUTPUT
+cd $TMP
+rm -rf $PRGNAM
+mkdir -p $PRGNAM
+cp $CWD/lmon.c $PRGNAM
+cd $TMP/$PRGNAM
+chown -R root:root .
+find -L . \
+ \( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
+ -o -perm 511 \) -exec chmod 755 {} \; -o \
+ \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
+ -o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
+
+cc -o $TMP/$PRGNAM/nmon $TMP/$PRGNAM/lmon.c $SLKCFLAGS
+
+find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \
+ | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true
+
+mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
+cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
+
+mkdir -p $PKG/install
+cat $CWD/slack-desc > $PKG/install/slack-desc
+
+mkdir -p $PKG/usr/bin
+cp $TMP/$PRGNAM/nmon $PKG/usr/bin/
+
+cd $PKG
+/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.${PKGTYPE:-txz}
diff --git a/source/SlackBuild/nmon/slack-desc b/source/SlackBuild/nmon/slack-desc
new file mode 100644
index 00000000..53d56d8c
--- /dev/null
+++ b/source/SlackBuild/nmon/slack-desc
@@ -0,0 +1,19 @@
+# HOW TO EDIT THIS FILE:
+# The "handy ruler" below makes it easier to edit a package description.
+# Line up the first '|' above the ':' following the base package name, and
+# the '|' on the right side marks the last column you can put a character in.
+# You must make exactly 11 lines for the formatting to be correct. It's also
+# customary to leave one space after the ':' except on otherwise blank lines.
+
+ |-----handy-ruler------------------------------------------------------|
+nmon: nmon (Nigel's performance MONitor)
+nmon:
+nmon: This systems administrator, tuner, benchmark tool gives you a huge
+nmon: amount of important performance information in one go. It can output
+nmon: the data in two ways.
+nmon:
+nmon: 1) You can display the CPU, memory, network, disks
+nmon: (mini graphs or numbers), file systems, NFS, top processes, resources
+nmon: 2) Save the data to a comma separated file for analysis and longer
+nmon: term data capture.
+nmon: