mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-28 02:31:25 +01:00
NetIO / DiskIO: reduces waitTime & improves accurency
This commit is contained in:
+4
-1
@@ -9,6 +9,9 @@ Changes:
|
||||
* `--logo-cache false` ignores the image logo cache completely: nothing is read from it and nothing is written to it.
|
||||
* `--logo-cache regen` does what `--logo-recache true` used to do.
|
||||
* `logo.cache` accepts a boolean, or the string `"regen"`.
|
||||
* The `waitTime` option of `DiskIO` and `NetIO` now defaults to `250` ms instead of `500`. (DiskIO / NetIO)
|
||||
* The byte counters are maintained by the kernel as I/O happens, so a shorter sampling window still yields an accurate rate, and both modules now finish about 250 ms sooner.
|
||||
* Note that the two modules wait concurrently, so enabling both does not cost twice the wait time.
|
||||
|
||||
Features:
|
||||
* Improved image logo support
|
||||
@@ -37,7 +40,7 @@ Features:
|
||||
* Improved Wallpaper detection on macOS Sonoma and later (#2559, Wallpaper, macOS)
|
||||
* The image path is now also extracted from the `Configuration` field of the wallpaper plist, and the `NSWorkspace` fallback is tried last.
|
||||
* Removed the `kvm` dependency on OpenBSD by using `sysctl` directly. (General, OpenBSD)
|
||||
* Modules that were selected on the command line via `--structure` / `-s` now honors module options configured in the JSON config. (CommandOption)
|
||||
* Modules that were selected on the command line via `--structure` / `-s` now honor module options configured in the JSON config. (CommandOption)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed Base64 encoding producing wrong output for some inputs. (General)
|
||||
|
||||
@@ -2710,7 +2710,7 @@
|
||||
"waitTime": {
|
||||
"type": "integer",
|
||||
"description": "Wait time (in ms) used to measure the I/O rate (calculated in bytes/sec).\nAvoid setting this too low, as the kernel requires time to accurately update counters.\nIgnored if 'detectTotal' is true.",
|
||||
"default": 500,
|
||||
"default": 250,
|
||||
"minimum": 1
|
||||
},
|
||||
"key": {
|
||||
@@ -3611,7 +3611,7 @@
|
||||
"waitTime": {
|
||||
"type": "integer",
|
||||
"description": "Wait time (in ms) used to measure the I/O rate (calculated in bytes/sec).\nAvoid setting this too low, as the kernel requires time to accurately update counters.\nIgnored if 'detectTotal' is true.",
|
||||
"default": 500,
|
||||
"default": 250,
|
||||
"minimum": 1
|
||||
},
|
||||
"key": {
|
||||
|
||||
+2
-2
@@ -99,7 +99,7 @@
|
||||
"gamepad",
|
||||
"mouse",
|
||||
"keyboard",
|
||||
"top",
|
||||
"tpm",
|
||||
"netio",
|
||||
"diskio",
|
||||
{
|
||||
@@ -110,7 +110,7 @@
|
||||
"type": "weather",
|
||||
"timeout": 1000
|
||||
},
|
||||
"tpm",
|
||||
"top",
|
||||
"version",
|
||||
"break",
|
||||
"colors"
|
||||
|
||||
+2
-2
@@ -101,7 +101,7 @@
|
||||
"gamepad",
|
||||
"mouse",
|
||||
"keyboard",
|
||||
"top",
|
||||
"tpm",
|
||||
"netio",
|
||||
"diskio",
|
||||
{
|
||||
@@ -112,7 +112,7 @@
|
||||
"type": "weather",
|
||||
"timeout": 1000
|
||||
},
|
||||
"tpm",
|
||||
"top",
|
||||
"version",
|
||||
"logo",
|
||||
"break",
|
||||
|
||||
@@ -63,6 +63,21 @@ bool ffParseModuleOptions(const char* key, const char* value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static yyjson_val* findStructureModuleConfig(FFdata* data, const char* moduleType);
|
||||
|
||||
// The module options live in the JSON config only. They must be merged here as well as in
|
||||
// `parseStructureCommand`, because `ffPrepareXxx` takes the first snapshot while `ffDetectXxx`
|
||||
// takes the second one. If the two disagree, they list different entries and the deltas are
|
||||
// meaningless. Keeping both call sites on this single helper is what makes them agree.
|
||||
static void initStructureModuleOptions(FFdata* data, FFModuleBaseInfo* baseInfo, void* options) {
|
||||
baseInfo->initOptions(options);
|
||||
|
||||
yyjson_val* configModule = findStructureModuleConfig(data, baseInfo->name);
|
||||
if (configModule != nullptr) {
|
||||
baseInfo->parseJsonObject(options, configModule);
|
||||
}
|
||||
}
|
||||
|
||||
void ffPrepareCommandOption(FFdata* data) {
|
||||
char* moduleType = nullptr;
|
||||
size_t moduleLen = 0;
|
||||
@@ -74,7 +89,7 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
case 'C':
|
||||
case 'c':
|
||||
FF_IF_MODULE_MATCH(ffCPUUsageModuleInfo.name)
|
||||
ffPrepareCPUUsage();
|
||||
ffPrepareCPUUsage(); // The rate is derived from the CPU's own counters; no options are involved
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -83,7 +98,7 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
case 'd':
|
||||
FF_IF_MODULE_MATCH(ffDiskIOModuleInfo.name) {
|
||||
[[gnu::cleanup(ffDestroyDiskIOOptions)]] FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
initStructureModuleOptions(data, &ffDiskIOModuleInfo, &options);
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
break;
|
||||
@@ -94,7 +109,7 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
case 'n':
|
||||
FF_IF_MODULE_MATCH(ffNetIOModuleInfo.name) {
|
||||
[[gnu::cleanup(ffDestroyNetIOOptions)]] FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
initStructureModuleOptions(data, &ffNetIOModuleInfo, &options);
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
break;
|
||||
@@ -105,7 +120,7 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
case 'p':
|
||||
FF_IF_MODULE_MATCH(ffPublicIPModuleInfo.name) {
|
||||
[[gnu::cleanup(ffDestroyPublicIpOptions)]] FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
initStructureModuleOptions(data, &ffPublicIPModuleInfo, &options);
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
break;
|
||||
@@ -116,7 +131,7 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
case 't':
|
||||
FF_IF_MODULE_MATCH(ffTopModuleInfo.name) {
|
||||
[[gnu::cleanup(ffDestroyTopOptions)]] FFTopOptions options;
|
||||
ffInitTopOptions(&options);
|
||||
initStructureModuleOptions(data, &ffTopModuleInfo, &options);
|
||||
ffPrepareTopProcesses(options.showTypes);
|
||||
}
|
||||
break;
|
||||
@@ -127,7 +142,7 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
case 'w':
|
||||
FF_IF_MODULE_MATCH(ffWeatherModuleInfo.name) {
|
||||
[[gnu::cleanup(ffDestroyWeatherOptions)]] FFWeatherOptions options;
|
||||
ffInitWeatherOptions(&options);
|
||||
initStructureModuleOptions(data, &ffWeatherModuleInfo, &options);
|
||||
ffPrepareWeather(&options);
|
||||
}
|
||||
break;
|
||||
@@ -215,17 +230,11 @@ static bool parseStructureCommand(
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(line, baseInfo->name)) {
|
||||
alignas(uint64_t) uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
initStructureModuleOptions(data, baseInfo, optionBuf);
|
||||
if (data->resultDoc != nullptr) {
|
||||
fn(data, baseInfo, optionBuf);
|
||||
} else {
|
||||
yyjson_val* configModule = findStructureModuleConfig(data, baseInfo->name);
|
||||
if (configModule != nullptr) {
|
||||
baseInfo->parseJsonObject(optionBuf, configModule);
|
||||
baseInfo->printModule(optionBuf);
|
||||
} else {
|
||||
baseInfo->printModule(optionBuf);
|
||||
}
|
||||
}
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return true;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options);
|
||||
|
||||
static FFlist ioCounters1;
|
||||
static uint64_t time1;
|
||||
static double time1;
|
||||
|
||||
void ffPrepareDiskIO(FFDiskIOOptions* options) {
|
||||
if (options->detectTotal) {
|
||||
@@ -16,9 +16,13 @@ void ffPrepareDiskIO(FFDiskIOOptions* options) {
|
||||
return; // Already prepared
|
||||
}
|
||||
|
||||
// The options cannot change between this call and `ffDetectDiskIO`: `ffPrepareCommandOption`
|
||||
// and `parseStructureCommand` both build them through `initStructureModuleOptions`, which
|
||||
// merges the module object from the JSON config. So the baseline always matches the second
|
||||
// snapshot and needs no re-validation.
|
||||
ffListInit(&ioCounters1);
|
||||
ffDiskIOGetIoCounters(&ioCounters1, options);
|
||||
time1 = ffTimeGetNow();
|
||||
time1 = ffTimeGetTick();
|
||||
}
|
||||
|
||||
const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options) {
|
||||
@@ -33,22 +37,17 @@ const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options) {
|
||||
}
|
||||
|
||||
if (time1 == 0) {
|
||||
ffListInit(&ioCounters1);
|
||||
error = ffDiskIOGetIoCounters(&ioCounters1, options);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
time1 = ffTimeGetNow();
|
||||
ffPrepareDiskIO(options);
|
||||
}
|
||||
|
||||
if (ioCounters1.length == 0) {
|
||||
return "No physical disk found";
|
||||
}
|
||||
|
||||
uint64_t time2 = ffTimeGetNow();
|
||||
while (time2 - time1 < options->waitTime) {
|
||||
double time2 = ffTimeGetTick();
|
||||
while (time2 - time1 < (double) options->waitTime) {
|
||||
ffTimeSleep((uint32_t) (options->waitTime - (time2 - time1)));
|
||||
time2 = ffTimeGetNow();
|
||||
time2 = ffTimeGetTick();
|
||||
}
|
||||
|
||||
error = ffDiskIOGetIoCounters(result, options);
|
||||
@@ -72,7 +71,7 @@ const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options) {
|
||||
uint64_t* prevValue = (uint64_t*) ((uint8_t*) icPrev + off);
|
||||
uint64_t* currValue = (uint64_t*) ((uint8_t*) icCurr + off);
|
||||
uint64_t temp = *currValue;
|
||||
*currValue = (*currValue - *prevValue) * 1000 / (time2 - time1); // Calculate per second
|
||||
*currValue = (uint64_t) ((double) (*currValue - *prevValue) * 1000.0 / (time2 - time1)); // Calculate per second
|
||||
|
||||
// For next function call
|
||||
*prevValue = temp;
|
||||
|
||||
+11
-12
@@ -3,7 +3,7 @@
|
||||
#include "common/time.h"
|
||||
|
||||
static FFlist ioCounters1;
|
||||
static uint64_t time1;
|
||||
static double time1;
|
||||
|
||||
void ffPrepareNetIO(FFNetIOOptions* options) {
|
||||
if (options->detectTotal) {
|
||||
@@ -14,9 +14,13 @@ void ffPrepareNetIO(FFNetIOOptions* options) {
|
||||
return; // Already prepared
|
||||
}
|
||||
|
||||
// The options cannot change between this call and `ffDetectNetIO`: `ffPrepareCommandOption`
|
||||
// and `parseStructureCommand` both build them through `initStructureModuleOptions`, which
|
||||
// merges the module object from the JSON config. So the baseline always matches the second
|
||||
// snapshot and needs no re-validation.
|
||||
ffListInit(&ioCounters1);
|
||||
ffNetIOGetIoCounters(&ioCounters1, options);
|
||||
time1 = ffTimeGetNow();
|
||||
time1 = ffTimeGetTick();
|
||||
}
|
||||
|
||||
const char* ffDetectNetIO(FFlist* result, FFNetIOOptions* options) {
|
||||
@@ -31,22 +35,17 @@ const char* ffDetectNetIO(FFlist* result, FFNetIOOptions* options) {
|
||||
}
|
||||
|
||||
if (time1 == 0) {
|
||||
ffListInit(&ioCounters1);
|
||||
error = ffNetIOGetIoCounters(&ioCounters1, options);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
time1 = ffTimeGetNow();
|
||||
ffPrepareNetIO(options);
|
||||
}
|
||||
|
||||
if (ioCounters1.length == 0) {
|
||||
return "No network interfaces found";
|
||||
}
|
||||
|
||||
uint64_t time2 = ffTimeGetNow();
|
||||
while (time2 - time1 < options->waitTime) {
|
||||
double time2 = ffTimeGetTick();
|
||||
while (time2 - time1 < (double) options->waitTime) {
|
||||
ffTimeSleep((uint32_t) (options->waitTime - (time2 - time1)));
|
||||
time2 = ffTimeGetNow();
|
||||
time2 = ffTimeGetTick();
|
||||
}
|
||||
|
||||
error = ffNetIOGetIoCounters(result, options);
|
||||
@@ -70,7 +69,7 @@ const char* ffDetectNetIO(FFlist* result, FFNetIOOptions* options) {
|
||||
uint64_t* prevValue = (uint64_t*) ((uint8_t*) icPrev + off);
|
||||
uint64_t* currValue = (uint64_t*) ((uint8_t*) icCurr + off);
|
||||
uint64_t temp = *currValue;
|
||||
*currValue = (*currValue - *prevValue) * 1000 / (time2 - time1); // Calculate per second
|
||||
*currValue = (uint64_t) ((double) (*currValue - *prevValue) * 1000.0 / (time2 - time1)); // Calculate per second
|
||||
*prevValue = temp;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-12
@@ -4,28 +4,22 @@
|
||||
|
||||
static FFlist first;
|
||||
static double startTick;
|
||||
static FFTopTypes preparedShowTypes = FF_TOP_TYPE_CPU | FF_TOP_TYPE_MEMORY | FF_TOP_TYPE_DISK;
|
||||
|
||||
void ffPrepareTopProcesses(FFTopTypes showTypes) {
|
||||
if ((showTypes & (FF_TOP_TYPE_CPU | FF_TOP_TYPE_DISK)) == 0) {
|
||||
return; // Memory usage is instantaneous; no baseline snapshot is needed
|
||||
}
|
||||
|
||||
if (startTick != 0 && preparedShowTypes == showTypes) {
|
||||
if (startTick != 0) {
|
||||
return; // Already prepared
|
||||
}
|
||||
|
||||
if (startTick != 0) {
|
||||
// The set of requested types changed; discard the stale baseline
|
||||
FF_LIST_FOR_EACH (FFTopProcessSnapshot, item, first) {
|
||||
ffStrbufDestroy(&item->name);
|
||||
}
|
||||
ffListDestroy(&first);
|
||||
}
|
||||
|
||||
// `showTypes` cannot change between this call and `ffDetectTopProcesses`: `ffPrepareCommandOption`
|
||||
// and `parseStructureCommand` both build the options through `initStructureModuleOptions`, which
|
||||
// merges the module object from the JSON config. So the baseline always matches what the second
|
||||
// snapshot collects and needs no re-validation.
|
||||
ffListInit(&first);
|
||||
startTick = ffTimeGetTick();
|
||||
preparedShowTypes = showTypes;
|
||||
ffTopGetProcessSnapshot(&first, showTypes);
|
||||
}
|
||||
|
||||
@@ -102,7 +96,7 @@ const char* ffDetectTopProcesses(FFTopOptions* options, FFlist* result) {
|
||||
ffStrbufInitMove(&item->name, &snap->name);
|
||||
}
|
||||
} else {
|
||||
if (startTick == 0 || preparedShowTypes != options->showTypes) {
|
||||
if (startTick == 0) {
|
||||
ffPrepareTopProcesses(options->showTypes);
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ void ffInitDiskIOOptions(FFDiskIOOptions* options) {
|
||||
|
||||
ffStrbufInit(&options->namePrefix);
|
||||
options->detectTotal = false;
|
||||
options->waitTime = 500;
|
||||
options->waitTime = 250;
|
||||
}
|
||||
|
||||
void ffDestroyDiskIOOptions(FFDiskIOOptions* options) {
|
||||
|
||||
@@ -192,7 +192,7 @@ void ffInitNetIOOptions(FFNetIOOptions* options) {
|
||||
#endif
|
||||
;
|
||||
options->detectTotal = false;
|
||||
options->waitTime = 500;
|
||||
options->waitTime = 250;
|
||||
}
|
||||
|
||||
void ffDestroyNetIOOptions(FFNetIOOptions* options) {
|
||||
|
||||
Reference in New Issue
Block a user