ohmu
·
2026-10-15
1#include "diskio.h"
2
3#include "common/time.h"
4
5const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options);
6
7static FFlist ioCounters1;
8static double time1;
9
10void ffPrepareDiskIO(FFDiskIOOptions* options) {
11 if (options->detectTotal) {
12 return;
13 }
14
15 if (time1 != 0) {
16 return; // Already prepared
17 }
18
19 // The options cannot change between this call and `ffDetectDiskIO`: `ffPrepareCommandOption`
20 // and `parseStructureCommand` both build them through `initStructureModuleOptions`, which
21 // merges the module object from the JSON config. So the baseline always matches the second
22 // snapshot and needs no re-validation.
23 ffListInit(&ioCounters1);
24 ffDiskIOGetIoCounters(&ioCounters1, options);
25 time1 = ffTimeGetTick();
26}
27
28const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options) {
29 const char* error = nullptr;
30
31 if (options->detectTotal) {
32 error = ffDiskIOGetIoCounters(result, options);
33 if (error) {
34 return error;
35 }
36 return nullptr;
37 }
38
39 if (time1 == 0) {
40 ffPrepareDiskIO(options);
41 }
42
43 if (ioCounters1.length == 0) {
44 return "No physical disk found";
45 }
46
47 double time2 = ffTimeGetTick();
48 while (time2 - time1 < (double) options->waitTime) {
49 ffTimeSleep((uint32_t) (options->waitTime - (time2 - time1)));
50 time2 = ffTimeGetTick();
51 }
52
53 error = ffDiskIOGetIoCounters(result, options);
54 if (error) {
55 return error;
56 }
57
58 if (result->length != ioCounters1.length) {
59 return "Different number of physical disks. Hardware change?";
60 }
61
62 for (uint32_t i = 0; i < result->length; ++i) {
63 FFDiskIOResult* icPrev = FF_LIST_GET(FFDiskIOResult, ioCounters1, i);
64 FFDiskIOResult* icCurr = FF_LIST_GET(FFDiskIOResult, *result, i);
65 if (!ffStrbufEqual(&icPrev->devPath, &icCurr->devPath)) {
66 return "Physical disk device path changed";
67 }
68
69 static_assert(sizeof(FFDiskIOResult) - offsetof(FFDiskIOResult, bytesRead) == sizeof(uint64_t) * 4, "Unexpected struct FFDiskIOResult layout");
70 for (size_t off = offsetof(FFDiskIOResult, bytesRead); off < sizeof(FFDiskIOResult); off += sizeof(uint64_t)) {
71 uint64_t* prevValue = (uint64_t*) ((uint8_t*) icPrev + off);
72 uint64_t* currValue = (uint64_t*) ((uint8_t*) icCurr + off);
73 uint64_t temp = *currValue;
74 *currValue = (uint64_t) ((double) (*currValue - *prevValue) * 1000.0 / (time2 - time1)); // Calculate per second
75
76 // For next function call
77 *prevValue = temp;
78 }
79 }
80
81 // For next function call
82 time1 = time2;
83 // Leak ioCounters1 here
84
85 return nullptr;
86}