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:
Craig Small 2015-07-07 22:42:06 +10:00
parent 62f9a51532
commit e445f7e6c5
7 changed files with 601 additions and 364 deletions

View File

@ -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
View 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
View 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

View File

@ -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;

View File

@ -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

View File

@ -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
View File

@ -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)