diskstats and slabinfo

This commit is contained in:
albert 2003-06-08 17:28:06 +00:00
parent 87402486f7
commit 5c99a21b72
10 changed files with 395 additions and 37 deletions

View File

@ -3,6 +3,9 @@ If you change an existing file, follow the existing style.
Hard tabs are OK, as long as you consider the tab stops to
be every 8 characters. You can also use 2, 3, or 4 spaces.
Tabs are kind of yucky, since cut-and-paste mangles them
sometimes and they make "diff -Naurd old new" output less
readable.
Spaces within a line don't matter much, and won't be
considered part of the style. Just make it readable:
@ -44,6 +47,8 @@ fprintf(fd, "%d %d %d %d %d %d\n",
sfssss + wwwwfwfw
);
Keep these distinct: NULL, '\0', 0, 0.0
Command-line parsers need to be bomb-proof. It is not acceptable
to crash due to a messed up command-line. For an option "-x" that
takes an argument, accept both "-x arg" and "-xarg". Remember to
@ -56,15 +61,22 @@ non-ASCII characters to be printed. Assuming the console is
not in UTF-8 mode, all of these are bad: "\b\e\f\n\r\t\v\x9b".
(the "\x9b" is valid in UTF-8 mode, but equivalent to "\e["
when not in UTF-8 mode -- which gives control of terminal
settings)
settings) It's best if you consider user-supplied data to
be unsafe, since this makes for less work in case the code
ends up needing to run setuid. Termcap data is user-supplied.
Except for the above security issues, don't bother to check
for something you can't handle... like printf() failing.
It is expected that /dev exists and so on.
Remember that a read() may return early, with partial data
or with -1 and errno set to EINTR. You then must try again.
char: may be signed or unsigned by default
int: always 32-bit
char: may be signed or unsigned by default
int: always 32-bit
long long: always 64-bit
long: same size as a pointer, either 32-bit or 64-bit
pointer: either 32-bit or 64-bit
long: same size as a pointer
KLONG: same size as a pointer or long IN THE KERNEL
Functions used in just one file must be marked static.
Use the "const" and "restrict" keywords wherever you can.

View File

@ -18,9 +18,9 @@
VERSION := 3
SUBVERSION := 1
MINORVERSION := 9
TARVERSION := 3.1.9
LIBVERSION := 3.1.9
MINORVERSION := 10
TARVERSION := 3.1.10
LIBVERSION := 3.1.10
############ vars

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; getstat;
meminfo; vminfo; getstat; getdiskstat; getslabinfo;
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

