DiskIO: init module

This commit is contained in:
李通洲
2023-10-07 16:21:26 +08:00
committed by 李通洲
parent b1d63e03d8
commit 276e22f6b0
15 changed files with 509 additions and 2 deletions
+5
View File
@@ -273,6 +273,7 @@ set(LIBFASTFETCH_SRC
src/detection/cpu/cpu.c
src/detection/cpuusage/cpuusage.c
src/detection/disk/disk.c
src/detection/diskio/diskio.c
src/detection/displayserver/displayserver.c
src/detection/font/font.c
src/detection/gpu/gpu.c
@@ -310,6 +311,7 @@ set(LIBFASTFETCH_SRC
src/modules/datetime/datetime.c
src/modules/de/de.c
src/modules/disk/disk.c
src/modules/diskio/diskio.c
src/modules/font/font.c
src/modules/gpu/gpu.c
src/modules/host/host.c
@@ -375,6 +377,7 @@ if(LINUX)
src/detection/cursor/cursor_linux.c
src/detection/bluetooth/bluetooth_linux.c
src/detection/disk/disk_linux.c
src/detection/diskio/diskio_linux.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/wayland.c
src/detection/displayserver/linux/wmde.c
@@ -534,6 +537,7 @@ elseif(APPLE)
src/detection/cpuusage/cpuusage_apple.c
src/detection/cursor/cursor_apple.m
src/detection/disk/disk_bsd.c
src/detection/diskio/diskio_apple.c
src/detection/displayserver/displayserver_apple.c
src/detection/font/font_apple.m
src/detection/gpu/gpu_apple.c
@@ -584,6 +588,7 @@ elseif(WIN32)
src/detection/cpuusage/cpuusage_windows.c
src/detection/cursor/cursor_windows.c
src/detection/disk/disk_windows.c
src/detection/diskio/diskio_windows.c
src/detection/displayserver/displayserver_windows.c
src/detection/font/font_windows.c
src/detection/gpu/gpu_windows.c
+2
View File
@@ -93,6 +93,7 @@ static void defaultConfig(void)
ffInitDEOptions(&instance.config.de);
ffInitDateTimeOptions(&instance.config.dateTime);
ffInitDiskOptions(&instance.config.disk);
ffInitDiskIOOptions(&instance.config.diskio);
ffInitDisplayOptions(&instance.config.display);
ffInitFontOptions(&instance.config.font);
ffInitGPUOptions(&instance.config.gpu);
@@ -307,6 +308,7 @@ static void destroyConfig(void)
ffDestroyDEOptions(&instance.config.de);
ffDestroyDateTimeOptions(&instance.config.dateTime);
ffDestroyDiskOptions(&instance.config.disk);
ffDestroyDiskIOOptions(&instance.config.diskio);
ffDestroyDisplayOptions(&instance.config.display);
ffDestroyFontOptions(&instance.config.font);
ffDestroyGPUOptions(&instance.config.gpu);
+1
View File
@@ -30,6 +30,7 @@ static FFModuleBaseInfo* D[] = {
(void*) &instance.config.de,
(void*) &instance.config.display,
(void*) &instance.config.disk,
(void*) &instance.config.diskio,
NULL,
};
-2
View File
@@ -57,9 +57,7 @@ const char* ffDetectDisksImpl(FFlist* disks)
}
if(GetVolumeNameForVolumeMountPointW(mountpoint, volumeName, sizeof(volumeName) / sizeof(*volumeName)))
{
ffStrbufInitWS(&disk->mountFrom, volumeName);
}
else
ffStrbufInit(&disk->mountFrom);
+67
View File
@@ -0,0 +1,67 @@
#include "diskio.h"
#include "common/time.h"
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options);
static FFlist ioCounters1;
static uint64_t time1;
void ffPrepareDiskIO(FFDiskIOOptions* options)
{
ffListInit(&ioCounters1, sizeof(FFDiskIOOptions));
ffDiskIOGetIoCounters(&ioCounters1, options);
time1 = ffTimeGetNow();
}
const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options)
{
const char* error = NULL;
if (time1 == 0)
{
ffListInit(&ioCounters1, sizeof(FFDiskIOResult));
error = ffDiskIOGetIoCounters(&ioCounters1, options);
if (error)
return error;
time1 = ffTimeGetNow();
}
if (ioCounters1.length == 0)
return "No physical disk found";
uint64_t time2 = ffTimeGetNow();
while (time2 - time1 < 1000)
{
ffTimeSleep((uint32_t) (1000 - (time2 - time1)));
time2 = ffTimeGetNow();
}
error = ffDiskIOGetIoCounters(result, options);
if (error)
return error;
if (result->length != ioCounters1.length)
return "Different number of physical disks. Hardware change?";
for (uint32_t i = 0; i < result->length; ++i)
{
FFDiskIOResult* icPrev = (FFDiskIOResult*)ffListGet(&ioCounters1, i);
FFDiskIOResult* icCurr = (FFDiskIOResult*)ffListGet(result, i);
if (!ffStrbufEqual(&icPrev->name, &icCurr->name))
return "Network interface name changed";
static_assert(sizeof(FFDiskIOResult) - offsetof(FFDiskIOResult, bytesRead) == sizeof(uint64_t) * 4, "Unexpected struct FFDiskIOResult layout");
for (size_t off = offsetof(FFDiskIOResult, bytesRead); off < sizeof(FFDiskIOResult); off += sizeof(uint64_t))
{
uint64_t* prevValue = (uint64_t*) ((uint8_t*) icPrev + off);
uint64_t* currValue = (uint64_t*) ((uint8_t*) icCurr + off);
uint64_t temp = *currValue;
*currValue -= *prevValue;
*currValue /= (time2 - time1) / 1000 /* seconds */;
*prevValue = temp;
}
}
time1 = time2;
return NULL;
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "fastfetch.h"
typedef struct FFDiskIOResult
{
FFstrbuf name;
FFstrbuf type;
FFstrbuf devPath;
uint64_t bytesRead;
uint64_t readCount;
uint64_t bytesWritten;
uint64_t writeCount;
} FFDiskIOResult;
const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options);
+41
View File
@@ -0,0 +1,41 @@
#include "diskio.h"
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
{
io_iterator_t iterator;
if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != kIOReturnSuccess)
return "IOServiceGetMatchingServices() failed";
io_registry_entry_t registryEntry;
while((registryEntry = IOIteratorNext(iterator)) != 0)
{
CFMutableDictionaryRef properties;
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
{
IOObjectRelease(registryEntry);
continue;
}
io_registry_entry_t parent;
IORegistryEntryGetParentEntry(registryEntry, kIOServicePlane, &parent);
if(IOObjectConformsTo(parent, kIOBlockStorageDriverClass)) continue;
io_name_t name;
if (IORegistryEntryGetName(registryEntry, name) != KERN_SUCCESS)
continue;
// NSDictionary* props = (__bridge NSDictionary*) properties;
// id statistics = [props valueForKey:@(kIOBlockStorageDriverStatisticsKey)];
// if (!statistics) continue;
// id volGroupaMntFromName = [props valueForKey:@"VolGroupMntFromName"];
// if (!volGroupaMntFromName) continue;
// NSLog(@"%@", props);
}
}
+93
View File
@@ -0,0 +1,93 @@
#include "diskio.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
#include <ctype.h>
#include <limits.h>
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
{
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS("/dev/disk/by-id/");
uint32_t baseDirLength = baseDir.length;
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir.chars);
if(dirp == NULL)
return "opendir(batteryDir) == NULL";
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL)
{
if (entry->d_name[0] == '.')
continue;
char* part = strstr(entry->d_name, "-part");
if (part && isdigit(part[strlen("-part")]))
continue;
if (ffStrStartsWith(entry->d_name, "nvme-eui.")) // NVMe drive indentifier
continue;
// Other exceptions?
ffStrbufAppendS(&baseDir, entry->d_name);
char pathDev[PATH_MAX];
ssize_t pathLen = readlink(baseDir.chars, pathDev, PATH_MAX);
ffStrbufSubstrBefore(&baseDir, baseDirLength);
if (pathLen < 0) continue;
pathDev[pathLen] = '\0'; // ../../nvme0n1
char pathDev1[PATH_MAX];
const char* devName = basename(pathDev);
snprintf(pathDev1, PATH_MAX, "/dev/%s", devName);
// Avoid duplicated disks
bool flag = false;
FF_LIST_FOR_EACH(FFDiskIOResult, disk, *result)
{
if (ffStrbufEqualS(&disk->devPath, pathDev1))
{
flag = true;
break;
}
}
if (flag) continue;
char pathSysBlockStat[PATH_MAX];
snprintf(pathSysBlockStat, PATH_MAX, "/sys/block/%s/stat", devName);
FF_AUTO_CLOSE_FILE FILE* sysBlockStat = fopen(pathSysBlockStat, "r");
if (!sysBlockStat) continue;
// I/Os merges sectors ticks ...
uint64_t nRead, sectorRead, nWritten, sectorWritten;
if (fscanf(sysBlockStat, "%lu%*u%lu%*u%lu%*u%lu%*u", &nRead, &sectorRead, &nWritten, &sectorWritten) == 0)
continue;
FFDiskIOResult* device = (FFDiskIOResult*) ffListAdd(result);
char* slash = strchr(entry->d_name, '-');
if (slash)
{
char* slash2 = strchr(slash + 1, '-');
if (slash2)
ffStrbufInitNS(&device->name, (uint32_t) (slash2 - slash - 1), slash + 1);
else
ffStrbufInitS(&device->name, slash + 1);
ffStrbufInitNS(&device->type, (uint32_t) (slash - entry->d_name), entry->d_name);
}
else
{
ffStrbufInitS(&device->name, entry->d_name);
ffStrbufInit(&device->type);
}
ffStrbufReplaceAllC(&device->name, '_', ' ');
ffStrbufInitS(&device->devPath, pathDev1);
device->bytesRead = sectorRead * 512;
device->bytesWritten = sectorWritten * 512;
device->readCount = nRead;
device->writeCount = nWritten;
}
return NULL;
}
+57
View File
@@ -0,0 +1,57 @@
#include "diskio.h"
#include "common/io/io.h"
#include "util/windows/registry.h"
#include "util/windows/unicode.h"
#include <winioctl.h>
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
{
FF_HKEY_AUTO_DESTROY hKey = NULL;
if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\disk\\Enum", &hKey, NULL))
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"SYSTEM\\CurrentControlSet\\Services\\disk\\Enum\") failed";
uint32_t nDevices;
if (!ffRegReadUint(hKey, L"Count", &nDevices, NULL))
return "ffRegReadUint(hKey, L\"Count\", &nDevices) failed";
wchar_t szDevice[32] = L"\\\\.\\PhysicalDrive";
wchar_t* pNum = szDevice + strlen("\\\\.\\PhysicalDrive");
for (uint32_t idev = 0; idev <= nDevices; ++idev) {
_ultow(idev, pNum, 10);
FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
continue;
DISK_PERFORMANCE diskPerformance;
DWORD ioctrlSize = sizeof(diskPerformance);
DWORD dwSize;
if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &diskPerformance, ioctrlSize, &dwSize, NULL))
{
FFDiskIOResult* device = (FFDiskIOResult*) ffListAdd(result);
ffStrbufInit(&device->name);
ffStrbufInit(&device->type);
if (ffRegReadStrbuf(hKey, pNum, &device->name, NULL))
{
// SCSI\Disk&Ven_NVMe&Prod_WDC_PC_SN810_SDC\5&19cebb7&0&000000
uint32_t index = ffStrbufFirstIndexC(&device->name, '\\');
if (index != device->name.length)
ffStrbufAppendNS(&device->type, index, device->name.chars); // SCSI
ffStrbufSubstrAfterFirstS(&device->name, "&Prod_");
ffStrbufSubstrBeforeLastC(&device->name, '\\');
ffStrbufReplaceAllC(&device->name, '_', ' ');
}
else
ffStrbufSetWS(&device->name, szDevice);
ffStrbufInitWS(&device->devPath, szDevice);
device->bytesRead = (uint64_t) diskPerformance.BytesRead.QuadPart;
device->readCount = (uint64_t) diskPerformance.ReadCount;
device->bytesWritten = (uint64_t) diskPerformance.BytesWritten.QuadPart;
device->writeCount = (uint64_t) diskPerformance.WriteCount;
}
}
return NULL;
}
+1
View File
@@ -99,6 +99,7 @@ typedef struct FFconfig
FFDEOptions de;
FFDateTimeOptions dateTime;
FFDiskOptions disk;
FFDiskIOOptions diskio;
FFDisplayOptions display;
FFFontOptions font;
FFGPUOptions gpu;
+196
View File
@@ -0,0 +1,196 @@
#include "common/printing.h"
#include "common/jsonconfig.h"
#include "common/parsing.h"
#include "detection/diskio/diskio.h"
#include "modules/diskio/diskio.h"
#include "util/stringUtils.h"
#define FF_DISKIO_DISPLAY_NAME "Disk IO"
#define FF_DISKIO_NUM_FORMAT_ARGS 7
static int sortDevices(const FFDiskIOResult* left, const FFDiskIOResult* right)
{
return ffStrbufComp(&left->name, &right->name);
}
static void formatKey(const FFDiskIOOptions* options, FFDiskIOResult* dev, uint32_t index, FFstrbuf* key)
{
if(options->moduleArgs.key.length == 0)
{
if(!dev->name.length)
ffStrbufSetF(&dev->name, "unknown %u", (unsigned) index);
ffStrbufSetF(key, FF_DISKIO_DISPLAY_NAME " (%s)", dev->name.chars);
}
else
{
ffStrbufClear(key);
ffParseFormatString(key, &options->moduleArgs.key, 2, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_UINT, &index},
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->name},
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->type},
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->devPath},
});
}
}
void ffPrintDiskIO(FFDiskIOOptions* options)
{
FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFDiskIOResult));
const char* error = ffDetectDiskIO(&result, options);
if(error)
{
ffPrintError(FF_DISKIO_DISPLAY_NAME, 0, &options->moduleArgs, "%s", error);
return;
}
ffListSort(&result, (const void*) sortDevices);
uint32_t index = 0;
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY buffer2 = ffStrbufCreate();
FF_LIST_FOR_EACH(FFDiskIOResult, dev, result)
{
formatKey(options, dev, result.length == 1 ? 0 : index + 1, &key);
ffStrbufClear(&buffer);
if(options->moduleArgs.outputFormat.length == 0)
{
ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffParseSize(dev->bytesRead, &buffer);
ffStrbufAppendS(&buffer, "/s (R) - ");
ffParseSize(dev->bytesWritten, &buffer);
ffStrbufAppendS(&buffer, "/s (W)");
ffStrbufPutTo(&buffer, stdout);
}
else
{
ffStrbufClear(&buffer2);
ffParseSize(dev->bytesRead, &buffer);
ffStrbufAppendS(&buffer, "/s");
ffParseSize(dev->bytesWritten, &buffer2);
ffStrbufAppendS(&buffer2, "/s");
ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_DISKIO_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &buffer},
{FF_FORMAT_ARG_TYPE_STRBUF, &buffer2},
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->name},
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->type},
{FF_FORMAT_ARG_TYPE_UINT64, &dev->bytesRead},
{FF_FORMAT_ARG_TYPE_UINT64, &dev->bytesWritten},
{FF_FORMAT_ARG_TYPE_UINT64, &dev->readCount},
{FF_FORMAT_ARG_TYPE_UINT64, &dev->writeCount},
});
}
++index;
}
FF_LIST_FOR_EACH(FFDiskIOResult, dev, result)
{
ffStrbufDestroy(&dev->name);
ffStrbufDestroy(&dev->type);
ffStrbufDestroy(&dev->devPath);
}
}
void ffInitDiskIOOptions(FFDiskIOOptions* options)
{
ffOptionInitModuleBaseInfo(&options->moduleInfo, FF_DISKIO_MODULE_NAME, ffParseDiskIOCommandOptions, ffParseDiskIOJsonObject, ffPrintDiskIO, ffGenerateDiskIOJson, ffPrintDiskIOHelpFormat);
ffOptionInitModuleArg(&options->moduleArgs);
ffStrbufInit(&options->namePrefix);
}
bool ffParseDiskIOCommandOptions(FFDiskIOOptions* options, const char* key, const char* value)
{
const char* subKey = ffOptionTestPrefix(key, FF_DISKIO_MODULE_NAME);
if (!subKey) return false;
if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs))
return true;
if (ffStrEqualsIgnCase(subKey, "name-prefix"))
{
ffOptionParseString(key, value, &options->namePrefix);
return true;
}
return false;
}
void ffDestroyDiskIOOptions(FFDiskIOOptions* options)
{
ffOptionDestroyModuleArg(&options->moduleArgs);
ffStrbufDestroy(&options->namePrefix);
}
void ffParseDiskIOJsonObject(FFDiskIOOptions* options, yyjson_val* module)
{
yyjson_val *key_, *val;
size_t idx, max;
yyjson_obj_foreach(module, idx, max, key_, val)
{
const char* key = yyjson_get_str(key_);
if(ffStrEqualsIgnCase(key, "type"))
continue;
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
continue;
if (ffStrEqualsIgnCase(key, "namePrefix"))
{
ffStrbufSetS(&options->namePrefix, yyjson_get_str(val));
continue;
}
ffPrintError(FF_DISKIO_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
}
}
void ffGenerateDiskIOJson(FFDiskIOOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFDiskIOResult));
const char* error = ffDetectDiskIO(&result, options);
if(error)
{
yyjson_mut_obj_add_str(doc, module, "error", error);
return;
}
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
FF_LIST_FOR_EACH(FFDiskIOResult, counter, result)
{
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &counter->name);
yyjson_mut_obj_add_strbuf(doc, obj, "type", &counter->type);
yyjson_mut_obj_add_uint(doc, obj, "bytesRead", counter->bytesRead);
yyjson_mut_obj_add_uint(doc, obj, "bytesWritten", counter->bytesWritten);
yyjson_mut_obj_add_uint(doc, obj, "readCount", counter->readCount);
yyjson_mut_obj_add_uint(doc, obj, "writeCount", counter->writeCount);
}
FF_LIST_FOR_EACH(FFDiskIOResult, dev, result)
{
ffStrbufDestroy(&dev->name);
ffStrbufDestroy(&dev->type);
ffStrbufDestroy(&dev->devPath);
}
}
void ffPrintDiskIOHelpFormat(void)
{
ffPrintModuleFormatHelp(FF_DISKIO_MODULE_NAME, "{1} (R) - {2} (W)", FF_DISKIO_NUM_FORMAT_ARGS, (const char* []) {
"Size of data read per second (formatted)",
"Size of data written per second (formatted)",
"Device name",
"Device type",
"Size of data read per second (in bytes)",
"Size of data written per second (in bytes)",
"Number of reads",
"Number of writes",
});
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include "fastfetch.h"
#define FF_DISKIO_MODULE_NAME "DiskIO"
void ffPrepareDiskIO(FFDiskIOOptions* options);
void ffPrintDiskIO(FFDiskIOOptions* options);
void ffInitDiskIOOptions(FFDiskIOOptions* options);
bool ffParseDiskIOCommandOptions(FFDiskIOOptions* options, const char* key, const char* value);
void ffDestroyDiskIOOptions(FFDiskIOOptions* options);
void ffParseDiskIOJsonObject(FFDiskIOOptions* options, yyjson_val* module);
void ffGenerateDiskIOJson(FFDiskIOOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module);
void ffPrintDiskIOHelpFormat(void);
+13
View File
@@ -0,0 +1,13 @@
#pragma once
// This file will be included in "fastfetch.h", do NOT put unnecessary things here
#include "common/option.h"
typedef struct FFDiskIOOptions
{
FFModuleBaseInfo moduleInfo;
FFModuleArgs moduleArgs;
FFstrbuf namePrefix;
} FFDiskIOOptions;
+1
View File
@@ -17,6 +17,7 @@
#include "modules/custom/custom.h"
#include "modules/datetime/datetime.h"
#include "modules/disk/disk.h"
#include "modules/diskio/diskio.h"
#include "modules/display/display.h"
#include "modules/de/de.h"
#include "modules/font/font.h"
+1
View File
@@ -18,6 +18,7 @@
#include "modules/datetime/option.h"
#include "modules/de/option.h"
#include "modules/disk/option.h"
#include "modules/diskio/option.h"
#include "modules/display/option.h"
#include "modules/font/option.h"
#include "modules/host/option.h"