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:
@@ -15,6 +15,7 @@ using duration_t = std::chrono::duration<double, std::milli>; // milliseconds
|
||||
|
||||
struct ChannelStats {
|
||||
std::atomic<uint64_t> pushes{0};
|
||||
std::atomic<uint64_t> bytes_pushed{0};
|
||||
std::atomic<uint64_t> drops{0};
|
||||
std::atomic<uint64_t> overflows{0};
|
||||
std::atomic<uint64_t> pops{0};
|
||||
@@ -24,8 +25,9 @@ struct ChannelStats {
|
||||
ChannelStats(const ChannelStats&) = delete;
|
||||
ChannelStats& operator=(const ChannelStats&) = delete;
|
||||
|
||||
void record_push(std::size_t current_fill) {
|
||||
void record_push(std::size_t current_fill, std::size_t data_bytes) {
|
||||
pushes.fetch_add(1, std::memory_order_relaxed);
|
||||
bytes_pushed.fetch_add(data_bytes, std::memory_order_relaxed);
|
||||
std::size_t prev = peak_fill.load(std::memory_order_relaxed);
|
||||
while (current_fill > prev &&
|
||||
!peak_fill.compare_exchange_weak(prev, current_fill,
|
||||
@@ -54,6 +56,12 @@ struct NodeStats {
|
||||
// blocked on mutexes/channels. Sampled once per frame.
|
||||
std::atomic<int64_t> total_cpu_us{0}; // cumulative CPU µs consumed
|
||||
|
||||
// Pool scheduling stats — only meaningful for PoolNode / InterruptNode.
|
||||
// exec_start_us: wall-clock µs when fire_once began; 0 when idle.
|
||||
// Used by the watchdog to detect hung nodes (elapsed > max_exec_time).
|
||||
std::atomic<int64_t> queue_wait_us{0}; // cumulative µs spent in pool queue
|
||||
std::atomic<int64_t> exec_start_us{0}; // non-zero while fire_once is running
|
||||
|
||||
NodeStats() = default;
|
||||
NodeStats(const NodeStats&) = delete;
|
||||
NodeStats& operator=(const NodeStats&) = delete;
|
||||
@@ -71,6 +79,11 @@ struct NodeStats {
|
||||
+ static_cast<int64_t>(ts.tv_nsec) / 1'000;
|
||||
}
|
||||
|
||||
void record_queue_wait(duration_t wait) {
|
||||
int64_t us = static_cast<int64_t>(wait.count() * 1000.0);
|
||||
if (us > 0) queue_wait_us.fetch_add(us, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void record_exec(duration_t exec_time, duration_t blocked_time,
|
||||
const struct timespec& cpu_before, const struct timespec& cpu_after) {
|
||||
frames_processed.fetch_add(1, std::memory_order_relaxed);
|
||||
@@ -105,10 +118,11 @@ struct ChannelSnapshot {
|
||||
std::size_t current_fill;
|
||||
std::size_t peak_fill;
|
||||
uint64_t pushes;
|
||||
uint64_t bytes_pushed; // actual bytes accumulated via channel_data_size<T>
|
||||
uint64_t drops;
|
||||
uint64_t overflows;
|
||||
uint64_t pops;
|
||||
std::size_t item_bytes; // sizeof(T) for the stored type — set by Channel<T>
|
||||
std::size_t item_bytes; // sizeof(T) — nominal struct size, not necessarily data size
|
||||
|
||||
double fill_pct() const {
|
||||
return capacity ? 100.0 * current_fill / capacity : 0.0;
|
||||
@@ -116,10 +130,10 @@ struct ChannelSnapshot {
|
||||
double peak_pct() const {
|
||||
return capacity ? 100.0 * peak_fill / capacity : 0.0;
|
||||
}
|
||||
// Bandwidth in MB/s: bytes transferred / elapsed seconds
|
||||
// Bandwidth in MB/s: actual bytes transferred / elapsed seconds
|
||||
double bandwidth_mbs(double elapsed_s) const {
|
||||
if (elapsed_s <= 0.0 || item_bytes == 0) return 0.0;
|
||||
return static_cast<double>(pushes * item_bytes) / elapsed_s / 1e6;
|
||||
if (elapsed_s <= 0.0) return 0.0;
|
||||
return static_cast<double>(bytes_pushed) / elapsed_s / 1e6;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -128,10 +142,27 @@ struct NodeSnapshot {
|
||||
uint64_t frames_processed;
|
||||
double ema_exec_ms;
|
||||
double max_exec_ms;
|
||||
double total_blocked_ms;
|
||||
double total_blocked_ms; // ThreadPerNode: time blocked in channel pop
|
||||
double throughput_fps;
|
||||
double total_cpu_ms; // cumulative CPU time consumed by this node's thread
|
||||
double cpu_util_pct; // exec_ms / (exec_ms + blocked_ms) * 100
|
||||
double total_cpu_ms; // cumulative CPU time consumed by this node's thread
|
||||
double cpu_util_pct; // exec_ms / (exec_ms + blocked_ms) * 100
|
||||
double queue_wait_ms{0}; // PoolNode: cumulative time spent in pool queue
|
||||
};
|
||||
|
||||
// ── Pool statistics + snapshot ────────────────────────────────────────────────
|
||||
|
||||
struct PoolSnapshot {
|
||||
std::string name;
|
||||
std::size_t thread_count;
|
||||
std::size_t queue_depth; // tasks waiting in the priority queue
|
||||
std::size_t active_count; // tasks currently executing
|
||||
uint64_t tasks_submitted;
|
||||
uint64_t tasks_completed;
|
||||
};
|
||||
|
||||
struct IPoolProbe {
|
||||
virtual ~IPoolProbe() = default;
|
||||
virtual PoolSnapshot snapshot(const std::string& name) const = 0;
|
||||
};
|
||||
|
||||
// ── Cross-network snapshot (used by DebugHub) ─────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user