@ -4,8 +4,10 @@
// This file is placed under the conditions of the GNU Library
// General Public License, version 2, or any later version.
// See file COPYING for information on distribution conditions.
/* File for parsing top-level /proc entities. */
//
// File for parsing top-level /proc entities. */
//
// June 2003, Fabian Frederick, disk and slab info
#include <stdio.h>
#include <stdlib.h>
@ -172,7 +174,9 @@ static void old_Hertz_hack(void){
#define AT_CLKTCK 17 /* frequency of times() */
#endif
extern char** environ;
#define NOTE_NOT_FOUND 42
//extern char** environ;
/* for ELF executables, notes are pushed before environment and args */
static unsigned long find_elf_note(unsigned long findme){
@ -182,7 +186,7 @@ static unsigned long find_elf_note(unsigned long findme){
if(ep[0]==findme) return ep[1];
ep+=2;
}
return 42;
return NOTE_NOT_FOUND;
}
static void init_libproc(void) __attribute__((constructor));
@ -195,7 +199,7 @@ static void init_libproc(void){
if(linux_version_code > LINUX_VERSION(2, 4, 0)){
Hertz = find_elf_note(AT_CLKTCK);
if(Hertz!=42) return;
if(Hertz!=NOTE_NOT_FOUND) return;
fprintf(stderr, "2.4 kernel w/o ELF notes? -- report to albert@users.sf.net\n");
}
old_Hertz_hack();
@ -651,3 +655,105 @@ nextline:
}
}
///////////////////////////////////////////////////////////////////////
// based on Fabian Frederick's /proc/diskstats parser
static unsigned int getFileLines(const char* szFile){
char szBuffer[1024];
FILE *fdiskStat;
int lines=0;
if ((fdiskStat=fopen (szFile,"rb"))){
while (fgets(szBuffer, 1024, fdiskStat)){
lines++;
}
fclose(fdiskStat);
}
return lines;
}
unsigned int getdiskstat(struct disk_stat **disks, struct partition_stat **partitions){
FILE* fd;
buff[BUFFSIZE-1] = 0;
int units,
i,
disk_type,
disk_num,
cDisk=0,
cPartition=0;
*disks = NULL;
*partitions = NULL;
units = getFileLines("/proc/diskstats");
fd = fopen("/proc/diskstats", "rb");
if(!fd) crash("/proc/diskstats");
for (i=0; i<units; i++){
if (!fgets(buff,BUFFSIZE-1,fd)){
fclose(fd);
crash("/proc/diskstats");
}
sscanf(buff, " %d %d", &disk_type, &disk_num);
if (disk_num == 0){
(*disks) = realloc(*disks, (cDisk+1)*sizeof(struct disk_stat));
sscanf(buff, " %d %*d %15s %u %u %llu %u %u %u %llu %u %u %u %u",
&(*disks)[cDisk].disk_type,
//&unused,
(*disks)[cDisk].disk_name,
&(*disks)[cDisk].reads,
&(*disks)[cDisk].merged_reads,
&(*disks)[cDisk].reads_sectors,
&(*disks)[cDisk].milli_reading,
&(*disks)[cDisk].writes,
&(*disks)[cDisk].merged_writes,
&(*disks)[cDisk].written_sectors,
&(*disks)[cDisk].milli_writing,
&(*disks)[cDisk].inprogress_IO,
&(*disks)[cDisk].milli_spent_IO,
&(*disks)[cDisk].weighted_milli_spent_IO
);
cDisk++;
}else{
(*partitions) = realloc(*partitions, (cPartition+1)*sizeof(struct partition_stat));
fflush(stdout);
sscanf(buff, " %d %d %15s %u %llu %u %u",
&(*partitions)[cPartition].disk_type,
&(*partitions)[cPartition].partition_num,
(*partitions)[cPartition].partition_name,
&(*partitions)[cPartition].reads,
&(*partitions)[cPartition].reads_sectors,
&(*partitions)[cPartition].writes,
&(*partitions)[cPartition].requested_writes
);
(*partitions)[cPartition++].parent_disk = &((*disks)[cDisk-1]);
}
}
fclose(fd);
return cDisk;
}
/////////////////////////////////////////////////////////////////////////////
// based on Fabian Frederick's /proc/slabinfo parser
unsigned int getslabinfo (struct slab_cache **slab){
FILE* fd;
int cSlab = 0;
buff[BUFFSIZE-1] = 0;
*slab = NULL;
fd = fopen("/proc/slabinfo", "rb");
if(!fd) crash("/proc/slabinfo");
while (fgets(buff,BUFFSIZE-1,fd)){
if(!memcmp("slabinfo - version:",buff,19)) continue; // skip header
if(*buff == '#') continue; // skip comments
(*slab) = realloc(*slab, (cSlab+1)*sizeof(struct slab_cache));
sscanf(buff, "%47s %u %u %u %u", // allow 47; max seen is 24
(*slab)[cSlab].name,
&(*slab)[cSlab].active_objs,
&(*slab)[cSlab].num_objs,
&(*slab)[cSlab].objsize,
&(*slab)[cSlab].objperslab
) ;
cSlab++;
}
fclose(fd);
return cSlab;
}

View File

@ -88,5 +88,44 @@ extern unsigned long vm_allocstall;
extern void vminfo(void);
typedef struct disk_stat{
unsigned int disk_type;
char disk_name [16];
unsigned reads;
unsigned merged_reads;
unsigned long long reads_sectors;
unsigned milli_reading;
unsigned writes;
unsigned merged_writes;
unsigned long long written_sectors;
unsigned milli_writing;
unsigned inprogress_IO;
unsigned milli_spent_IO;
unsigned weighted_milli_spent_IO;
}disk_stat;
typedef struct partition_stat{
unsigned int disk_type;
unsigned int partition_num;
char partition_name [16];
struct disk_stat* parent_disk;
unsigned reads;
unsigned long long reads_sectors;
unsigned writes;
unsigned requested_writes;
}partition_stat;
extern unsigned int getdiskstat (struct disk_stat**,struct partition_stat**);
typedef struct slab_cache{
char name[48];
unsigned active_objs;
unsigned num_objs;
unsigned objsize;
unsigned objperslab;
}slab_cache;
extern unsigned int getslabinfo (struct slab_cache**);
EXTERN_C_END
#endif /* SYSINFO_H */

