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