fast-cli/src/lib/bandwidth.zig
Caeser af4d3971c9
Updated to zig 0.15.1 and zli 4.1.0
* Refactor: Update build process and improve memory management

- Commented out library tests in build.zig for clarity.
- Changed minimum Zig version to 0.15.1 in build.zig.zon.
- Modified root.zig to accept a Writer for output instead of using log.
- Updated bandwidth.zig tests to use std.Thread.sleep for consistency.
- Adjusted fast.zig to improve memory allocation handling.
- Enhanced http_latency_tester.zig to manage latencies with allocator.
- Refined speed_worker.zig to utilize std.Thread.sleep for delays.
- Improved measurement_strategy.zig to handle speed measurements with allocator.
- Updated main.zig to flush writer after command execution.

* Fix: Update zli dependency to use URL and hash instead of path

* Fix: Add newline to spinner output for better readability

* switch worksflows to using zig 0.15.1

---------

Co-authored-by: mikkelam <mikkelarm@gmail.com>
2025-11-17 13:42:35 +00:00

137 lines
3.9 KiB
Zig

const std = @import("std");
const assert = @import("std").debug.assert;
pub const SpeedUnit = enum {
bps,
kbps,
mbps,
gbps,
pub fn toString(self: SpeedUnit) []const u8 {
return switch (self) {
.bps => "bps",
.kbps => "Kbps",
.mbps => "Mbps",
.gbps => "Gbps",
};
}
};
pub const SpeedMeasurement = struct {
value: f64,
unit: SpeedUnit,
};
pub const BandwidthMeter = struct {
_bytes_transferred: u64 = 0,
_timer: std.time.Timer = undefined,
_started: bool = false,
pub fn init() BandwidthMeter {
return .{};
}
pub fn start(self: *BandwidthMeter) !void {
self._timer = try std.time.Timer.start();
self._started = true;
}
pub fn update_total(self: *BandwidthMeter, total_bytes: u64) void {
assert(self._started);
self._bytes_transferred = total_bytes;
}
pub fn bandwidth(self: *BandwidthMeter) f64 {
if (!self._started) return 0;
const delta_nanos = self._timer.read();
const delta_secs = @as(f64, @floatFromInt(delta_nanos)) / std.time.ns_per_s;
return @as(f64, @floatFromInt(self._bytes_transferred)) / delta_secs;
}
/// Get bandwidth with automatic unit selection for optimal readability
pub fn bandwidthWithUnits(self: *BandwidthMeter) SpeedMeasurement {
const speed_bps = self.bandwidth();
return selectOptimalUnit(speed_bps);
}
/// Convert bytes per second to optimal unit for display (in bits per second)
fn selectOptimalUnit(speed_bytes_per_sec: f64) SpeedMeasurement {
// Convert bytes/s to bits/s
const speed_bits_per_sec = speed_bytes_per_sec * 8.0;
const abs_speed = @abs(speed_bits_per_sec);
if (abs_speed >= 1_000_000_000) {
return SpeedMeasurement{ .value = speed_bits_per_sec / 1_000_000_000, .unit = .gbps };
} else if (abs_speed >= 1_000_000) {
return SpeedMeasurement{ .value = speed_bits_per_sec / 1_000_000, .unit = .mbps };
} else if (abs_speed >= 1_000) {
return SpeedMeasurement{ .value = speed_bits_per_sec / 1_000, .unit = .kbps };
} else {
return SpeedMeasurement{ .value = speed_bits_per_sec, .unit = .bps };
}
}
};
const testing = std.testing;
test "BandwidthMeter init" {
const meter = BandwidthMeter.init();
try testing.expect(!meter._started);
try testing.expectEqual(@as(u64, 0), meter._bytes_transferred);
}
test "BandwidthMeter start" {
var meter = BandwidthMeter.init();
try meter.start();
try testing.expect(meter._started);
}
test "BandwidthMeter record_bytes" {
var meter = BandwidthMeter.init();
try meter.start();
meter.update_total(1000);
meter.update_total(1500);
// Just test that bandwidth calculation works
const bw = meter.bandwidth();
try testing.expect(bw >= 0);
}
test "BandwidthMeter bandwidth calculation" {
var meter = BandwidthMeter.init();
try meter.start();
meter.update_total(1000); // 1000 bytes
// Sleep briefly to ensure time passes
std.Thread.sleep(std.time.ns_per_ms * 10); // 10ms
const bw = meter.bandwidth();
try testing.expect(bw > 0);
}
test "BandwidthMeter not started errors" {
var meter = BandwidthMeter.init();
// Should return 0 bandwidth when not started
try testing.expectEqual(@as(f64, 0), meter.bandwidth());
}
test "BandwidthMeter unit conversion" {
var meter = BandwidthMeter.init();
try meter.start();
// Test different speed ranges
meter._bytes_transferred = 1000;
meter._timer = try std.time.Timer.start();
std.Thread.sleep(std.time.ns_per_s); // 1 second
const measurement = meter.bandwidthWithUnits();
// Should automatically select appropriate unit
try testing.expect(measurement.value > 0);
try testing.expect(measurement.unit != .gbps); // Shouldn't be gigabits for small test
}