This commit is contained in:
albert 2003-05-31 00:38:55 +00:00
parent 044e7004c4
commit de2857aa89
6 changed files with 249 additions and 168 deletions

View File

@ -10,7 +10,7 @@ global:
Hertz; smp_num_cpus;
sprint_uptime; uptime; user_from_uid; print_uptime; loadavg;
pretty_print_signals; print_given_signals; unix_print_signals; signal_name_to_number; signal_number_to_name;
meminfo; vminfo;
meminfo; vminfo; getstat;
kb_active; kb_inactive; kb_main_buffers; kb_main_cached;
kb_main_free; kb_main_total; kb_main_used; kb_swap_free;
kb_swap_total; kb_swap_used; kb_main_shared;

View File

@ -269,6 +269,127 @@ void loadavg(double *restrict av1, double *restrict av5, double *restrict av15)
SET_IF_DESIRED(av15, avg_15);
}
static char buff[BUFFSIZE]; /* used in the procedures */
/***********************************************************************/
static void crash(const char *filename) {
perror(filename);
exit(EXIT_FAILURE);
}
/***********************************************************************/
static void getrunners(unsigned int *restrict running, unsigned int *restrict blocked) {
struct direct *ent;
DIR *proc;
*running=0;
*blocked=0;
if((proc=opendir("/proc"))==NULL) crash("/proc");
while(( ent=readdir(proc) )) {
unsigned size;
int fd;
char filename[80];
char c;
if (!isdigit(ent->d_name[0])) continue;
sprintf(filename, "/proc/%s/stat", ent->d_name);
fd = open(filename, O_RDONLY, 0);
if (fd == -1) continue;
read(fd,buff,BUFFSIZE-1);
sscanf(
buff,
"%*d %*s %c "
"%*d %*d %*d %*d %*d %*u %*u"
" %*u %*u %*u %*d %*d %*d %*d %*d %*d %*u %*u %*d %*u %u"
/* " %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u\n" */ ,
&c,
&size
);
close(fd);
if (c=='R') {
(*running)++;
continue;
}
if (c=='D') {
(*blocked)++;
continue;
}
}
closedir(proc);
}
/***********************************************************************/
void getstat(jiff *restrict cuse, jiff *restrict cice, jiff *restrict csys, jiff *restrict cide, jiff *restrict ciow,
unsigned long *restrict pin, unsigned long *restrict pout, unsigned long *restrict s_in, unsigned long *restrict sout,
unsigned *restrict intr, unsigned *restrict ctxt,
unsigned int *restrict running, unsigned int *restrict blocked,
unsigned int *restrict btime, unsigned int *restrict processes) {
static int fd;
int need_vmstat_file = 0;
int need_proc_scan = 0;
const char* b;
buff[BUFFSIZE-1] = 0; /* ensure null termination in buffer */
if(fd){
lseek(fd, 0L, SEEK_SET);
}else{
fd = open("/proc/stat", O_RDONLY, 0);
if(fd == -1) crash("/proc/stat");
}
read(fd,buff,BUFFSIZE-1);
*intr = 0;
*ciow = 0; /* not separated out until the 2.5.41 kernel */
b = strstr(buff, "cpu ");
if(b) sscanf(b, "cpu %Lu %Lu %Lu %Lu %Lu", cuse, cice, csys, cide, ciow);
b = strstr(buff, "page ");
if(b) sscanf(b, "page %lu %lu", pin, pout);
else need_vmstat_file = 1;
b = strstr(buff, "swap ");
if(b) sscanf(b, "swap %lu %lu", s_in, sout);
else need_vmstat_file = 1;
b = strstr(buff, "intr ");
if(b) sscanf(b, "intr %u", intr);
b = strstr(buff, "ctxt ");
if(b) sscanf(b, "ctxt %u", ctxt);
b = strstr(buff, "btime ");
if(b) sscanf(b, "btime %u", btime);
b = strstr(buff, "processes ");
if(b) sscanf(b, "processes %u", processes);
b = strstr(buff, "procs_running ");
if(b) sscanf(b, "procs_running %u", running);
else need_proc_scan = 1;
b = strstr(buff, "procs_blocked ");
if(b) sscanf(b, "procs_blocked %u", blocked);
else need_proc_scan = 1;
if(need_proc_scan){ /* Linux 2.5.46 (approximately) and below */
getrunners(running, blocked);
}
(*running)--; // exclude vmstat itself
if(need_vmstat_file){ /* Linux 2.5.40-bk4 and above */
vminfo();
*pin = vm_pgpgin;
*pout = vm_pgpgout;
*s_in = vm_pswpin;
*sout = vm_pswpout;
}
}
/***********************************************************************/
/*
* Copyright 1999 by Albert Cahalan; all rights reserved.
@ -529,4 +650,4 @@ nextline:
head = tail+1;
}
}
/*****************************************************************/

