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:
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
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.
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
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;
// 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>
#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){
if(ep[0]==findme) return ep[1];
ep+=2;
}
- return 42;
+ return NOTE_NOT_FOUND;
}
static void init_libproc(void) __attribute__((constructor));
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();
}
}
+///////////////////////////////////////////////////////////////////////
+// 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;
+}
+
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 */
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
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
.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,
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
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
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.
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
.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>
// 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>
#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
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");
////////////////////////////////////////////////////////////////////////////
-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);
}
sleep_half=(sleep_time/2);
new_header();
-
meminfo();
getstat(cpu_use,cpu_nic,cpu_sys,cpu_idl,cpu_iow,
////////////////////////////////////////////////////////////////////////////
+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;
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;
printf("%13u forks\n", processes);
}
+////////////////////////////////////////////////////////////////////////////
static int winhi(void) {
struct winsize win;
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;
// FIXME: check for conflicting args
fork_format();
exit(0);
+ case 'm':
+ statMode |= SLABSTAT;
+ break;
case 'n':
/* print only one header */
moreheaders=FALSE;
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:
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;
}
#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 */