View File

@ -1,15 +1,15 @@
Begin4
Title: procps
Version: 3.1.9
Entered-date: 2003-03-27
Version: 3.1.10
Entered-date: 2003-06-08
Description: Linux system utilities
Keywords: procps /proc libproc sysctl pmap ps uptime tload
free w top vmstat watch skill snice kill pgrep pkill
Author: Albert Cahalan, Michael K. Johnson, Jim Warner, etc.
Maintained-by: various <procps-feedback@lists.sf.net>
Primary-site: http://procps.sf.net/
239kB procps-3.1.9.tar.gz
239kB procps-3.1.10.tar.gz
Alternate-site: http://www.debian.org/Packages/unstable/base/procps.html
239kB procps-3.1.9.tar.gz
239kB procps-3.1.10.tar.gz
Copying-policy: mixed
End

View File

@ -3,7 +3,7 @@ Summary: System and process monitoring utilities
Name: procps
%define major_version 3
%define minor_version 1
%define revision 9
%define revision 10
%define version %{major_version}.%{minor_version}.%{revision}
Version: %{version}
Release: 1

View File

@ -13,11 +13,15 @@ vmstat \- Report virtual memory statistics
.B vmstat
.RB [ "\-f" ]
.RB [ "\-s" ]
.RB [ "\-m" ]
.br
.B vmstat
.RB [ "\-S unit"]
.br
.B vmstat
.RB [ "\-d"]
.br
.B vmstat
.RB [ "\-V" ]
.SH DESCRIPTION
\fBvmstat\fP reports information about processes, memory, paging,
@ -36,6 +40,8 @@ equivalent to the total number of tasks created. Each process
is represented by one or more tasks, depending on thread usage.
This display does not repeat.
.PP
The \fB-m\fP displays slabinfo.
.PP
The \fB-n\fP switch causes the header to be displayed only once rather than periodically.
.PP
The \fB-s\fP switch displays a table of various event counters
@ -49,11 +55,13 @@ 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-d\fP reports disk statistics (2.5.70 or above required)
.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
.SH FIELD DESCRIPTION FOR VM MODE
.SS
.B "Procs"
.nf
@ -101,7 +109,47 @@ us: Time spent running non-kernel code. (user time, including nice time)
sy: Time spent running kernel code. (system time)
id: Time spent idle. Prior to Linux 2.5.41, this includes IO-wait time.
wa: Time spent waiting for IO. Prior to Linux 2.5.41, shown as zero.
.PP
.SH FIELD DESCRIPTION FOR DISK MODE
.SS
.B "Reads"
.nf
total: Total reads completed successfully
merged: grouped reads (resulting in one I/O)
sectors: Sectors read successfully
ms: milliseconds spent reading
.fi
.PP
.SS
.B "Writes"
.nf
total: Total writes completed successfully
merged: grouped writes (resulting in one I/O)
sectors: Sectors written successfully
ms: milliseconds spent writing
.fi
.PP
.SS
.B "IO"
.nf
cur: I/O in progress
s: seconds spent for I/O
.fi
.PP
.SH FIELD DESCRIPTION FOR SLAB MODE
.nf
cache: Cache name
num: Number of currently active objects
total: Total number of available objects
size: Size of each object
pages: Number of pages with at least one active object
totpages: Total number of allocated pages
pslab: Number of pages per slab
.fi
.SH NOTES
.B "vmstat "
does not require special permissions.
@ -113,8 +161,9 @@ 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)
Since procps 3.1.9, vmstat lets you choose units (k, K, m, M) default is K (1024 bytes) in the default mode
.PP
vmstat uses slabinfo 1.1 FIXME
.SH FILES
.ta
.nf
@ -128,5 +177,7 @@ iostat(1), sar(1), mpstat(1), ps(1), top(1), free(1)
.PP
.SH BUGS
Does not tabulate the block io per device or count the number of system calls.
.SH AUTHOR
.SH AUTHORS
.nf
Written by Henry Ware <al172@yfn.ysu.edu>.
Diskstat,slab mode and some improvements by Fabian Frederick <fabian.frederick@gmx.fr>

