Performance improvements, better readme and complete python bindings
🧪 Test / test (push) Failing after 28m30s
🧪 Test / test (push) Failing after 28m30s
This commit is contained in:
+80
-2
@@ -1,6 +1,8 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <kpn/channel.hpp>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace kpn;
|
||||
|
||||
@@ -70,13 +72,21 @@ TEST_CASE("push to disabled channel is silently dropped", "[channel]") {
|
||||
REQUIRE(ch.size() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("disable clears existing queue contents", "[channel]") {
|
||||
TEST_CASE("disable stops accepting and unblocks pop", "[channel]") {
|
||||
// With the SPSC lock-free ring, disable() does not drain the ring immediately;
|
||||
// items are freed when the Channel is destroyed. What it must do is:
|
||||
// 1. reject further pushes (drops silently)
|
||||
// 2. unblock any waiting pop() (throws ChannelClosedError)
|
||||
Channel<int> ch(5);
|
||||
ch.push(1);
|
||||
ch.push(2);
|
||||
REQUIRE(ch.size() == 2);
|
||||
ch.disable();
|
||||
REQUIRE(ch.size() == 0);
|
||||
// Further pushes are dropped
|
||||
ch.push(3);
|
||||
REQUIRE(ch.size() <= 2);
|
||||
// pop() must throw even though items remain in the ring
|
||||
REQUIRE_THROWS_AS(ch.pop(), ChannelClosedError);
|
||||
}
|
||||
|
||||
TEST_CASE("enable re-accepts pushes after disable", "[channel]") {
|
||||
@@ -97,3 +107,71 @@ TEST_CASE("large type stored as shared_ptr — no copy on pop", "[channel]") {
|
||||
auto out = ch.pop();
|
||||
REQUIRE(out.tag == 123);
|
||||
}
|
||||
|
||||
// ── ChannelDataSize / bytes_pushed tests ─────────────────────────────────────
|
||||
|
||||
TEST_CASE("bytes_pushed uses sizeof(T) by default for POD type", "[channel][bandwidth]") {
|
||||
Channel<int> ch(10);
|
||||
ch.push(1);
|
||||
ch.push(2);
|
||||
ch.push(3);
|
||||
ch.pop(); ch.pop(); ch.pop();
|
||||
|
||||
auto snap = ch.snapshot("test");
|
||||
REQUIRE(snap.pushes == 3);
|
||||
REQUIRE(snap.bytes_pushed == 3 * sizeof(int));
|
||||
}
|
||||
|
||||
TEST_CASE("bytes_pushed uses sizeof(T) by default for large struct", "[channel][bandwidth]") {
|
||||
struct Blob { char data[256]; };
|
||||
Channel<Blob> ch(10);
|
||||
ch.push(Blob{});
|
||||
ch.push(Blob{});
|
||||
|
||||
auto snap = ch.snapshot("test");
|
||||
REQUIRE(snap.bytes_pushed == 2 * sizeof(Blob));
|
||||
}
|
||||
|
||||
// A fake heap-owning type whose logical payload size differs from sizeof.
|
||||
struct FakeFrame {
|
||||
std::vector<uint8_t> pixels;
|
||||
};
|
||||
|
||||
// Specialise ChannelDataSize so the channel counts actual pixel bytes.
|
||||
template<>
|
||||
struct kpn::ChannelDataSize<FakeFrame> {
|
||||
static std::size_t bytes(const FakeFrame& f) { return f.pixels.size(); }
|
||||
};
|
||||
|
||||
TEST_CASE("bytes_pushed uses ChannelDataSize specialisation for heap-owning type", "[channel][bandwidth]") {
|
||||
Channel<FakeFrame> ch(10);
|
||||
ch.push(FakeFrame{std::vector<uint8_t>(1000)});
|
||||
ch.push(FakeFrame{std::vector<uint8_t>(2000)});
|
||||
|
||||
auto snap = ch.snapshot("test");
|
||||
REQUIRE(snap.pushes == 2);
|
||||
REQUIRE(snap.bytes_pushed == 3000);
|
||||
// item_bytes is still sizeof(FakeFrame) — the struct header
|
||||
REQUIRE(snap.item_bytes == sizeof(FakeFrame));
|
||||
}
|
||||
|
||||
TEST_CASE("bandwidth_mbs is non-zero and correct for heap-owning type", "[channel][bandwidth]") {
|
||||
Channel<FakeFrame> ch(10);
|
||||
// Push 10 frames of 1 MB each
|
||||
for (int i = 0; i < 10; ++i)
|
||||
ch.push(FakeFrame{std::vector<uint8_t>(1'000'000)});
|
||||
|
||||
auto snap = ch.snapshot("test");
|
||||
// 10 MB over 1 second => 10.0 MB/s
|
||||
REQUIRE(snap.bandwidth_mbs(1.0) == Catch::Approx(10.0).epsilon(1e-6));
|
||||
// Without the fix (using sizeof), this would have been ~40 bytes/s ≈ 0.00004 MB/s.
|
||||
REQUIRE(snap.bandwidth_mbs(1.0) > 1.0);
|
||||
}
|
||||
|
||||
TEST_CASE("bandwidth_mbs returns 0 when elapsed_s is zero or negative", "[channel][bandwidth]") {
|
||||
Channel<int> ch(5);
|
||||
ch.push(42);
|
||||
auto snap = ch.snapshot("test");
|
||||
REQUIRE(snap.bandwidth_mbs(0.0) == 0.0);
|
||||
REQUIRE(snap.bandwidth_mbs(-1.0) == 0.0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user