Public Access
S1 #11: bytes read and written, counted per network service
A Counted<> wrapper around the network clients adds what goes through their buffer read and write to a per-service counter (IRC, Gemini, Debug Console, Updates); the single-byte calls and print() end up there, so each byte counts once. `net` prints the totals. For TLS it's the plain text the service sees. Checked on the device: a Gemini fetch counts 164,986 in (a 164,970-byte page and its 16-byte header) and 42 out (the URL and CRLF). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
#include "traffic.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
|
||||
namespace roro::net {
|
||||
|
||||
namespace {
|
||||
constexpr size_t kUsers = static_cast<size_t>(User::Count);
|
||||
std::atomic<uint32_t> in_[kUsers], out_[kUsers];
|
||||
} // namespace
|
||||
|
||||
const char* userName(User user) {
|
||||
switch (user) {
|
||||
case User::Irc: return "IRC";
|
||||
case User::Gemini: return "Gemini";
|
||||
case User::DebugConsole: return "Debug Console";
|
||||
case User::Updates: return "Updates";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
void received(User user, size_t bytes) { in_[static_cast<size_t>(user)] += static_cast<uint32_t>(bytes); }
|
||||
void sent(User user, size_t bytes) { out_[static_cast<size_t>(user)] += static_cast<uint32_t>(bytes); }
|
||||
Traffic traffic(User user) { return {in_[static_cast<size_t>(user)], out_[static_cast<size_t>(user)]}; }
|
||||
|
||||
void resetTraffic() {
|
||||
for (size_t i = 0; i < kUsers; i++) in_[i] = out_[i] = 0;
|
||||
}
|
||||
|
||||
uint32_t bytesPerSecond(uint32_t before, uint32_t now, uint32_t elapsedMs) {
|
||||
if (!elapsedMs) return 0;
|
||||
return static_cast<uint32_t>(static_cast<uint64_t>(now - before) * 1000 / elapsedMs); // wraps with the counter
|
||||
}
|
||||
|
||||
std::string formatTraffic(uint32_t bytes) {
|
||||
char s[16];
|
||||
if (bytes < 1000) std::snprintf(s, sizeof s, "%u B", static_cast<unsigned>(bytes));
|
||||
else if (bytes < 10 * 1024) std::snprintf(s, sizeof s, "%.1f KB", bytes / 1024.0);
|
||||
else if (bytes < 1000 * 1024) std::snprintf(s, sizeof s, "%u KB", static_cast<unsigned>(bytes / 1024));
|
||||
else if (bytes < 10u * 1024 * 1024) std::snprintf(s, sizeof s, "%.1f MB", bytes / 1048576.0);
|
||||
else std::snprintf(s, sizeof s, "%u MB", static_cast<unsigned>(bytes / 1048576));
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace roro::net
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace roro::net {
|
||||
|
||||
// Bytes each network service has read and written since boot (S1, Q121), as the service sees
|
||||
// them: for TLS connections that's the plain text, without the handshake or record overhead.
|
||||
// Counted from the services' own tasks, read from the main loop.
|
||||
enum class User : uint8_t { Irc, Gemini, DebugConsole, Updates, Count };
|
||||
const char* userName(User user);
|
||||
|
||||
struct Traffic {
|
||||
uint32_t in = 0, out = 0;
|
||||
};
|
||||
void received(User user, size_t bytes);
|
||||
void sent(User user, size_t bytes);
|
||||
Traffic traffic(User user);
|
||||
void resetTraffic(); // for tests
|
||||
|
||||
uint32_t bytesPerSecond(uint32_t before, uint32_t now, uint32_t elapsedMs);
|
||||
std::string formatTraffic(uint32_t bytes); // "999 B", "1.5 KB", "12 KB", "1.7 MB"
|
||||
|
||||
} // namespace roro::net
|
||||
Reference in New Issue
Block a user