library: Update diskstat API
The calls for reading diskstat have been moved out of sysinfo and into new files diskstat.[ch] These new library calls follow the standard pattern for the new libprocps. vmstat is updated to use the new API and also got the weighted IO time added. vmstat -p previously would only show partitions, not disks. There does not appear to be any good reason to artifically deny a user to use this command on a disk, rather than a partition so this restriction was lifted. I also realised using int for devid means you can send the library negative numbers, the index uses unsigned int. Other similiar calls will need to be fixed too. Signed-off-by: Craig Small <csmall@enc.com.au>
This commit is contained in:
parent
62f9a51532
commit
e445f7e6c5
@ -156,6 +156,8 @@ proc_libprocps_la_SOURCES = \
|
||||
proc/alloc.h \
|
||||
proc/devname.c \
|
||||
proc/devname.h \
|
||||
proc/diskstat.c \
|
||||
proc/diskstat.h \
|
||||
proc/escape.c \
|
||||
proc/escape.h \
|
||||
proc/procps-private.h \
|
||||
@ -185,6 +187,7 @@ proc_libprocps_la_includedir = $(includedir)/proc/
|
||||
proc_libprocps_la_include_HEADERS = \
|
||||
proc/alloc.h \
|
||||
proc/devname.h \
|
||||
proc/diskstat.h \
|
||||
proc/escape.h \
|
||||
proc/procps.h \
|
||||
proc/pwcache.h \
|
||||
|
327
proc/diskstat.c
Normal file
327
proc/diskstat.c
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* diskstat - Disk statistics - part of procps
|
||||
*
|
||||
* Copyright (C) 2003 Fabian Frederick
|
||||
* Copyright (C) 2003 Albert Cahalan
|
||||
* Copyright (C) 2015 Craig Small <csmall@enc.com.au>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <proc/diskstat.h>
|
||||
#include "procps-private.h"
|
||||
|
||||
#define DISKSTAT_LINE_LEN 1024
|
||||
#define DISKSTAT_NAME_LEN 15
|
||||
#define DISKSTAT_FILE "/proc/diskstats"
|
||||
#define SYSBLOCK_DIR "/sys/block"
|
||||
|
||||
struct procps_diskstat_dev {
|
||||
char name[DISKSTAT_NAME_LEN];
|
||||
int is_disk;
|
||||
unsigned long reads;
|
||||
unsigned long reads_merged;
|
||||
unsigned long read_sectors;
|
||||
unsigned long read_time;
|
||||
unsigned long writes;
|
||||
unsigned long writes_merged;
|
||||
unsigned long write_sectors;
|
||||
unsigned long write_time;
|
||||
unsigned long io_inprogress;
|
||||
unsigned long io_time;
|
||||
unsigned long io_wtime;
|
||||
};
|
||||
|
||||
struct procps_diskstat {
|
||||
int refcount;
|
||||
FILE *diskstat_fp;
|
||||
struct procps_diskstat_dev *devs;
|
||||
int devs_alloc;
|
||||
int devs_used;
|
||||
};
|
||||
|
||||
/*
|
||||
* scan_for_disks:
|
||||
*
|
||||
* All disks start off as partitions. This function
|
||||
* scans /sys/block and changes all devices found there
|
||||
* into disks. If /sys/block cannot have the directory
|
||||
* read, all devices are disks
|
||||
*/
|
||||
static int scan_for_disks(struct procps_diskstat *info)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent *dent;
|
||||
int myerrno, i;
|
||||
|
||||
if ((dirp = opendir(SYSBLOCK_DIR)) == NULL) {
|
||||
myerrno = errno;
|
||||
if (myerrno != ENOENT && myerrno != EACCES)
|
||||
return -myerrno;
|
||||
/* Cannot open the dir or perm denied, make all devs disks */
|
||||
for (i=0 ; i < info->devs_used; i++)
|
||||
info->devs[i].is_disk = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while((dent = readdir(dirp)) != NULL) {
|
||||
for (i=0; i < info->devs_used; i++)
|
||||
if (strcmp(dent->d_name, info->devs[i].name) == 0) {
|
||||
info->devs[i].is_disk = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void diskstat_clear(struct procps_diskstat *info)
|
||||
{
|
||||
if (info == NULL)
|
||||
return;
|
||||
if (info->devs != NULL && info->devs_alloc > 0) {
|
||||
memset(info->devs, 0, sizeof(struct procps_diskstat_dev)*info->devs_alloc);
|
||||
info->devs_used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int diskdata_alloc(
|
||||
struct procps_diskstat *info)
|
||||
{
|
||||
struct procps_diskstat_dev *new_disks;
|
||||
int new_count;
|
||||
|
||||
if (info == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->devs_used < info->devs_alloc)
|
||||
return 0;
|
||||
|
||||
/* Increment the allocated number of slabs */
|
||||
new_count = info->devs_alloc * 5/4+30;
|
||||
|
||||
if ((new_disks = realloc(info->devs,
|
||||
sizeof(struct procps_diskstat_dev)*new_count)) == NULL)
|
||||
return -ENOMEM;
|
||||
info->devs = new_disks;
|
||||
info->devs_alloc = new_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_disk(
|
||||
struct procps_diskstat *info,
|
||||
struct procps_diskstat_dev **node)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!info)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->devs_used == info->devs_alloc) {
|
||||
if ((retval = diskdata_alloc(info)) < 0)
|
||||
return retval;
|
||||
}
|
||||
*node = &(info->devs[info->devs_used++]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* procps_diskstat_new:
|
||||
*
|
||||
* Create a new container to hold the diskstat information
|
||||
*
|
||||
* The initial refcount is 1, and needs to be decremented
|
||||
* to release the resources of the structure.
|
||||
*
|
||||
* Returns: a new procps_diskstat container
|
||||
*/
|
||||
PROCPS_EXPORT int procps_diskstat_new (
|
||||
struct procps_diskstat **info)
|
||||
{
|
||||
struct procps_diskstat *ds;
|
||||
ds = calloc(1, sizeof(struct procps_diskstat));
|
||||
if (!ds)
|
||||
return -ENOMEM;
|
||||
|
||||
ds->refcount = 1;
|
||||
ds->diskstat_fp = NULL;
|
||||
*info = ds;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* procps_diskstat_read:
|
||||
*
|
||||
* @info: info structure created at procps_diskstat_new
|
||||
*
|
||||
* Read the data out of /proc/diskstats putting the information
|
||||
* into the supplied info structure
|
||||
*
|
||||
* Returns: 0 on success, negative on error
|
||||
*/
|
||||
PROCPS_EXPORT int procps_diskstat_read (
|
||||
struct procps_diskstat *info)
|
||||
{
|
||||
int retval, is_disk;
|
||||
char buf[DISKSTAT_LINE_LEN];
|
||||
char devname[DISKSTAT_NAME_LEN];
|
||||
struct procps_diskstat_dev *disk;
|
||||
|
||||
/* clear/zero structures */
|
||||
diskstat_clear(info);
|
||||
|
||||
if (NULL == info->diskstat_fp &&
|
||||
NULL == (info->diskstat_fp = fopen(DISKSTAT_FILE, "r")))
|
||||
return -errno;
|
||||
|
||||
if (fseek(info->diskstat_fp, 0L, SEEK_SET) == -1)
|
||||
return -errno;
|
||||
|
||||
while (fgets(buf, DISKSTAT_LINE_LEN, info->diskstat_fp)) {
|
||||
if (sscanf(buf,
|
||||
"%*d %*d %" STRINGIFY(DISKSTAT_NAME_LEN) "s",
|
||||
devname) < 1) {
|
||||
if (errno != 0)
|
||||
return -errno;
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((retval = get_disk(info, &disk)) < 0)
|
||||
return retval;
|
||||
if (sscanf(buf, " %*d %*d %*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
|
||||
&disk->reads, &disk->reads_merged, &disk->read_sectors,
|
||||
&disk->read_time,
|
||||
&disk->writes, &disk->writes_merged, &disk->write_sectors,
|
||||
&disk->write_time,
|
||||
&disk->io_inprogress, &disk->io_time, &disk->io_wtime) != 11) {
|
||||
if (errno != 0)
|
||||
return -errno;
|
||||
return -EINVAL;
|
||||
}
|
||||
disk->is_disk = 0; /* default to no until we scan */
|
||||
strcpy(disk->name, devname);
|
||||
}
|
||||
if ((retval = scan_for_disks(info)) < 0)
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* procps_diskstat_dev_count:
|
||||
*
|
||||
* @info: structure that has been read
|
||||
*
|
||||
* Returns: number of devices (disk+partitions)
|
||||
*/
|
||||
PROCPS_EXPORT int procps_diskstat_dev_count (
|
||||
const struct procps_diskstat *info)
|
||||
{
|
||||
if (!info)
|
||||
return -EINVAL;
|
||||
return info->devs_used;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* procps_diskstat_dev_getbyname
|
||||
*
|
||||
* @info: diskstat data already read
|
||||
* @name: name of partition
|
||||
*
|
||||
* Find the device index by the name
|
||||
*
|
||||
* Returns: devid if found
|
||||
* -1 if not found
|
||||
*/
|
||||
PROCPS_EXPORT int procps_diskstat_dev_getbyname(
|
||||
const struct procps_diskstat *info,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info == NULL || info->devs_used == 0)
|
||||
return -1;
|
||||
for (i=0; i < info->devs_used; i++)
|
||||
if (strcmp(info->devs[i].name, name) == 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
PROCPS_EXPORT unsigned long procps_diskstat_dev_get(
|
||||
const struct procps_diskstat *info,
|
||||
const enum procps_diskstat_devitem item,
|
||||
const unsigned int devid)
|
||||
{
|
||||
if (info == NULL)
|
||||
return 0;
|
||||
if (devid > info->devs_used)
|
||||
return 0;
|
||||
switch(item) {
|
||||
case PROCPS_DISKSTAT_READS:
|
||||
return info->devs[devid].reads;
|
||||
case PROCPS_DISKSTAT_READS_MERGED:
|
||||
return info->devs[devid].reads_merged;
|
||||
case PROCPS_DISKSTAT_READ_SECTORS:
|
||||
return info->devs[devid].read_sectors;
|
||||
case PROCPS_DISKSTAT_READ_TIME:
|
||||
return info->devs[devid].read_time;
|
||||
case PROCPS_DISKSTAT_WRITES:
|
||||
return info->devs[devid].writes;
|
||||
case PROCPS_DISKSTAT_WRITES_MERGED:
|
||||
return info->devs[devid].writes_merged;
|
||||
case PROCPS_DISKSTAT_WRITE_SECTORS:
|
||||
return info->devs[devid].write_sectors;
|
||||
case PROCPS_DISKSTAT_WRITE_TIME:
|
||||
return info->devs[devid].write_time;
|
||||
case PROCPS_DISKSTAT_IO_INPROGRESS:
|
||||
return info->devs[devid].io_inprogress;
|
||||
case PROCPS_DISKSTAT_IO_TIME:
|
||||
return info->devs[devid].io_time;
|
||||
case PROCPS_DISKSTAT_IO_WTIME:
|
||||
return info->devs[devid].io_wtime;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PROCPS_EXPORT char* procps_diskstat_dev_getname(
|
||||
const struct procps_diskstat *info,
|
||||
const unsigned int devid)
|
||||
{
|
||||
if (info == NULL)
|
||||
return 0;
|
||||
if (devid > info->devs_used)
|
||||
return 0;
|
||||
return info->devs[devid].name;
|
||||
}
|
||||
|
||||
PROCPS_EXPORT int procps_diskstat_dev_isdisk(
|
||||
const struct procps_diskstat *info,
|
||||
const unsigned int devid)
|
||||
{
|
||||
if (info == NULL || devid > info->devs_used)
|
||||
return -EINVAL;
|
||||
|
||||
return info->devs[devid].is_disk;
|
||||
}
|
70
proc/diskstat.h
Normal file
70
proc/diskstat.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* diskstat - Disk statistics - part of procps
|
||||
*
|
||||
* Copyright (c) 2003 Fabian Frederick
|
||||
* Copyright (C) 2003 Albert Cahalan
|
||||
* Copyright (C) 2015 Craig Small <csmall@enc.com.au>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef PROC_DISKSTAT_H
|
||||
#define PROC_DISKSTAT_H
|
||||
|
||||
#include <proc/procps.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
enum procps_diskstat_devitem {
|
||||
PROCPS_DISKSTAT_READS,
|
||||
PROCPS_DISKSTAT_READS_MERGED,
|
||||
PROCPS_DISKSTAT_READ_SECTORS,
|
||||
PROCPS_DISKSTAT_READ_TIME,
|
||||
PROCPS_DISKSTAT_WRITES,
|
||||
PROCPS_DISKSTAT_WRITES_MERGED,
|
||||
PROCPS_DISKSTAT_WRITE_SECTORS,
|
||||
PROCPS_DISKSTAT_WRITE_TIME,
|
||||
PROCPS_DISKSTAT_IO_INPROGRESS,
|
||||
PROCPS_DISKSTAT_IO_TIME,
|
||||
PROCPS_DISKSTAT_IO_WTIME
|
||||
};
|
||||
|
||||
struct procps_diskstat;
|
||||
struct procps_diskstat_dev;
|
||||
|
||||
int procps_diskstat_new (struct procps_diskstat **info);
|
||||
int procps_diskstat_read (struct procps_diskstat *info);
|
||||
|
||||
int procps_diskstat_ref (struct procps_diskstat *info);
|
||||
int procps_diskstat_unref (struct procps_diskstat **info);
|
||||
|
||||
int procps_diskstat_dev_count (const struct procps_diskstat *info);
|
||||
int procps_diskstat_dev_getbyname(
|
||||
const struct procps_diskstat *info,
|
||||
const char *name);
|
||||
|
||||
unsigned long procps_diskstat_dev_get(
|
||||
const struct procps_diskstat *info,
|
||||
const enum procps_diskstat_devitem item,
|
||||
const unsigned int devid);
|
||||
|
||||
char* procps_diskstat_dev_getname(
|
||||
const struct procps_diskstat *info,
|
||||
const unsigned int devid);
|
||||
|
||||
int procps_diskstat_dev_isdisk(
|
||||
const struct procps_diskstat *info,
|
||||
const unsigned int devid);
|
||||
__END_DECLS
|
||||
#endif
|
@ -12,7 +12,6 @@ global:
|
||||
get_ns_name;
|
||||
get_pid_digits;
|
||||
get_slabinfo;
|
||||
getdiskstat;
|
||||
getslabinfo;
|
||||
look_up_our_self;
|
||||
lookup_wchan;
|
||||
@ -27,6 +26,15 @@ global:
|
||||
tty_to_dev;
|
||||
user_from_uid;
|
||||
procps_cpu_count;
|
||||
procps_diskstat_dev_count;
|
||||
procps_diskstat_dev_get;
|
||||
procps_diskstat_dev_getbyname;
|
||||
procps_diskstat_dev_getname;
|
||||
procps_diskstat_dev_isdisk;
|
||||
procps_diskstat_new;
|
||||
procps_diskstat_read;
|
||||
procps_diskstat_ref;
|
||||
procps_diskstat_unref;
|
||||
procps_hertz_get;
|
||||
procps_linux_version;
|
||||
procps_loadavg;
|
||||
|
@ -2,7 +2,7 @@
|
||||
* File for parsing top-level /proc entities.
|
||||
* Copyright (C) 1992-1998 by Michael K. Johnson, johnsonm@redhat.com
|
||||
* Copyright 1998-2003 Albert Cahalan
|
||||
* June 2003, Fabian Frederick, disk and slab info
|
||||
* June 2003, Fabian Frederick, slab info
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -154,86 +154,6 @@ static void crash(const char *filename) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
static int is_disk(char *dev)
|
||||
{
|
||||
char syspath[32];
|
||||
char *slash;
|
||||
|
||||
while ((slash = strchr(dev, '/')))
|
||||
*slash = '!';
|
||||
snprintf(syspath, sizeof(syspath), "/sys/block/%s", dev);
|
||||
return !(access(syspath, F_OK));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int getdiskstat(struct disk_stat **disks, struct partition_stat **partitions){
|
||||
FILE* fd;
|
||||
int cDisk = 0;
|
||||
int cPartition = 0;
|
||||
int fields;
|
||||
unsigned dummy;
|
||||
char devname[32];
|
||||
|
||||
*disks = NULL;
|
||||
*partitions = NULL;
|
||||
buff[BUFFSIZE-1] = 0;
|
||||
fd = fopen("/proc/diskstats", "rb");
|
||||
if(!fd) crash("/proc/diskstats");
|
||||
|
||||
for (;;) {
|
||||
if (!fgets(buff,BUFFSIZE-1,fd)){
|
||||
fclose(fd);
|
||||
break;
|
||||
}
|
||||
fields = sscanf(buff, " %*d %*d %15s %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %u", devname, &dummy);
|
||||
if (fields == 2 && is_disk(devname)){
|
||||
(*disks) = xrealloc(*disks, (cDisk+1)*sizeof(struct disk_stat));
|
||||
sscanf(buff, " %*d %*d %15s %u %u %llu %u %u %u %llu %u %u %u %u",
|
||||
//&disk_major,
|
||||
//&disk_minor,
|
||||
(*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
|
||||
);
|
||||
(*disks)[cDisk].partitions=0;
|
||||
cDisk++;
|
||||
}else{
|
||||
(*partitions) = xrealloc(*partitions, (cPartition+1)*sizeof(struct partition_stat));
|
||||
fflush(stdout);
|
||||
sscanf(buff, (fields == 2)
|
||||
? " %*d %*d %15s %u %*u %llu %*u %u %*u %llu %*u %*u %*u %*u"
|
||||
: " %*d %*d %15s %u %llu %u %llu",
|
||||
//&part_major,
|
||||
//&part_minor,
|
||||
(*partitions)[cPartition].partition_name,
|
||||
&(*partitions)[cPartition].reads,
|
||||
&(*partitions)[cPartition].reads_sectors,
|
||||
&(*partitions)[cPartition].writes,
|
||||
&(*partitions)[cPartition].requested_writes
|
||||
);
|
||||
|
||||
if (cDisk > 0) {
|
||||
(*partitions)[cPartition++].parent_disk = cDisk-1;
|
||||
(*disks)[cDisk-1].partitions++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cDisk;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// based on Fabian Frederick's /proc/slabinfo parser
|
||||
|
||||
|
@ -15,33 +15,6 @@ int procps_loadavg(double *av1, double *av5, double *av15);
|
||||
#define BUFFSIZE (64*1024)
|
||||
typedef unsigned long long jiff;
|
||||
|
||||
typedef struct disk_stat{
|
||||
unsigned long long reads_sectors;
|
||||
unsigned long long written_sectors;
|
||||
char disk_name [16];
|
||||
unsigned inprogress_IO;
|
||||
unsigned merged_reads;
|
||||
unsigned merged_writes;
|
||||
unsigned milli_reading;
|
||||
unsigned milli_spent_IO;
|
||||
unsigned milli_writing;
|
||||
unsigned partitions;
|
||||
unsigned reads;
|
||||
unsigned weighted_milli_spent_IO;
|
||||
unsigned writes;
|
||||
}disk_stat;
|
||||
|
||||
typedef struct partition_stat{
|
||||
char partition_name [16];
|
||||
unsigned long long reads_sectors;
|
||||
unsigned parent_disk; // index into a struct disk_stat array
|
||||
unsigned reads;
|
||||
unsigned writes;
|
||||
unsigned long long requested_writes;
|
||||
}partition_stat;
|
||||
|
||||
extern unsigned int getdiskstat (struct disk_stat**,struct partition_stat**);
|
||||
|
||||
typedef struct slab_cache{
|
||||
char name[48];
|
||||
unsigned active_objs;
|
||||
|
446
vmstat.c
446
vmstat.c
@ -53,6 +53,7 @@
|
||||
#include <proc/vmstat.h>
|
||||
#include <proc/readstat.h>
|
||||
#include <proc/meminfo.h>
|
||||
#include <proc/diskstat.h>
|
||||
|
||||
#define UNIT_B 1
|
||||
#define UNIT_k 1000
|
||||
@ -83,7 +84,7 @@ static int t_option;
|
||||
|
||||
static unsigned sleep_time = 1;
|
||||
static int infinite_updates = 0;
|
||||
static unsigned long num_updates;
|
||||
static unsigned long num_updates =1;
|
||||
/* window height */
|
||||
static unsigned int height;
|
||||
static unsigned int moreheaders = TRUE;
|
||||
@ -199,19 +200,6 @@ static void new_header(void)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// based on Fabian Frederick's /proc/diskstats parser
|
||||
|
||||
static unsigned int getpartitions_num(struct disk_stat *disks, int ndisks)
|
||||
{
|
||||
unsigned int i;
|
||||
int partitions=0;
|
||||
|
||||
for (i=0; i<ndisks; i++) {
|
||||
partitions+=disks[i].partitions;
|
||||
}
|
||||
return partitions;
|
||||
}
|
||||
|
||||
static unsigned long unitConvert(unsigned long size)
|
||||
{
|
||||
@ -444,227 +432,165 @@ static void diskpartition_header(const char *partition_name)
|
||||
|
||||
static int diskpartition_format(const char *partition_name)
|
||||
{
|
||||
FILE *fDiskstat;
|
||||
struct disk_stat *disks;
|
||||
struct partition_stat *partitions, *current_partition = NULL;
|
||||
unsigned long ndisks, j, k, npartitions;
|
||||
const char format[] = "%20u %10llu %10u %10llu\n";
|
||||
#define PARTGET(x) procps_diskstat_dev_get(disk_stat, (x), partid)
|
||||
struct procps_diskstat *disk_stat;
|
||||
const char format[] = "%20u %10llu %10u %10llu\n";
|
||||
int i, partid;
|
||||
|
||||
fDiskstat = fopen("/proc/diskstats", "rb");
|
||||
if (!fDiskstat)
|
||||
xerrx(EXIT_FAILURE,
|
||||
_("your kernel does not support diskstat. (2.5.70 or above required)"));
|
||||
if (procps_diskstat_new(&disk_stat) < 0)
|
||||
xerr(EXIT_FAILURE,
|
||||
_("Unable to create diskstat structure"));
|
||||
|
||||
fclose(fDiskstat);
|
||||
ndisks = getdiskstat(&disks, &partitions);
|
||||
npartitions = getpartitions_num(disks, ndisks);
|
||||
for (k = 0; k < npartitions; k++) {
|
||||
if (!strcmp(partition_name, partitions[k].partition_name)) {
|
||||
current_partition = &(partitions[k]);
|
||||
}
|
||||
}
|
||||
if (!current_partition) {
|
||||
free(disks);
|
||||
free(partitions);
|
||||
return -1;
|
||||
}
|
||||
diskpartition_header(partition_name);
|
||||
printf(format,
|
||||
current_partition->reads, current_partition->reads_sectors,
|
||||
current_partition->writes, current_partition->requested_writes);
|
||||
fflush(stdout);
|
||||
free(disks);
|
||||
free(partitions);
|
||||
for (j = 1; infinite_updates || j < num_updates; j++) {
|
||||
if (moreheaders && ((j % height) == 0))
|
||||
diskpartition_header(partition_name);
|
||||
sleep(sleep_time);
|
||||
ndisks = getdiskstat(&disks, &partitions);
|
||||
npartitions = getpartitions_num(disks, ndisks);
|
||||
current_partition = NULL;
|
||||
for (k = 0; k < npartitions; k++) {
|
||||
if (!strcmp
|
||||
(partition_name, partitions[k].partition_name)) {
|
||||
current_partition = &(partitions[k]);
|
||||
}
|
||||
}
|
||||
if (!current_partition) {
|
||||
free(disks);
|
||||
free(partitions);
|
||||
return -1;
|
||||
}
|
||||
printf(format,
|
||||
current_partition->reads,
|
||||
current_partition->reads_sectors,
|
||||
current_partition->writes,
|
||||
current_partition->requested_writes);
|
||||
fflush(stdout);
|
||||
free(disks);
|
||||
free(partitions);
|
||||
}
|
||||
return 0;
|
||||
if (procps_diskstat_read(disk_stat) < 0)
|
||||
xerr(EXIT_FAILURE,
|
||||
_("Unable to read diskstat"));
|
||||
if ((partid = procps_diskstat_dev_getbyname(disk_stat, partition_name))
|
||||
< 0)
|
||||
xerrx(EXIT_FAILURE, _("Partition %s not found"), partition_name);
|
||||
|
||||
diskpartition_header(partition_name);
|
||||
for (i=0; infinite_updates || i < num_updates ; i++) {
|
||||
if (procps_diskstat_read(disk_stat) < 0)
|
||||
xerr(EXIT_FAILURE,
|
||||
_("Unable to read diskstat"));
|
||||
if ((partid = procps_diskstat_dev_getbyname(disk_stat, partition_name))
|
||||
< 0)
|
||||
xerrx(EXIT_FAILURE,
|
||||
_("Partition %s not found"), partition_name);
|
||||
|
||||
printf(format,
|
||||
PARTGET(PROCPS_DISKSTAT_READS),
|
||||
PARTGET(PROCPS_DISKSTAT_READ_SECTORS),
|
||||
PARTGET(PROCPS_DISKSTAT_WRITES),
|
||||
PARTGET(PROCPS_DISKSTAT_WRITE_SECTORS)
|
||||
);
|
||||
|
||||
if (infinite_updates || i+1 < num_updates)
|
||||
sleep(sleep_time);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void diskheader(void)
|
||||
{
|
||||
struct tm *tm_ptr;
|
||||
time_t the_time;
|
||||
char timebuf[32];
|
||||
struct tm *tm_ptr;
|
||||
time_t the_time;
|
||||
char timebuf[32];
|
||||
|
||||
/* Translation Hint: Translating folloging header & fields
|
||||
* that follow (marked with max x chars) might not work,
|
||||
* unless manual page is translated as well. */
|
||||
const char *header =
|
||||
_("disk- ------------reads------------ ------------writes----------- -----IO------");
|
||||
const char *wide_header =
|
||||
_("disk- -------------------reads------------------- -------------------writes------------------ ------IO-------");
|
||||
const char *timestamp_header = _(" -----timestamp-----");
|
||||
/* Translation Hint: Translating folloging header & fields
|
||||
* that follow (marked with max x chars) might not work,
|
||||
* unless manual page is translated as well. */
|
||||
const char *header =
|
||||
_("disk- ------------reads------------ ------------writes----------- -----IO------");
|
||||
const char *wide_header =
|
||||
_("disk- -------------------reads------------------- -------------------writes------------------ ------IO-------");
|
||||
const char *timestamp_header = _(" -----timestamp-----");
|
||||
|
||||
const char format[] =
|
||||
"%5s %6s %6s %7s %7s %6s %6s %7s %7s %6s %6s";
|
||||
const char wide_format[] =
|
||||
"%5s %9s %9s %11s %11s %9s %9s %11s %11s %7s %7s";
|
||||
const char format[] =
|
||||
"%5s %6s %6s %7s %7s %6s %6s %7s %7s %6s %6s";
|
||||
const char wide_format[] =
|
||||
"%5s %9s %9s %11s %11s %9s %9s %11s %11s %7s %7s";
|
||||
|
||||
printf("%s", w_option ? wide_header : header);
|
||||
printf("%s", w_option ? wide_header : header);
|
||||
|
||||
if (t_option) {
|
||||
printf("%s", timestamp_header);
|
||||
}
|
||||
if (t_option) {
|
||||
printf("%s", timestamp_header);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
|
||||
printf(w_option ? wide_format : format,
|
||||
" ",
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("total"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("merged"),
|
||||
/* Translation Hint: max 7 chars */
|
||||
_("sectors"),
|
||||
/* Translation Hint: max 7 chars */
|
||||
_("ms"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("total"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("merged"),
|
||||
/* Translation Hint: max 7 chars */
|
||||
_("sectors"),
|
||||
/* Translation Hint: max 7 chars */
|
||||
_("ms"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("cur"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("sec"));
|
||||
printf(w_option ? wide_format : format,
|
||||
" ",
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("total"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("merged"),
|
||||
/* Translation Hint: max 7 chars */
|
||||
_("sectors"),
|
||||
/* Translation Hint: max 7 chars */
|
||||
_("ms"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("total"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("merged"),
|
||||
/* Translation Hint: max 7 chars */
|
||||
_("sectors"),
|
||||
/* Translation Hint: max 7 chars */
|
||||
_("ms"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("cur"),
|
||||
/* Translation Hint: max 6 chars */
|
||||
_("sec"));
|
||||
|
||||
if (t_option) {
|
||||
(void) time( &the_time );
|
||||
tm_ptr = localtime( &the_time );
|
||||
if (strftime(timebuf, sizeof(timebuf), "%Z", tm_ptr)) {
|
||||
timebuf[strlen(timestamp_header) - 1] = '\0';
|
||||
} else {
|
||||
timebuf[0] = '\0';
|
||||
}
|
||||
printf(" %*s", (int)(strlen(timestamp_header) - 1), timebuf);
|
||||
}
|
||||
if (t_option) {
|
||||
(void) time( &the_time );
|
||||
tm_ptr = localtime( &the_time );
|
||||
if (strftime(timebuf, sizeof(timebuf), "%Z", tm_ptr)) {
|
||||
timebuf[strlen(timestamp_header) - 1] = '\0';
|
||||
} else {
|
||||
timebuf[0] = '\0';
|
||||
}
|
||||
printf(" %*s", (int)(strlen(timestamp_header) - 1), timebuf);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void diskformat(void)
|
||||
{
|
||||
const char format[] =
|
||||
"%-5s %6u %6u %7llu %7u %6u %6u %7llu %7u %6u %6u";
|
||||
const char wide_format[] =
|
||||
"%-5s %9u %9u %11llu %11u %9u %9u %11llu %11u %7u %7u";
|
||||
#define DSTAT(x) procps_diskstat_dev_get(disk_stat, (x), diskid)
|
||||
struct procps_diskstat *disk_stat;
|
||||
int i,diskid, disk_count;
|
||||
time_t the_time;
|
||||
struct tm *tm_ptr;
|
||||
char timebuf[32];
|
||||
const char format[] = "%-5s %6u %6u %7llu %7u %6u %6u %7llu %7u %6u %6u";
|
||||
const char wide_format[] = "%-5s %9u %9u %11llu %11u %9u %9u %11llu %11u %7u %7u";
|
||||
|
||||
FILE *fDiskstat;
|
||||
struct disk_stat *disks;
|
||||
struct partition_stat *partitions;
|
||||
unsigned long ndisks, i, j, k;
|
||||
struct tm *tm_ptr;
|
||||
time_t the_time;
|
||||
char timebuf[32];
|
||||
if (procps_diskstat_new(&disk_stat) < 0)
|
||||
xerr(EXIT_FAILURE,
|
||||
_("Unable to create diskstat structure"));
|
||||
|
||||
if (!moreheaders)
|
||||
diskheader();
|
||||
for (i=0; infinite_updates || i < num_updates ; i++) {
|
||||
if (procps_diskstat_read(disk_stat) < 0)
|
||||
xerr(EXIT_FAILURE,
|
||||
_("Unable to read diskstat data"));
|
||||
|
||||
if ((fDiskstat = fopen("/proc/diskstats", "rb"))) {
|
||||
fclose(fDiskstat);
|
||||
ndisks = getdiskstat(&disks, &partitions);
|
||||
|
||||
if (t_option) {
|
||||
(void) time( &the_time );
|
||||
tm_ptr = localtime( &the_time );
|
||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
|
||||
}
|
||||
|
||||
if (!moreheaders)
|
||||
diskheader();
|
||||
for (k = 0; k < ndisks; k++) {
|
||||
if (moreheaders && ((k % height) == 0))
|
||||
diskheader();
|
||||
printf(w_option ? wide_format : 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);
|
||||
|
||||
if (t_option) {
|
||||
printf(" %s", timebuf);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
free(disks);
|
||||
free(partitions);
|
||||
|
||||
for (j = 1; infinite_updates || j < num_updates; j++) {
|
||||
sleep(sleep_time);
|
||||
ndisks = getdiskstat(&disks, &partitions);
|
||||
|
||||
if (t_option) {
|
||||
(void) time( &the_time );
|
||||
tm_ptr = localtime( &the_time );
|
||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
|
||||
}
|
||||
|
||||
for (i = 0; i < ndisks; i++, k++) {
|
||||
if (moreheaders && ((k % height) == 0))
|
||||
diskheader();
|
||||
printf(w_option ? wide_format : 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);
|
||||
|
||||
if (t_option) {
|
||||
printf(" %s", timebuf);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
free(disks);
|
||||
free(partitions);
|
||||
}
|
||||
} else
|
||||
xerrx(EXIT_FAILURE,
|
||||
_("your kernel does not support diskstat (2.5.70 or above required)"));
|
||||
if (t_option) {
|
||||
(void) time( &the_time );
|
||||
tm_ptr = localtime( &the_time );
|
||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
|
||||
}
|
||||
disk_count = procps_diskstat_dev_count(disk_stat);
|
||||
for (diskid = 0; diskid < disk_count; diskid++) {
|
||||
if (procps_diskstat_dev_isdisk(disk_stat, diskid) != 1)
|
||||
continue; /* not a disk */
|
||||
if (moreheaders && ((diskid % height) == 0))
|
||||
diskheader();
|
||||
printf(w_option ? wide_format : format,
|
||||
procps_diskstat_dev_getname(disk_stat, diskid),
|
||||
DSTAT(PROCPS_DISKSTAT_READS),
|
||||
DSTAT(PROCPS_DISKSTAT_READS_MERGED),
|
||||
DSTAT(PROCPS_DISKSTAT_READ_SECTORS),
|
||||
DSTAT(PROCPS_DISKSTAT_READ_TIME),
|
||||
DSTAT(PROCPS_DISKSTAT_WRITES),
|
||||
DSTAT(PROCPS_DISKSTAT_WRITES_MERGED),
|
||||
DSTAT(PROCPS_DISKSTAT_WRITE_SECTORS),
|
||||
DSTAT(PROCPS_DISKSTAT_WRITE_TIME),
|
||||
DSTAT(PROCPS_DISKSTAT_IO_INPROGRESS) / 1000,
|
||||
DSTAT(PROCPS_DISKSTAT_IO_TIME) / 1000);
|
||||
if (t_option)
|
||||
printf(" %s\n", timebuf);
|
||||
else
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
if (infinite_updates || i+1 < num_updates)
|
||||
sleep(sleep_time);
|
||||
}
|
||||
#undef DSTAT
|
||||
}
|
||||
|
||||
static void slabheader(void)
|
||||
@ -730,53 +656,63 @@ static void slabformat(void)
|
||||
|
||||
static void disksum_format(void)
|
||||
{
|
||||
#define DSTAT(x) procps_diskstat_dev_get(disk_stat, (x), devid)
|
||||
struct procps_diskstat *disk_stat;
|
||||
|
||||
FILE *fDiskstat;
|
||||
struct disk_stat *disks;
|
||||
struct partition_stat *partitions;
|
||||
int ndisks, i;
|
||||
unsigned long reads, merged_reads, read_sectors, milli_reading, writes,
|
||||
merged_writes, written_sectors, milli_writing, inprogress_IO,
|
||||
milli_spent_IO, weighted_milli_spent_IO;
|
||||
if (procps_diskstat_new(&disk_stat) < 0)
|
||||
xerr(EXIT_FAILURE,
|
||||
_("Unable to create diskstat structure"));
|
||||
|
||||
reads = merged_reads = read_sectors = milli_reading = writes =
|
||||
merged_writes = written_sectors = milli_writing = inprogress_IO =
|
||||
milli_spent_IO = weighted_milli_spent_IO = 0;
|
||||
if (procps_diskstat_read(disk_stat) < 0)
|
||||
xerr(EXIT_FAILURE,
|
||||
_("Unable to read diskstat"));
|
||||
|
||||
if ((fDiskstat = fopen("/proc/diskstats", "rb"))) {
|
||||
fclose(fDiskstat);
|
||||
ndisks = getdiskstat(&disks, &partitions);
|
||||
printf(_("%13d disks \n"), ndisks);
|
||||
printf(_("%13d partitions \n"),
|
||||
getpartitions_num(disks, ndisks));
|
||||
int devid, dev_count, disk_count, part_count ;
|
||||
unsigned long reads, merged_reads, read_sectors, milli_reading, writes,
|
||||
merged_writes, written_sectors, milli_writing, inprogress_IO,
|
||||
milli_spent_IO, weighted_milli_spent_IO;
|
||||
|
||||
for (i = 0; i < ndisks; i++) {
|
||||
reads += disks[i].reads;
|
||||
merged_reads += disks[i].merged_reads;
|
||||
read_sectors += disks[i].reads_sectors;
|
||||
milli_reading += disks[i].milli_reading;
|
||||
writes += disks[i].writes;
|
||||
merged_writes += disks[i].merged_writes;
|
||||
written_sectors += disks[i].written_sectors;
|
||||
milli_writing += disks[i].milli_writing;
|
||||
inprogress_IO += disks[i].inprogress_IO ? disks[i].inprogress_IO / 1000 : 0;
|
||||
milli_spent_IO += disks[i].milli_spent_IO ? disks[i].milli_spent_IO / 1000 : 0;
|
||||
}
|
||||
reads = merged_reads = read_sectors = milli_reading = writes =
|
||||
merged_writes = written_sectors = milli_writing = inprogress_IO =
|
||||
milli_spent_IO = weighted_milli_spent_IO = 0;
|
||||
disk_count = part_count = 0;
|
||||
|
||||
printf(_("%13lu total reads\n"), reads);
|
||||
printf(_("%13lu merged reads\n"), merged_reads);
|
||||
printf(_("%13lu read sectors\n"), read_sectors);
|
||||
printf(_("%13lu milli reading\n"), milli_reading);
|
||||
printf(_("%13lu writes\n"), writes);
|
||||
printf(_("%13lu merged writes\n"), merged_writes);
|
||||
printf(_("%13lu written sectors\n"), written_sectors);
|
||||
printf(_("%13lu milli writing\n"), milli_writing);
|
||||
printf(_("%13lu inprogress IO\n"), inprogress_IO);
|
||||
printf(_("%13lu milli spent IO\n"), milli_spent_IO);
|
||||
if ((dev_count = procps_diskstat_dev_count(disk_stat)) < 0)
|
||||
xerr(EXIT_FAILURE,
|
||||
_("Unable to count diskstat devices"));
|
||||
|
||||
free(disks);
|
||||
free(partitions);
|
||||
}
|
||||
for (devid=0; devid < dev_count; devid++) {
|
||||
if (procps_diskstat_dev_isdisk(disk_stat, devid) != 1) {
|
||||
part_count++;
|
||||
continue; /* not a disk */
|
||||
}
|
||||
disk_count++;
|
||||
reads += DSTAT(PROCPS_DISKSTAT_READS);
|
||||
merged_reads += DSTAT(PROCPS_DISKSTAT_READS_MERGED);
|
||||
read_sectors += DSTAT(PROCPS_DISKSTAT_READ_SECTORS);
|
||||
milli_reading += DSTAT(PROCPS_DISKSTAT_READ_TIME);
|
||||
writes += DSTAT(PROCPS_DISKSTAT_WRITES);
|
||||
merged_writes += DSTAT(PROCPS_DISKSTAT_WRITES_MERGED);
|
||||
written_sectors += DSTAT(PROCPS_DISKSTAT_WRITE_SECTORS);
|
||||
milli_writing += DSTAT(PROCPS_DISKSTAT_WRITE_TIME);
|
||||
inprogress_IO += DSTAT(PROCPS_DISKSTAT_IO_INPROGRESS) / 1000;
|
||||
milli_spent_IO += DSTAT(PROCPS_DISKSTAT_IO_TIME) / 1000;
|
||||
weighted_milli_spent_IO += DSTAT(PROCPS_DISKSTAT_IO_TIME) / 1000;
|
||||
}
|
||||
printf(_("%13d disks\n"), disk_count);
|
||||
printf(_("%13d partitions\n"), part_count);
|
||||
printf(_("%13lu reads\n"), reads);
|
||||
printf(_("%13lu merged reads\n"), merged_reads);
|
||||
printf(_("%13lu read sectors\n"), read_sectors);
|
||||
printf(_("%13lu milli reading\n"), milli_reading);
|
||||
printf(_("%13lu writes\n"), writes);
|
||||
printf(_("%13lu merged writes\n"), merged_writes);
|
||||
printf(_("%13lu written sectors\n"), written_sectors);
|
||||
printf(_("%13lu milli writing\n"), milli_writing);
|
||||
printf(_("%13lu inprogress IO\n"), inprogress_IO);
|
||||
printf(_("%13lu milli spent IO\n"), milli_spent_IO);
|
||||
printf(_("%13lu milli weighted IO\n"), weighted_milli_spent_IO);
|
||||
#undef DSTAT
|
||||
}
|
||||
|
||||
static void sum_format(void)
|
||||
|
Loading…
Reference in New Issue
Block a user