|
@@ -8,6 +8,7 @@
|
|
|
#include "../common-contexts/common-contexts.h"
|
|
|
|
|
|
struct logical_disk {
|
|
|
+ usec_t last_collected;
|
|
|
bool collected_metadata;
|
|
|
|
|
|
STRING *filesystem;
|
|
@@ -21,6 +22,7 @@ struct logical_disk {
|
|
|
};
|
|
|
|
|
|
struct physical_disk {
|
|
|
+ usec_t last_collected;
|
|
|
bool collected_metadata;
|
|
|
|
|
|
STRING *device;
|
|
@@ -30,11 +32,23 @@ struct physical_disk {
|
|
|
COUNTER_DATA diskReadBytesPerSec;
|
|
|
COUNTER_DATA diskWriteBytesPerSec;
|
|
|
|
|
|
+ ND_DISK_OPS disk_ops;
|
|
|
+ COUNTER_DATA diskReadsPerSec;
|
|
|
+ COUNTER_DATA diskWritesPerSec;
|
|
|
+
|
|
|
+ ND_DISK_UTIL disk_util;
|
|
|
COUNTER_DATA percentIdleTime;
|
|
|
+
|
|
|
+ ND_DISK_BUSY disk_busy;
|
|
|
COUNTER_DATA percentDiskTime;
|
|
|
+
|
|
|
+ ND_DISK_IOTIME disk_iotime;
|
|
|
COUNTER_DATA percentDiskReadTime;
|
|
|
COUNTER_DATA percentDiskWriteTime;
|
|
|
+
|
|
|
+ ND_DISK_QOPS disk_qops;
|
|
|
COUNTER_DATA currentDiskQueueLength;
|
|
|
+
|
|
|
COUNTER_DATA averageDiskQueueLength;
|
|
|
COUNTER_DATA averageDiskReadQueueLength;
|
|
|
COUNTER_DATA averageDiskWriteQueueLength;
|
|
@@ -42,8 +56,6 @@ struct physical_disk {
|
|
|
COUNTER_DATA averageDiskSecondsPerRead;
|
|
|
COUNTER_DATA averageDiskSecondsPerWrite;
|
|
|
COUNTER_DATA diskTransfersPerSec;
|
|
|
- COUNTER_DATA diskReadsPerSec;
|
|
|
- COUNTER_DATA diskWritesPerSec;
|
|
|
COUNTER_DATA diskBytesPerSec;
|
|
|
COUNTER_DATA averageDiskBytesPerTransfer;
|
|
|
COUNTER_DATA averageDiskBytesPerRead;
|
|
@@ -55,45 +67,61 @@ struct physical_disk system_physical_total = {
|
|
|
.collected_metadata = true,
|
|
|
};
|
|
|
|
|
|
-void dict_logical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
|
|
|
- struct logical_disk *ld = value;
|
|
|
+static void dict_logical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
|
|
|
+ struct logical_disk *d = value;
|
|
|
+
|
|
|
+ d->percentDiskFree.key = "% Free Space";
|
|
|
+ // d->freeMegabytes.key = "Free Megabytes";
|
|
|
+}
|
|
|
+
|
|
|
+static void logical_disk_cleanup(struct logical_disk *d) {
|
|
|
+ rrdset_is_obsolete___safe_from_collector_thread(d->st_disk_space);
|
|
|
+}
|
|
|
|
|
|
- ld->percentDiskFree.key = "% Free Space";
|
|
|
- // ld->freeMegabytes.key = "Free Megabytes";
|
|
|
+static void physical_disk_initialize(struct physical_disk *d) {
|
|
|
+ d->percentIdleTime.key = "% Idle Time";
|
|
|
+ d->percentDiskTime.key = "% Disk Time";
|
|
|
+ d->percentDiskReadTime.key = "% Disk Read Time";
|
|
|
+ d->percentDiskWriteTime.key = "% Disk Write Time";
|
|
|
+ d->currentDiskQueueLength.key = "Current Disk Queue Length";
|
|
|
+ d->averageDiskQueueLength.key = "Avg. Disk Queue Length";
|
|
|
+ d->averageDiskReadQueueLength.key = "Avg. Disk Read Queue Length";
|
|
|
+ d->averageDiskWriteQueueLength.key = "Avg. Disk Write Queue Length";
|
|
|
+ d->averageDiskSecondsPerTransfer.key = "Avg. Disk sec/Transfer";
|
|
|
+ d->averageDiskSecondsPerRead.key = "Avg. Disk sec/Read";
|
|
|
+ d->averageDiskSecondsPerWrite.key = "Avg. Disk sec/Write";
|
|
|
+ d->diskTransfersPerSec.key = "Disk Transfers/sec";
|
|
|
+ d->diskReadsPerSec.key = "Disk Reads/sec";
|
|
|
+ d->diskWritesPerSec.key = "Disk Writes/sec";
|
|
|
+ d->diskBytesPerSec.key = "Disk Bytes/sec";
|
|
|
+ d->diskReadBytesPerSec.key = "Disk Read Bytes/sec";
|
|
|
+ d->diskWriteBytesPerSec.key = "Disk Write Bytes/sec";
|
|
|
+ d->averageDiskBytesPerTransfer.key = "Avg. Disk Bytes/Transfer";
|
|
|
+ d->averageDiskBytesPerRead.key = "Avg. Disk Bytes/Read";
|
|
|
+ d->averageDiskBytesPerWrite.key = "Avg. Disk Bytes/Write";
|
|
|
+ d->splitIoPerSec.key = "Split IO/Sec";
|
|
|
}
|
|
|
|
|
|
-void initialize_physical_disk(struct physical_disk *pd) {
|
|
|
- pd->percentIdleTime.key = "% Idle Time";
|
|
|
- pd->percentDiskTime.key = "% Disk Time";
|
|
|
- pd->percentDiskReadTime.key = "% Disk Read Time";
|
|
|
- pd->percentDiskWriteTime.key = "% Disk Write Time";
|
|
|
- pd->currentDiskQueueLength.key = "Current Disk Queue Length";
|
|
|
- pd->averageDiskQueueLength.key = "Avg. Disk Queue Length";
|
|
|
- pd->averageDiskReadQueueLength.key = "Avg. Disk Read Queue Length";
|
|
|
- pd->averageDiskWriteQueueLength.key = "Avg. Disk Write Queue Length";
|
|
|
- pd->averageDiskSecondsPerTransfer.key = "Avg. Disk sec/Transfer";
|
|
|
- pd->averageDiskSecondsPerRead.key = "Avg. Disk sec/Read";
|
|
|
- pd->averageDiskSecondsPerWrite.key = "Avg. Disk sec/Write";
|
|
|
- pd->diskTransfersPerSec.key = "Disk Transfers/sec";
|
|
|
- pd->diskReadsPerSec.key = "Disk Reads/sec";
|
|
|
- pd->diskWritesPerSec.key = "Disk Writes/sec";
|
|
|
- pd->diskBytesPerSec.key = "Disk Bytes/sec";
|
|
|
- pd->diskReadBytesPerSec.key = "Disk Read Bytes/sec";
|
|
|
- pd->diskWriteBytesPerSec.key = "Disk Write Bytes/sec";
|
|
|
- pd->averageDiskBytesPerTransfer.key = "Avg. Disk Bytes/Transfer";
|
|
|
- pd->averageDiskBytesPerRead.key = "Avg. Disk Bytes/Read";
|
|
|
- pd->averageDiskBytesPerWrite.key = "Avg. Disk Bytes/Write";
|
|
|
- pd->splitIoPerSec.key = "Split IO/Sec";
|
|
|
+static void physical_disk_cleanup(struct physical_disk *d) {
|
|
|
+ string_freez(d->device);
|
|
|
+ string_freez(d->mount_point);
|
|
|
+
|
|
|
+ rrdset_is_obsolete___safe_from_collector_thread(d->disk_io.st_io);
|
|
|
+ rrdset_is_obsolete___safe_from_collector_thread(d->disk_ops.st_ops);
|
|
|
+ rrdset_is_obsolete___safe_from_collector_thread(d->disk_util.st_util);
|
|
|
+ rrdset_is_obsolete___safe_from_collector_thread(d->disk_busy.st_busy);
|
|
|
+ rrdset_is_obsolete___safe_from_collector_thread(d->disk_iotime.st_iotime);
|
|
|
+ rrdset_is_obsolete___safe_from_collector_thread(d->disk_qops.st_qops);
|
|
|
}
|
|
|
|
|
|
void dict_physical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
|
|
|
struct physical_disk *pd = value;
|
|
|
- initialize_physical_disk(pd);
|
|
|
+ physical_disk_initialize(pd);
|
|
|
}
|
|
|
|
|
|
static DICTIONARY *logicalDisks = NULL, *physicalDisks = NULL;
|
|
|
static void initialize(void) {
|
|
|
- initialize_physical_disk(&system_physical_total);
|
|
|
+ physical_disk_initialize(&system_physical_total);
|
|
|
|
|
|
logicalDisks = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
|
|
|
DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct logical_disk));
|
|
@@ -144,7 +172,7 @@ static STRING *getFileSystemType(const char* diskName) {
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
+static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec_t now_ut) {
|
|
|
DICTIONARY *dict = logicalDisks;
|
|
|
|
|
|
PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "LogicalDisk");
|
|
@@ -162,6 +190,7 @@ static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
continue;
|
|
|
|
|
|
struct logical_disk *d = dictionary_set(dict, windows_shared_buffer, NULL, sizeof(*d));
|
|
|
+ d->last_collected = now_ut;
|
|
|
|
|
|
if(!d->collected_metadata) {
|
|
|
d->filesystem = getFileSystemType(windows_shared_buffer);
|
|
@@ -174,8 +203,10 @@ static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
if(!d->st_disk_space) {
|
|
|
d->st_disk_space = rrdset_create_localhost(
|
|
|
"disk_space"
|
|
|
- , windows_shared_buffer, NULL
|
|
|
- , windows_shared_buffer, "disk.space"
|
|
|
+ , windows_shared_buffer
|
|
|
+ , NULL
|
|
|
+ , windows_shared_buffer
|
|
|
+ , "disk.space"
|
|
|
, "Disk Space Usage"
|
|
|
, "GiB"
|
|
|
, PLUGIN_WINDOWS_NAME
|
|
@@ -201,6 +232,19 @@ static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
rrdset_done(d->st_disk_space);
|
|
|
}
|
|
|
|
|
|
+ // cleanup
|
|
|
+ {
|
|
|
+ struct logical_disk *d;
|
|
|
+ dfe_start_write(dict, d) {
|
|
|
+ if(d->last_collected < now_ut) {
|
|
|
+ logical_disk_cleanup(d);
|
|
|
+ dictionary_del(dict, d_dfe.name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ dfe_done(d);
|
|
|
+ dictionary_garbage_collect(dict);
|
|
|
+ }
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -214,7 +258,12 @@ static void physical_disk_labels(RRDSET *st, void *data) {
|
|
|
rrdlabels_add(st->rrdlabels, "mount_point", string2str(d->mount_point), RRDLABEL_SRC_AUTO);
|
|
|
}
|
|
|
|
|
|
-static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
+static bool str_is_numeric(const char *s) {
|
|
|
+ while(*s) if(!isdigit((uint8_t)*s++)) return false;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec_t now_ut) {
|
|
|
DICTIONARY *dict = physicalDisks;
|
|
|
|
|
|
PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "PhysicalDisk");
|
|
@@ -230,12 +279,7 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
|
|
|
|
|
|
char *device = windows_shared_buffer;
|
|
|
- char *mount_point = NULL;
|
|
|
-
|
|
|
- if((mount_point = strchr(device, ' '))) {
|
|
|
- *mount_point = '\0';
|
|
|
- mount_point++;
|
|
|
- }
|
|
|
+ char mount_point[128]; mount_point[0] = '\0';
|
|
|
|
|
|
struct physical_disk *d;
|
|
|
bool is_system;
|
|
@@ -244,9 +288,22 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
is_system = true;
|
|
|
}
|
|
|
else {
|
|
|
+ char *space;
|
|
|
+ if((space = strchr(windows_shared_buffer, ' '))) {
|
|
|
+ *space++ = '\0';
|
|
|
+ strncpyz(mount_point, space, sizeof(mount_point) - 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(str_is_numeric(windows_shared_buffer)) {
|
|
|
+ uint64_t n = str2ull(device, NULL);
|
|
|
+ snprintfz(windows_shared_buffer, sizeof(windows_shared_buffer), "Disk %" PRIu64, n);
|
|
|
+ device = windows_shared_buffer;
|
|
|
+ }
|
|
|
+
|
|
|
d = dictionary_set(dict, device, NULL, sizeof(*d));
|
|
|
is_system = false;
|
|
|
}
|
|
|
+ d->last_collected = now_ut;
|
|
|
|
|
|
if (!d->collected_metadata) {
|
|
|
// TODO collect metadata - device_type, serial, id
|
|
@@ -258,7 +315,10 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadBytesPerSec) &&
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWriteBytesPerSec)) {
|
|
|
if(is_system)
|
|
|
- common_system_io(d->diskReadBytesPerSec.current.Data, d->diskWriteBytesPerSec.current.Data, update_every);
|
|
|
+ common_system_io(
|
|
|
+ d->diskReadBytesPerSec.current.Data,
|
|
|
+ d->diskWriteBytesPerSec.current.Data,
|
|
|
+ update_every);
|
|
|
else
|
|
|
common_disk_io(
|
|
|
&d->disk_io,
|
|
@@ -271,11 +331,79 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
d);
|
|
|
}
|
|
|
|
|
|
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentIdleTime);
|
|
|
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskTime);
|
|
|
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskReadTime);
|
|
|
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskWriteTime);
|
|
|
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->currentDiskQueueLength);
|
|
|
+ if(is_system) continue;
|
|
|
+
|
|
|
+ if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadsPerSec) &&
|
|
|
+ perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWritesPerSec)) {
|
|
|
+
|
|
|
+ common_disk_ops(
|
|
|
+ &d->disk_ops,
|
|
|
+ device,
|
|
|
+ NULL,
|
|
|
+ d->diskReadBytesPerSec.current.Data,
|
|
|
+ d->diskWriteBytesPerSec.current.Data,
|
|
|
+ update_every,
|
|
|
+ physical_disk_labels,
|
|
|
+ d);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentIdleTime)) {
|
|
|
+ if (d->percentIdleTime.previous.Data && d->percentIdleTime.previous.Time &&
|
|
|
+ d->percentIdleTime.current.Time > d->percentIdleTime.previous.Time) {
|
|
|
+ collected_number idle_percentage =
|
|
|
+ 100 * (d->percentIdleTime.current.Data - d->percentIdleTime.previous.Data)
|
|
|
+ / (d->percentIdleTime.current.Time - d->percentIdleTime.previous.Time);
|
|
|
+
|
|
|
+ if (idle_percentage > 100)
|
|
|
+ idle_percentage = 100;
|
|
|
+
|
|
|
+ common_disk_util(
|
|
|
+ &d->disk_util,
|
|
|
+ device,
|
|
|
+ NULL,
|
|
|
+ 100 - idle_percentage,
|
|
|
+ update_every,
|
|
|
+ physical_disk_labels,
|
|
|
+ d);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskTime)) {
|
|
|
+ common_disk_busy(
|
|
|
+ &d->disk_busy,
|
|
|
+ device,
|
|
|
+ NULL,
|
|
|
+ d->percentDiskTime.current.Data / NS100_PER_MS,
|
|
|
+ update_every,
|
|
|
+ physical_disk_labels,
|
|
|
+ d);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskReadTime) &&
|
|
|
+ perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskWriteTime)) {
|
|
|
+
|
|
|
+ common_disk_iotime(
|
|
|
+ &d->disk_iotime,
|
|
|
+ device,
|
|
|
+ NULL,
|
|
|
+ d->percentDiskReadTime.current.Data / NS100_PER_MS,
|
|
|
+ d->percentDiskWriteTime.current.Data / NS100_PER_MS,
|
|
|
+ update_every,
|
|
|
+ physical_disk_labels,
|
|
|
+ d);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->currentDiskQueueLength)) {
|
|
|
+ common_disk_qops(
|
|
|
+ &d->disk_qops,
|
|
|
+ device,
|
|
|
+ NULL,
|
|
|
+ d->currentDiskQueueLength.current.Data,
|
|
|
+ update_every,
|
|
|
+ physical_disk_labels,
|
|
|
+ d);
|
|
|
+ }
|
|
|
+
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskQueueLength);
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskReadQueueLength);
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskWriteQueueLength);
|
|
@@ -283,8 +411,6 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerRead);
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerWrite);
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskTransfersPerSec);
|
|
|
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadsPerSec);
|
|
|
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWritesPerSec);
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskBytesPerSec);
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerTransfer);
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerRead);
|
|
@@ -292,6 +418,19 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
|
|
|
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->splitIoPerSec);
|
|
|
}
|
|
|
|
|
|
+ // cleanup
|
|
|
+ {
|
|
|
+ struct physical_disk *d;
|
|
|
+ dfe_start_write(dict, d) {
|
|
|
+ if(d->last_collected < now_ut) {
|
|
|
+ physical_disk_cleanup(d);
|
|
|
+ dictionary_del(dict, d_dfe.name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ dfe_done(d);
|
|
|
+ dictionary_garbage_collect(dict);
|
|
|
+ }
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -310,8 +449,9 @@ int do_PerflibStorage(int update_every, usec_t dt __maybe_unused) {
|
|
|
PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
|
|
|
if(!pDataBlock) return -1;
|
|
|
|
|
|
- do_logical_disk(pDataBlock, update_every);
|
|
|
- do_physical_disk(pDataBlock, update_every);
|
|
|
+ usec_t now_ut = now_monotonic_usec();
|
|
|
+ do_logical_disk(pDataBlock, update_every, now_ut);
|
|
|
+ do_physical_disk(pDataBlock, update_every, now_ut);
|
|
|
|
|
|
return 0;
|
|
|
}
|