View File

@ -1,6 +1,7 @@
#ifndef PROC_SYSINFO_H
#define PROC_SYSINFO_H
#include <sys/types.h>
#include <sys/dir.h>
#include "procps.h"
EXTERN_C_BEGIN
@ -50,6 +51,16 @@ extern unsigned long kb_inactive;
extern unsigned long kb_mapped;
extern unsigned long kb_pagetables;
#define BUFFSIZE 8192
typedef unsigned long long jiff;
extern void crash(const char *filename);
extern void getrunners(unsigned int *restrict running, unsigned int *restrict blocked);
extern void getstat(jiff *restrict cuse, jiff *restrict cice, jiff *restrict csys, jiff *restrict cide, jiff *restrict ciow,
unsigned long *restrict pin, unsigned long *restrict pout, unsigned long *restrict s_in, unsigned long *restrict sout,
unsigned *restrict intr, unsigned *restrict ctxt,
unsigned int *restrict running, unsigned int *restrict blocked,
unsigned int *restrict btime, unsigned int *restrict processes);
extern void meminfo(void);

View File

@ -15,6 +15,9 @@ vmstat \- Report virtual memory statistics
.RB [ "\-s" ]
.br
.B vmstat
.RB [ "\-S unit"]
.br
.B vmstat
.RB [ "\-V" ]
.SH DESCRIPTION
\fBvmstat\fP reports information about processes, memory, paging,
@ -46,6 +49,8 @@ only one report is printed with the average values since boot.
is the number of updates. If no count is specified and delay is
defined, \fIcount\fP defaults to infinity.
.PP
The \fB-S\fP followed by k or K or m or M switches outputs between 1000, 1024, 1000000, or 1048576 bytes
.PP
The \fB-V\fP switch results in displaying version information.
.PP
.SH FIELD DESCRIPTIONS
@ -53,25 +58,25 @@ The \fB-V\fP switch results in displaying version information.
.B "Procs"
.nf
r: The number of processes waiting for run time.
b: The number of processes in uninterruptable sleep.
b: The number of processes in uninterruptible sleep.
.fi
.PP
.SS
.B "Memory"
.nf
swpd: the amount of virtual memory used (kB).
free: the amount of idle memory (kB).
buff: the amount of memory used as buffers (kB).
cache: the amount of memory used as cache (kB).
inact: the amount of inactive memory (kB). (-a option)
active: the amount of active memory (kB). (-a option)
swpd: the amount of virtual memory used.
free: the amount of idle memory.
buff: the amount of memory used as buffers.
cache: the amount of memory used as cache.
inact: the amount of inactive memory. (-a option)
active: the amount of active memory. (-a option)
.fi
.PP
.SS
.B "Swap"
.nf
si: Amount of memory swapped in from disk (kB/s).
so: Amount of memory swapped to disk (kB/s).
si: Amount of memory swapped in from disk (/s).
so: Amount of memory swapped to disk (/s).
.fi
.PP
.SS
@ -108,6 +113,8 @@ does not count itself as a running process.
All linux blocks are currently 1024 bytes. Old kernels may report
blocks as 512 bytes, 2048 bytes, or 4096 bytes.
.PP
Since procps 3.1.9, vmstat lets you choose units (k, K, m, M)
.PP
.SH FILES
.ta
.nf

227
vmstat.c
View File

