// Example 06 — Watchdog & Diagnostics (+ optional web debug UI) // // A four-stage pipeline with deliberately uneven node speeds: // // [source] --int--> [fast_filter] --int--> [slow_transform] --int--> [sink] // // The watchdog fires every second and prints a full diagnostics report: // - frames processed, throughput fps, exec time, blocked time per node // - channel fill %, peak fill %, pushes, overflows, bandwidth // - bottleneck hint (node with highest avg exec time) // // "slow_transform" sleeps 30 ms per item, making it the obvious bottleneck. // Watch the channel upstream of it saturate and the fps converge to ~33. // // Build with -DKPN_WEB_DEBUG=ON to also get a live D3 graph at localhost:9090. #include #include #include #include #include // ── Node functions ──────────────────────────────────────────────────────────── static int source() { // Produces at ~50 fps — faster than slow_transform (33 fps) so the // channel between filter and slow gradually fills, but not catastrophically std::this_thread::sleep_for(std::chrono::milliseconds(20)); static int n = 0; return ++n; } static int fast_filter(int x) { // Trivial work: ~0.1 ms return (x % 2 == 0) ? x : x + 1; } static int slow_transform(int x) { // Simulates expensive processing (e.g. a neural net inference step) std::this_thread::sleep_for(std::chrono::milliseconds(30)); return x * x; } static void sink(int x) { // Print every 10th result to avoid flooding the terminal if (x % 100 < 4) std::cout << "[sink] " << x << '\n'; } // ── main ────────────────────────────────────────────────────────────────────── int main() { using namespace kpn; // Larger capacity buffers so the fast nodes don't immediately overflow auto src = make_node (out<"v">{}, 16); auto filt = make_node (in<"v">{}, out<"v">{}, 16); auto slow = make_node (in<"v">{}, out<"v">{}, 8); auto snk = make_node (in<"v">{}, 8); Network net; // Watchdog fires every 1 second — prints the built-in diagnostics table // including the "Bottleneck hint" line net.set_watchdog_interval(std::chrono::milliseconds(1000)); net.add("source", src) .add("filter", filt) .add("slow", slow) .add("sink", snk) .connect("source", src.template output<"v">(), "filter", filt.template input<"v">()) .connect("filter", filt.template output<"v">(), "slow", slow.template input<"v">()) .connect("slow", slow.template output<"v">(), "sink", snk.template input<"v">()) .build(); std::cout << "Running for 30 seconds — watch 'slow' become the bottleneck.\n" << "Watchdog diagnostics print every 1 second.\n"; #ifdef KPN_WEB_DEBUG net.set_web_debug_port(9090); std::cout << "Web debug UI: http://localhost:9090 (live graph, auto-updates every 500 ms)\n"; #endif std::cout << '\n'; net.start(); std::this_thread::sleep_for(std::chrono::seconds(30)); net.stop(); std::cout << "\n=== Final diagnostics ===\n"; net.print_diagnostics(); }