/**
* collectd - src/disk.c
- * Copyright (C) 2005-2008 Florian octo Forster
+ * Copyright (C) 2005-2012 Florian octo Forster
+ * Copyright (C) 2009 Manuel Sanmartin
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
+ * Manuel Sanmartin
**/
#include "collectd.h"
# include <statgrab.h>
#endif
+#if HAVE_PERFSTAT
+# ifndef _AIXVERSION_610
+# include <sys/systemcfg.h>
+# endif
+# include <sys/protosw.h>
+# include <libperfstat.h>
+#endif
+
#if HAVE_IOKIT_IOKITLIB_H
static mach_port_t io_master_port = MACH_PORT_NULL;
+/* This defaults to false for backwards compatibility. Please fix in the next
+ * major version. */
+static _Bool use_bsd_name = 0;
/* #endif HAVE_IOKIT_IOKITLIB_H */
#elif KERNEL_LINUX
/* This overflows in roughly 1361 years */
unsigned int poll_count;
- counter_t read_sectors;
- counter_t write_sectors;
+ derive_t read_sectors;
+ derive_t write_sectors;
- counter_t read_bytes;
- counter_t write_bytes;
+ derive_t read_bytes;
+ derive_t write_bytes;
- counter_t read_ops;
- counter_t write_ops;
- counter_t read_time;
- counter_t write_time;
+ derive_t read_ops;
+ derive_t write_ops;
+ derive_t read_time;
+ derive_t write_time;
- counter_t avg_read_time;
- counter_t avg_write_time;
+ derive_t avg_read_time;
+ derive_t avg_write_time;
struct diskstats *next;
} diskstats_t;
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
-#define MAX_NUMDISK 256
+#define MAX_NUMDISK 1024
extern kstat_ctl_t *kc;
static kstat_t *ksp[MAX_NUMDISK];
static int numdisk = 0;
#elif defined(HAVE_LIBSTATGRAB)
/* #endif HAVE_LIBKSTATGRAB */
+#elif HAVE_PERFSTAT
+static perfstat_disk_t * stat_disk;
+static int numdisk;
+static int pnumdisk;
+/* #endif HAVE_PERFSTAT */
+
#else
# error "No applicable input method."
#endif
static const char *config_keys[] =
{
"Disk",
+ "UseBSDName",
"IgnoreSelected"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
else if (strcasecmp ("IgnoreSelected", key) == 0)
{
int invert = 1;
- if ((strcasecmp ("True", value) == 0)
- || (strcasecmp ("Yes", value) == 0)
- || (strcasecmp ("On", value) == 0))
+ if (IS_TRUE (value))
invert = 0;
ignorelist_set_invert (ignorelist, invert);
}
+ else if (strcasecmp ("UseBSDName", key) == 0)
+ {
+#if HAVE_IOKIT_IOKITLIB_H
+ use_bsd_name = IS_TRUE (value) ? 1 : 0;
+#else
+ WARNING ("disk plugin: The \"UseBSDName\" option is only supported "
+ "on Mach / Mac OS X and will be ignored.");
+#endif
+ }
else
{
return (-1);
{
#if HAVE_IOKIT_IOKITLIB_H
kern_return_t status;
-
+
if (io_master_port != MACH_PORT_NULL)
{
mach_port_deallocate (mach_task_self (),
static void disk_submit (const char *plugin_instance,
const char *type,
- counter_t read, counter_t write)
+ derive_t read, derive_t write)
{
value_t values[2];
value_list_t vl = VALUE_LIST_INIT;
if (ignorelist_match (ignorelist, plugin_instance) != 0)
return;
- values[0].counter = read;
- values[1].counter = write;
+ values[0].derive = read;
+ values[1].derive = write;
vl.values = values;
vl.values_len = 2;
plugin_dispatch_values (&vl);
} /* void disk_submit */
+#if KERNEL_LINUX
+static counter_t disk_calc_time_incr (counter_t delta_time, counter_t delta_ops)
+{
+ double interval = CDTIME_T_TO_DOUBLE (plugin_get_interval ());
+ double avg_time = ((double) delta_time) / ((double) delta_ops);
+ double avg_time_incr = interval * avg_time;
+
+ return ((counter_t) (avg_time_incr + .5));
+}
+#endif
+
#if HAVE_IOKIT_IOKITLIB_H
static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
{
CFDictionaryRef props_dict;
CFDictionaryRef stats_dict;
CFDictionaryRef child_dict;
- kern_return_t status;
+ CFStringRef tmp_cf_string_ref;
+ kern_return_t status;
signed long long read_ops;
signed long long read_byt;
int disk_major;
int disk_minor;
- char disk_name[64];
+ char disk_name[DATA_MAX_NAME_LEN];
+ char disk_name_bsd[DATA_MAX_NAME_LEN];
/* Get the list of all disk objects. */
if (IOServiceGetMatchingServices (io_master_port,
continue;
}
+ /* tmp_cf_string_ref doesn't need to be released. */
+ tmp_cf_string_ref = (CFStringRef) CFDictionaryGetValue (props_dict,
+ CFSTR(kIOBSDNameKey));
+ if (!tmp_cf_string_ref)
+ {
+ DEBUG ("disk plugin: CFDictionaryGetValue("
+ "kIOBSDNameKey) failed.");
+ CFRelease (props_dict);
+ IOObjectRelease (disk_child);
+ IOObjectRelease (disk);
+ continue;
+ }
+ assert (CFGetTypeID (tmp_cf_string_ref) == CFStringGetTypeID ());
+
+ memset (disk_name_bsd, 0, sizeof (disk_name_bsd));
+ CFStringGetCString (tmp_cf_string_ref,
+ disk_name_bsd, sizeof (disk_name_bsd),
+ kCFStringEncodingUTF8);
+ if (disk_name_bsd[0] == 0)
+ {
+ ERROR ("disk plugin: CFStringGetCString() failed.");
+ CFRelease (props_dict);
+ IOObjectRelease (disk_child);
+ IOObjectRelease (disk);
+ continue;
+ }
+ DEBUG ("disk plugin: disk_name_bsd = \"%s\"", disk_name_bsd);
+
stats_dict = (CFDictionaryRef) CFDictionaryGetValue (props_dict,
CFSTR (kIOBlockStorageDriverStatisticsKey));
if (stats_dict == NULL)
{
- DEBUG ("CFDictionaryGetValue (%s) failed.",
+ DEBUG ("disk plugin: CFDictionaryGetValue ("
+ "%s) failed.",
kIOBlockStorageDriverStatisticsKey);
CFRelease (props_dict);
IOObjectRelease (disk_child);
kNilOptions)
!= kIOReturnSuccess)
{
- DEBUG ("IORegistryEntryCreateCFProperties (disk_child) failed.");
+ DEBUG ("disk plugin: IORegistryEntryCreateCFProperties ("
+ "disk_child) failed.");
IOObjectRelease (disk_child);
CFRelease (props_dict);
IOObjectRelease (disk);
write_tme = dict_get_value (stats_dict,
kIOBlockStorageDriverStatisticsTotalWriteTimeKey);
- if (ssnprintf (disk_name, sizeof (disk_name),
- "%i-%i", disk_major, disk_minor) >= sizeof (disk_name))
- {
- DEBUG ("snprintf (major, minor) failed.");
- CFRelease (child_dict);
- IOObjectRelease (disk_child);
- CFRelease (props_dict);
- IOObjectRelease (disk);
- continue;
- }
- DEBUG ("disk_name = %s", disk_name);
+ if (use_bsd_name)
+ sstrncpy (disk_name, disk_name_bsd, sizeof (disk_name));
+ else
+ ssnprintf (disk_name, sizeof (disk_name), "%i-%i",
+ disk_major, disk_minor);
+ DEBUG ("disk plugin: disk_name = \"%s\"", disk_name);
if ((read_byt != -1LL) || (write_byt != -1LL))
disk_submit (disk_name, "disk_octets", read_byt, write_byt);
int numfields;
int fieldshift = 0;
- int major = 0;
int minor = 0;
- counter_t read_sectors = 0;
- counter_t write_sectors = 0;
+ derive_t read_sectors = 0;
+ derive_t write_sectors = 0;
- counter_t read_ops = 0;
- counter_t read_merged = 0;
- counter_t read_time = 0;
- counter_t write_ops = 0;
- counter_t write_merged = 0;
- counter_t write_time = 0;
+ derive_t read_ops = 0;
+ derive_t read_merged = 0;
+ derive_t read_time = 0;
+ derive_t write_ops = 0;
+ derive_t write_merged = 0;
+ derive_t write_time = 0;
int is_disk = 0;
diskstats_t *ds, *pre_ds;
if ((numfields != (14 + fieldshift)) && (numfields != 7))
continue;
- major = atoll (fields[0]);
minor = atoll (fields[1]);
disk_name = fields[2 + fieldshift];
}
{
- counter_t diff_read_sectors;
- counter_t diff_write_sectors;
+ derive_t diff_read_sectors;
+ derive_t diff_write_sectors;
/* If the counter wraps around, it's only 32 bits.. */
if (read_sectors < ds->read_sectors)
/* Calculate the average time an io-op needs to complete */
if (is_disk)
{
- counter_t diff_read_ops;
- counter_t diff_write_ops;
- counter_t diff_read_time;
- counter_t diff_write_time;
+ derive_t diff_read_ops;
+ derive_t diff_write_ops;
+ derive_t diff_read_time;
+ derive_t diff_write_time;
if (read_ops < ds->read_ops)
diff_read_ops = 1 + read_ops
+ (UINT_MAX - ds->read_ops);
else
diff_read_ops = read_ops - ds->read_ops;
- DEBUG ("disk plugin: disk_name = %s; read_ops = %llu; "
- "ds->read_ops = %llu; diff_read_ops = %llu;",
+ DEBUG ("disk plugin: disk_name = %s; read_ops = %"PRIi64"; "
+ "ds->read_ops = %"PRIi64"; diff_read_ops = %"PRIi64";",
disk_name,
read_ops, ds->read_ops, diff_read_ops);
diff_write_time = write_time - ds->write_time;
if (diff_read_ops != 0)
- ds->avg_read_time += (diff_read_time
- + (diff_read_ops / 2))
- / diff_read_ops;
+ ds->avg_read_time += disk_calc_time_incr (
+ diff_read_time, diff_read_ops);
if (diff_write_ops != 0)
- ds->avg_write_time += (diff_write_time
- + (diff_write_ops / 2))
- / diff_write_ops;
+ ds->avg_write_time += disk_calc_time_incr (
+ diff_write_time, diff_write_ops);
ds->read_ops = read_ops;
ds->read_time = read_time;
disk_submit (name, "disk_octets", ds->read_bytes, ds->write_bytes);
ds++;
}
-#endif /* defined(HAVE_LIBSTATGRAB) */
+/* #endif defined(HAVE_LIBSTATGRAB) */
+
+#elif defined(HAVE_PERFSTAT)
+ derive_t read_sectors;
+ derive_t write_sectors;
+ derive_t read_time;
+ derive_t write_time;
+ derive_t read_ops;
+ derive_t write_ops;
+ perfstat_id_t firstpath;
+ int rnumdisk;
+ int i;
+
+ if ((numdisk = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0)) < 0)
+ {
+ char errbuf[1024];
+ WARNING ("disk plugin: perfstat_disk: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ if (numdisk != pnumdisk || stat_disk==NULL) {
+ if (stat_disk!=NULL)
+ free(stat_disk);
+ stat_disk = (perfstat_disk_t *)calloc(numdisk, sizeof(perfstat_disk_t));
+ }
+ pnumdisk = numdisk;
+
+ firstpath.name[0]='\0';
+ if ((rnumdisk = perfstat_disk(&firstpath, stat_disk, sizeof(perfstat_disk_t), numdisk)) < 0)
+ {
+ char errbuf[1024];
+ WARNING ("disk plugin: perfstat_disk : %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ for (i = 0; i < rnumdisk; i++)
+ {
+ read_sectors = stat_disk[i].rblks*stat_disk[i].bsize;
+ write_sectors = stat_disk[i].wblks*stat_disk[i].bsize;
+ disk_submit (stat_disk[i].name, "disk_octets", read_sectors, write_sectors);
+
+ read_ops = stat_disk[i].xrate;
+ write_ops = stat_disk[i].xfers - stat_disk[i].xrate;
+ disk_submit (stat_disk[i].name, "disk_ops", read_ops, write_ops);
+
+ read_time = stat_disk[i].rserv;
+ read_time *= ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) / 1000000.0;
+ write_time = stat_disk[i].wserv;
+ write_time *= ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) / 1000000.0;
+ disk_submit (stat_disk[i].name, "disk_time", read_time, write_time);
+ }
+#endif /* defined(HAVE_PERFSTAT) */
return (0);
} /* int disk_read */