175
vmstat.c
View File

@ -3,6 +3,10 @@
// 27/05/2003 (Fabian) : Add unit conversion + interface
// Export proc/stat access to libproc
// Adapt vmstat helpfile
// 31/05/2003 (Fabian) : Add diskstat support (/libproc)
// June 2003 (Fabian) : -S <x> -s & -s -S <x> patch
// June 2003 (Fabian) : -Adding diskstat against 3.1.9, slabinfo
// -patching 'header' in disk & slab
#include <stdio.h>
#include <stdlib.h>
@ -19,7 +23,21 @@
#include "proc/sysinfo.h"
#include "proc/version.h"
#include "vmstat.h"
static unsigned long dataUnit=1024;
static char szDataUnit [16];
#define UNIT_B 1
#define UNIT_k 1000
#define UNIT_K 1024
#define UNIT_m 1000000
#define UNIT_M 1048576
#define VMSTAT 0
#define DISKSTAT 0x00000001
#define VMSUMSTAT 0x00000002
#define SLABSTAT 0x00000004
static int statMode=VMSTAT;
#define FALSE 0
#define TRUE 1
@ -41,6 +59,8 @@ 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," -d prints disk statistics\n");
fprintf(stderr," -m prints slabinfo\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");
@ -132,10 +152,25 @@ static void new_header(void){
////////////////////////////////////////////////////////////////////////////
unsigned long unitConvert(unsigned int kbsize)
{
static void new_diskheader(void){
printf("disk ----------reads------------ -----------writes----------- -------IO-------\n");
printf("%3s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", " ", "total", "merged","sectors","ms","total","merged","sectors","ms","cur","s");
}
////////////////////////////////////////////////////////////////////////////
static void new_slabheader(void){
printf("%-24s %6s %6s %6s %6s\n","Cache","Num", "Total", "Size", "Pages");
}
////////////////////////////////////////////////////////////////////////////
static unsigned long unitConvert(unsigned int size){
float cvSize;
cvSize=(float)kbsize/dataUnit*1024;
cvSize=(float)size/dataUnit*((statMode==SLABSTAT)?1:1024);
return ((unsigned long) cvSize);
}
@ -157,7 +192,6 @@ static void new_format(void) {
sleep_half=(sleep_time/2);
new_header();
meminfo();
getstat(cpu_use,cpu_nic,cpu_sys,cpu_idl,cpu_iow,
@ -240,6 +274,98 @@ static void new_format(void) {
////////////////////////////////////////////////////////////////////////////
static void new_diskformat(void){
FILE *fDiskstat;
struct disk_stat *disks;
struct partition_stat *partitions;
unsigned long ndisks,i,j,k;
const char format[]="%-3s %6u %6u %6llu %6u %6u %6u %6llu %6u %6u %6u\n";
if ((fDiskstat=fopen("/proc/diskstats", "rb"))){
fclose(fDiskstat);
ndisks=getdiskstat(&disks,&partitions);
for(k=0; k<ndisks; k++){
if (moreheaders && ((k%height)==0)) new_diskheader();
printf(format,
disks[k].disk_name,disks[k].reads, disks[k].merged_reads,disks[k].reads_sectors, disks[k].milli_reading, disks[k].writes, disks[k].merged_writes, disks[k].written_sectors,disks[k].milli_writing, disks[k].inprogress_IO?disks[k].inprogress_IO/1000:0, disks[k].milli_spent_IO?disks[k].milli_spent_IO/1000:0/*, disks[i].weighted_milli_spent_IO/1000*/);
fflush(stdout);
}
free(disks);
free(partitions);
for(j=1; j<num_updates; j++){
sleep(sleep_time);
ndisks=getdiskstat(&disks,&partitions);
for(i=0; i<ndisks; i++,k++){
if (moreheaders && ((k%height)==0)) new_diskheader();
printf(format,
disks[i].disk_name,
disks[i].reads,
disks[i].merged_reads,
disks[i].reads_sectors,
disks[i].milli_reading,
disks[i].writes,
disks[i].merged_writes,
disks[i].written_sectors,
disks[i].milli_writing,
disks[i].inprogress_IO?disks[i].inprogress_IO/1000:0,
disks[i].milli_spent_IO?disks[i].milli_spent_IO/1000:0/*,
disks[i].weighted_milli_spent_IO/1000*/
);
fflush(stdout);
}
free(disks);
free(partitions);
}
}else{
fprintf(stderr, "Your kernel doesn't support diskstat (2.5.70 or above required)");
exit(0);
}
}
////////////////////////////////////////////////////////////////////////////
static void new_slabformat (void){
FILE *fSlab;
struct slab_cache *slabs;
unsigned long nSlab,i,j,k;
const char format[]="%-24s %6u %6u %6u %6u\n";
fSlab=fopen("/proc/slabinfo", "rb");
if(!fSlab){
fprintf(stderr, "Your kernel doesn't support slabinfo");
return;
}
nSlab = getslabinfo(&slabs);
for(k=0; k<nSlab; k++){
if (moreheaders && ((k%height)==0)) new_slabheader();
printf(format,
slabs[k].name,
slabs[k].active_objs,
slabs[k].num_objs,
slabs[k].objsize,
slabs[k].objperslab
);
}
free(slabs);
for(j=1,k=1; j<num_updates; j++) {
sleep(sleep_time);
nSlab = getslabinfo(&slabs);
for(i=0; i<nSlab; i++,k++){
if (moreheaders && ((k%height)==0)) new_slabheader();
printf(format,
slabs[i].name,
slabs[i].active_objs,
slabs[i].num_objs,
slabs[i].objsize,
slabs[i].objperslab
);
}
free(slabs);
}
}
////////////////////////////////////////////////////////////////////////////
static void sum_format(void) {
unsigned int running, blocked, btime, processes;
jiff cpu_use, cpu_nic, cpu_sys, cpu_idl, cpu_iow;
@ -278,6 +404,9 @@ 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;
@ -293,6 +422,7 @@ static void fork_format(void) {
printf("%13u forks\n", processes);
}
////////////////////////////////////////////////////////////////////////////
static int winhi(void) {
struct winsize win;
@ -304,16 +434,20 @@ static int winhi(void) {
return rows;
}
////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]) {
argc=0; /* redefined as number of integer arguments */
for (argv++;*argv;argv++) {
if ('-' ==(**argv)) {
switch (*(++(*argv))) {
case 'V':
display_version();
exit(0);
case 'd':
statMode |= DISKSTAT;
break;
case 'a':
/* active/inactive mode */
a_option=1;
@ -322,6 +456,9 @@ int main(int argc, char *argv[]) {
// FIXME: check for conflicting args
fork_format();
exit(0);
case 'm':
statMode |= SLABSTAT;
break;
case 'n':
/* print only one header */
moreheaders=FALSE;
@ -341,16 +478,14 @@ int main(int argc, char *argv[]) {
exit(EXIT_FAILURE);
}
break;
case 's':
// FIXME: check for conflicting args
sum_format();
exit(0);
statMode |= VMSUMSTAT;
break;
default:
/* no other aguments defined yet. */
usage();
}
} else {
}else{
argc++;
switch (argc) {
case 1:
@ -364,17 +499,25 @@ int main(int argc, char *argv[]) {
default:
usage();
} /* switch */
}
}
}
if (moreheaders) {
int tmp=winhi()-3;
height=((tmp>0)?tmp:22);
}
setlinebuf(stdout);
new_format();
switch(statMode){
case(VMSTAT): new_format();
break;
case(VMSUMSTAT):sum_format();
break;
case(DISKSTAT): new_diskformat();
break;
case(SLABSTAT): new_slabformat();
break;
default: usage();
break;
}
return 0;
}

View File

@ -19,9 +19,16 @@
#define _IVMstat
unsigned long dataUnit=1024;
char szDataUnit [16];
#define UNIT_B 1
#define UNIT_k 1000
#define UNIT_K 1024
#define UNIT_m 1000000
#define UNIT_M 1048576
#define VMSTAT 1
#define DISKSTAT 2
#define VMSUMSTAT 3
#define SLABSTAT 4
int statMode=VMSTAT;
#endif /* _IVMstat */