@ -1,5 +1,8 @@
// old: "Copyright 1994 by Henry Ware <al172@yfn.ysu.edu>. Copyleft same year."
// most code copyright 2002 Albert Cahalan
// 27/05/2003 (Fabian) : Add unit conversion + interface
// Export proc/stat access to libproc
// Adapt vmstat helpfile
#include <stdio.h>
#include <stdlib.h>
@ -16,15 +19,11 @@
#include "proc/sysinfo.h"
#include "proc/version.h"
#include "vmstat.h"
#define BUFFSIZE 8192
#define FALSE 0
#define TRUE 1
static char buff[BUFFSIZE]; /* used in the procedures */
typedef unsigned long long jiff;
static int a_option; /* "-a" means "show active/inactive" */
static unsigned sleep_time = 1;
@ -42,131 +41,14 @@ static void usage(void) {
fprintf(stderr," -V prints version.\n");
fprintf(stderr," -n causes the headers not to be reprinted regularly.\n");
fprintf(stderr," -a print inactive/active page stats.\n");
fprintf(stderr," -S unit size\n");
fprintf(stderr," delay is the delay between updates in seconds. \n");
fprintf(stderr," unit size k:1000 K:1024 m:1000000 M:1048576 (default is K)\n");
fprintf(stderr," count is the number of updates.\n");
exit(EXIT_FAILURE);
}
static void crash(const char *filename) NORETURN;
static void crash(const char *filename) {
perror(filename);
exit(EXIT_FAILURE);
}
////////////////////////////////////////////////////////////////////////
static void getrunners(unsigned int *restrict running, unsigned int *restrict blocked) {
static struct direct *ent;
DIR *proc;
*running=0;
*blocked=0;
if((proc=opendir("/proc"))==NULL) crash("/proc");
while(( ent=readdir(proc) )) {
unsigned size;
int fd;
char filename[80];
char c;
if (!isdigit(ent->d_name[0])) continue;
sprintf(filename, "/proc/%s/stat", ent->d_name);
fd = open(filename, O_RDONLY, 0);
if (fd == -1) continue;
read(fd,buff,BUFFSIZE-1);
sscanf(
buff,
"%*d %*s %c "
"%*d %*d %*d %*d %*d %*u %*u"
" %*u %*u %*u %*d %*d %*d %*d %*d %*d %*u %*u %*d %*u %u"
/* " %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u\n" */ ,
&c,
&size
);
close(fd);
if (c=='R') {
(*running)++;
continue;
}
if (c=='D') {
(*blocked)++;
continue;
}
}
closedir(proc);
}
static void getstat(jiff *restrict cuse, jiff *restrict cice, jiff *restrict csys, jiff *restrict cide, jiff *restrict ciow,
unsigned long *restrict pin, unsigned long *restrict pout, unsigned long *restrict s_in, unsigned long *restrict sout,
unsigned *restrict intr, unsigned *restrict ctxt,
unsigned int *restrict running, unsigned int *restrict blocked,
unsigned int *restrict btime, unsigned int *restrict processes) {
static int fd;
int need_vmstat_file = 0;
int need_proc_scan = 0;
const char* b;
buff[BUFFSIZE-1] = 0; /* ensure null termination in buffer */
if(fd){
lseek(fd, 0L, SEEK_SET);
}else{
fd = open("/proc/stat", O_RDONLY, 0);
if(fd == -1) crash("/proc/stat");
}
read(fd,buff,BUFFSIZE-1);
*intr = 0;
*ciow = 0; /* not separated out until the 2.5.41 kernel */
b = strstr(buff, "cpu ");
if(b) sscanf(b, "cpu %Lu %Lu %Lu %Lu %Lu", cuse, cice, csys, cide, ciow);
b = strstr(buff, "page ");
if(b) sscanf(b, "page %lu %lu", pin, pout);
else need_vmstat_file = 1;
b = strstr(buff, "swap ");
if(b) sscanf(b, "swap %lu %lu", s_in, sout);
else need_vmstat_file = 1;
b = strstr(buff, "intr ");
if(b) sscanf(b, "intr %u", intr);
b = strstr(buff, "ctxt ");
if(b) sscanf(b, "ctxt %u", ctxt);
b = strstr(buff, "btime ");
if(b) sscanf(b, "btime %u", btime);
b = strstr(buff, "processes ");
if(b) sscanf(b, "processes %u", processes);
b = strstr(buff, "procs_running ");
if(b) sscanf(b, "procs_running %u", running);
else need_proc_scan = 1;
b = strstr(buff, "procs_blocked ");
if(b) sscanf(b, "procs_blocked %u", blocked);
else need_proc_scan = 1;
if(need_proc_scan){ /* Linux 2.5.46 (approximately) and below */
getrunners(running, blocked);
}
(*running)--; // exclude vmstat itself
if(need_vmstat_file){ /* Linux 2.5.40-bk4 and above */
vminfo();
*pin = vm_pgpgin;
*pout = vm_pgpgout;
*s_in = vm_pswpin;
*sout = vm_pswpout;
}
}
//////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#if 0
// produce: " 6 ", "123 ", "123k ", etc.
@ -248,6 +130,17 @@ static void new_header(void){
);
}
////////////////////////////////////////////////////////////////////////////
unsigned long unitConvert(unsigned int kbsize)
{
float cvSize;
cvSize=(float)kbsize/dataUnit*1024;
return ((unsigned long) cvSize);
}
////////////////////////////////////////////////////////////////////////////
static void new_format(void) {
const char format[]="%2u %2u %6lu %6lu %6lu %6lu %4u %4u %5u %5u %4u %5u %2u %2u %2u %2u\n";
unsigned int tog=0; /* toggle switch for cleaner code */
@ -266,11 +159,13 @@ static void new_format(void) {
new_header();
meminfo();
getstat(cpu_use,cpu_nic,cpu_sys,cpu_idl,cpu_iow,
pgpgin,pgpgout,pswpin,pswpout,
intr,ctxt,
&running,&blocked,
&dummy_1, &dummy_2);
duse= *cpu_use + *cpu_nic;
dsys= *cpu_sys;
didl= *cpu_idl;
@ -279,11 +174,11 @@ static void new_format(void) {
divo2= Div/2UL;
printf(format,
running, blocked,
kb_swap_used, kb_main_free,
a_option?kb_inactive:kb_main_buffers,
a_option?kb_active:kb_main_cached,
(unsigned)( (*pswpin * kb_per_page * hz + divo2) / Div ),
(unsigned)( (*pswpout * kb_per_page * hz + divo2) / Div ),
unitConvert(kb_swap_used), unitConvert(kb_main_free),
unitConvert(a_option?kb_inactive:kb_main_buffers),
unitConvert(a_option?kb_active:kb_main_cached),
(unsigned)( (*pswpin * unitConvert(kb_per_page) * hz + divo2) / Div ),
(unsigned)( (*pswpout * unitConvert(kb_per_page) * hz + divo2) / Div ),
(unsigned)( (*pgpgin * hz + divo2) / Div ),
(unsigned)( (*pgpgout * hz + divo2) / Div ),
(unsigned)( (*intr * hz + divo2) / Div ),
@ -300,11 +195,13 @@ static void new_format(void) {
tog= !tog;
meminfo();
getstat(cpu_use+tog,cpu_nic+tog,cpu_sys+tog,cpu_idl+tog,cpu_iow+tog,
pgpgin+tog,pgpgout+tog,pswpin+tog,pswpout+tog,
intr+tog,ctxt+tog,
&running,&blocked,
&dummy_1,&dummy_2);
duse= cpu_use[tog]-cpu_use[!tog] + cpu_nic[tog]-cpu_nic[!tog];
dsys= cpu_sys[tog]-cpu_sys[!tog];
didl= cpu_idl[tog]-cpu_idl[!tog];
@ -324,25 +221,24 @@ static void new_format(void) {
divo2= Div/2UL;
printf(format,
running, blocked,
kb_swap_used,kb_main_free,
a_option?kb_inactive:kb_main_buffers,
a_option?kb_active:kb_main_cached,
(unsigned)( ( (pswpin [tog] - pswpin [!tog])*kb_per_page+sleep_half )/sleep_time ),
(unsigned)( ( (pswpout[tog] - pswpout[!tog])*kb_per_page+sleep_half )/sleep_time ),
(unsigned)( ( pgpgin [tog] - pgpgin [!tog] +sleep_half )/sleep_time ),
(unsigned)( ( pgpgout[tog] - pgpgout[!tog] +sleep_half )/sleep_time ),
(unsigned)( ( intr [tog] - intr [!tog] +sleep_half )/sleep_time ),
(unsigned)( ( ctxt [tog] - ctxt [!tog] +sleep_half )/sleep_time ),
(unsigned)( (100*duse+divo2)/Div ),
(unsigned)( (100*dsys+divo2)/Div ),
(unsigned)( (100*didl+divo2)/Div ),
(unsigned)( (100*diow+divo2)/Div )
unitConvert(kb_swap_used),unitConvert(kb_main_free),
unitConvert(a_option?kb_inactive:kb_main_buffers),
unitConvert(a_option?kb_active:kb_main_cached),
(unsigned)( ( (pswpin [tog] - pswpin [!tog])*unitConvert(kb_per_page)+sleep_half )/sleep_time ), /*si*/
(unsigned)( ( (pswpout[tog] - pswpout[!tog])*unitConvert(kb_per_page)+sleep_half )/sleep_time ), /*so*/
(unsigned)( ( pgpgin [tog] - pgpgin [!tog] +sleep_half )/sleep_time ), /*bi*/
(unsigned)( ( pgpgout[tog] - pgpgout[!tog] +sleep_half )/sleep_time ), /*bo*/
(unsigned)( ( intr [tog] - intr [!tog] +sleep_half )/sleep_time ), /*in*/
(unsigned)( ( ctxt [tog] - ctxt [!tog] +sleep_half )/sleep_time ), /*cs*/
(unsigned)( (100*duse+divo2)/Div ), /*us*/
(unsigned)( (100*dsys+divo2)/Div ), /*sy*/
(unsigned)( (100*didl+divo2)/Div ), /*id*/
(unsigned)( (100*diow+divo2)/Div ) /*wa*/
);
}
}
//////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
static void sum_format(void) {
unsigned int running, blocked, btime, processes;
@ -351,21 +247,23 @@ static void sum_format(void) {
unsigned int intr, ctxt;
meminfo();
getstat(&cpu_use, &cpu_nic, &cpu_sys, &cpu_idl, &cpu_iow,
&pgpgin, &pgpgout, &pswpin, &pswpout,
&intr, &ctxt,
&running, &blocked,
&btime, &processes);
printf("%13lu kB total memory\n", kb_main_total);
printf("%13lu kB used memory\n", kb_main_used);
printf("%13lu kB active memory\n", kb_active);
printf("%13lu kB inactive memory\n", kb_inactive);
printf("%13lu kB free memory\n", kb_main_free);
printf("%13lu kB buffer memory\n", kb_main_buffers);
printf("%13lu kB swap cache\n", kb_main_cached);
printf("%13lu kB total swap\n", kb_swap_total);
printf("%13lu kB used swap\n", kb_swap_used);
printf("%13lu kB free swap\n", kb_swap_free);
printf("%13lu %s total memory\n", unitConvert(kb_main_total),szDataUnit);
printf("%13lu %s used memory\n", unitConvert(kb_main_used),szDataUnit);
printf("%13lu %s active memory\n", unitConvert(kb_active),szDataUnit);
printf("%13lu %s inactive memory\n", unitConvert(kb_inactive),szDataUnit);
printf("%13lu %s free memory\n", unitConvert(kb_main_free),szDataUnit);
printf("%13lu %s buffer memory\n", unitConvert(kb_main_buffers),szDataUnit);
printf("%13lu %s swap cache\n", unitConvert(kb_main_cached),szDataUnit);
printf("%13lu %s total swap\n", unitConvert(kb_swap_total),szDataUnit);
printf("%13lu %s used swap\n", unitConvert(kb_swap_used),szDataUnit);
printf("%13lu %s free swap\n", unitConvert(kb_swap_free),szDataUnit);
printf("%13Lu non-nice user cpu ticks\n", cpu_use);
printf("%13Lu nice user cpu ticks\n", cpu_nic);
printf("%13Lu system cpu ticks\n", cpu_sys);
@ -380,7 +278,6 @@ static void sum_format(void) {
printf("%13u boot time\n", btime);
printf("%13u forks\n", processes);
}
static void fork_format(void) {
unsigned int running, blocked, btime, processes;
jiff cpu_use, cpu_nic, cpu_sys, cpu_idl, cpu_iow;
@ -392,6 +289,7 @@ static void fork_format(void) {
&intr, &ctxt,
&running, &blocked,
&btime, &processes);
printf("%13u forks\n", processes);
}
@ -412,6 +310,7 @@ int main(int argc, char *argv[]) {
for (argv++;*argv;argv++) {
if ('-' ==(**argv)) {
switch (*(++(*argv))) {
case 'V':
display_version();
exit(0);
@ -427,6 +326,22 @@ int main(int argc, char *argv[]) {
/* print only one header */
moreheaders=FALSE;
break;
case 'S':
if (argv[1]){
++argv;
if (!strcmp(*argv, "k")) dataUnit=UNIT_k;
else if (!strcmp(*argv, "K")) dataUnit=UNIT_K;
else if (!strcmp(*argv, "m")) dataUnit=UNIT_m;
else if (!strcmp(*argv, "M")) dataUnit=UNIT_M;
else {fprintf(stderr, "-S requires k, K, m or M (default is kb)\n");
exit(EXIT_FAILURE);
}
strcpy(szDataUnit, *argv);
}else {fprintf(stderr, "-S requires an argument\n");
exit(EXIT_FAILURE);
}
break;
case 's':
// FIXME: check for conflicting args
sum_format();

27
vmstat.h Normal file
View File

@ -0,0 +1,27 @@
/* vmstat.h - Header file: memory usage */
/*
* Copyright (c) 2003, by: Fabian Frederick
* All rights reserved. fabian.frederick@gmx.fr
*
*
* This file may be used subject to the terms and conditions of the
* GNU Library General Public License Version 2, or any later version
* at your option, as published by the Free Software Foundation.
* 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 Library General Public License for more details.
*
*
*/
#ifndef _IVMstat
#define _IVMstat
unsigned long dataUnit=1024;
char szDataUnit [16];
#define UNIT_k 1000
#define UNIT_K 1024
#define UNIT_m 1000000
#define UNIT_M 1048576
#endif /* _IVMstat */