diff --git a/.gitignore b/.gitignore index 66fa602..e9f2249 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ corpus # Analysis artifacts (depgraph + spectral) **/deps.dot **/deps.html +docs/architecture.dot +docs/architecture.html diff --git a/Cargo.toml b/Cargo.toml index 2ce9c26..9d83c9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ getrandom = ["dep:getrandom"] serde = ["dep:serde"] tracing = ["dep:tracing"] no_random = [] # compile without access to a source of randomness +transport = [] # transport-agnostic messaging (no mandatory deps; codec is user-provided) [dependencies] getrandom = { version = "0.2", optional = true } diff --git a/README.md b/README.md index 764e683..fc9f95d 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # swactor -Small, WASM-compatible actor runtime for Rust, with Python and WebAssembly -bindings. +Minimal actor runtime for Rust. Single-threaded or multi-threaded, with +Python and WebAssembly bindings. -## Quick Start (Rust) +## Quick Start ```rust use swactor::actor::{ActorAddress, ActorInterface}; @@ -39,221 +39,92 @@ fn main() { } ``` -## Quick Start (Python) +## Features + +### Actor Model + +Actors implement one trait (`ActorInterface`), receive one message type, and +hold mutable state. No lifecycle hooks, no supervision trees, no async. + +Every actor gets a 32-byte globally unique `ActorAddress`. The same +`ctx.send(addr, msg)` call works whether the target is on the same worker, +a different worker thread, an external inbox, or a remote process. + +Single-threaded mode (`rt.tick()`) gives deterministic frame-level control. +Multi-threaded mode (`rt.run()`) spawns OS threads with adaptive backoff. + +See [docs/actor-model.md](docs/actor-model.md) and +[docs/runtime.md](docs/runtime.md) for the full model. + +### Transport + +Pluggable cross-process messaging. User-provided codecs handle serialization +(gRPC/protobuf, bincode, hand-rolled — no serde bounds imposed) and +user-provided transports handle delivery (TCP, in-memory, gRPC channel). ```bash -uv pip install . # builds the Rust extension automatically +cargo build --features transport +cargo run --example tcp_ping_pong --features transport -- receiver # terminal 1 +cargo run --example tcp_ping_pong --features transport -- sender # terminal 2 ``` -Single-threaded — caller drives each tick: +See [docs/transport.md](docs/transport.md) for the routing chain, codec +registry, and address resolution. -```python -from swactor import Runtime +### Runtime Dashboard -def echo(ctx, msg): - ctx.send(msg["reply_to"], f"hello, {msg['name']}!") +Live web dashboard for monitoring actors, message throughput, and mailbox +depths. Supports trace recording and replay at configurable speed. -rt = Runtime() -addr = rt.spawn(echo) -inbox = rt.inbox() -rt.send(addr, {"name": "world", "reply_to": inbox.addr}) -rt.tick() -print(inbox.try_recv()) # "hello, world!" -``` +Includes hand-authored SVG diagrams (actor lifecycle, message lifecycle, +tick cycle, transport routing) and generated diagrams from DOT sources +(architecture, dataflow, type erasure). -Multi-threaded — workers run on background threads: +See [crates/runtime-dashboard/](crates/runtime-dashboard/README.md). -```python -import asyncio -from swactor import Runtime, RuntimeConfig +### Language Bindings -async def main(): - rt = Runtime(RuntimeConfig(num_threads=2)) - - def echo(ctx, msg): - ctx.send(msg["reply_to"], f"hello, {msg['name']}!") - - addr = rt.spawn(echo) - inbox = rt.inbox() - handle = rt.run() # spawns worker threads, consumes rt - - for name in ["alice", "bob", "charlie"]: - handle.send(addr, {"name": name, "reply_to": inbox.addr}) - while (reply := inbox.try_recv()) is None: - await asyncio.sleep(0.01) - print(reply) - - handle.shutdown() - handle.join() - -asyncio.run(main()) -``` - -## Quick Start (WASM) - -The `wasm/` crate wraps swactor for use from JavaScript via `wasm-bindgen`. -It runs single-threaded with the caller driving `tick()` — a natural fit -for game loops, simulations, or any frame-based update cycle. +**Python** — PyO3 via Maturin. Spawn actors from Python callables, pass +dicts as messages, single-threaded or multi-threaded. ```bash -cd wasm && wasm-pack build --target nodejs # or --target web +cd crates/swactor-python && maturin develop ``` -```javascript -import { SwactorRuntime } from "./wasm/pkg/swactor_wasm.js"; +Examples in `examples/python/` (single-thread, async, Jupyter notebook). -const rt = new SwactorRuntime(); - -// spawn a counter actor — accumulates values sent to it -const counter = rt.spawn_counter(); - -// spawn a relay that forwards messages to the counter -const relay = rt.spawn_relay(counter); - -// send through the relay -rt.send(relay, 5); -rt.send(relay, 7); - -rt.tick(); // relay receives and forwards -rt.tick(); // counter receives forwarded messages - -// drain results from the inbox -let v; -while ((v = rt.try_recv()) !== undefined) { - console.log(v); // 5, then 12 -} - -rt.free(); -``` - -The WASM crate uses the `no_random` feature (deterministic address -generation) so there's no dependency on system RNG. - -## Running the Examples +**WASM** — wasm-bindgen. Runs single-threaded with deterministic addressing +(`no_random` feature). ```bash -cargo run --example hello # single actor, request/response -cargo run --example ring # 500 actors in a ring topology +cd crates/swactor-wasm && wasm-pack build --target nodejs ``` -## Multi-threaded Mode +### Connectome Analysis -Pass `num_threads` in the config. The runtime spawns OS threads and runs -workers autonomously — no `tick()` calls needed. +Structural analysis of the internal dependency graph. -```rust -let mut config = RuntimeConfig::default(); -config.num_threads = 4; -let rt = Runtime::new(config); +- **depgraph** (`tools/depgraph/`) — AST-based extraction of module + dependencies, outputs GraphViz DOT +- **spectral** (`tools/spectral/`) — Laplacian eigenvalue analysis, + Connectome Complexity Index (CCI), coupling heatmaps, interactive HTML + dashboard -let addr = rt.spawn(MyActor::default()).unwrap(); -let handle = rt.run().unwrap(); // consumes rt, spawns 4 threads - -// use handle.runtime to spawn/send while workers run -handle.runtime.send_to(addr, MyMsg).unwrap(); - -handle.shutdown(); -handle.join(); +```bash +cargo run --manifest-path tools/depgraph/Cargo.toml -- --src-dir src/ --output deps +python tools/spectral/spectral_analysis.py deps.dot ``` -## Architecture - -The runtime is layered: **Runtime** → **Workers** → **ActorPool** → **Actors**. - -``` -┌─ Runtime (Arc, shared) ──────────────────────────────────────┐ -│ │ -│ AddressMap Placement InboxRegistry is_running │ -│ (addr→worker) (round-robin) (external inboxes) (AtomicBool) │ -│ │ -│ transfer_txs[] spawn_txs[] │ -│ (one Sender per worker) (one Sender per worker) │ -│ │ -└───────┬───────────────┬───────────────┬───────────────────────┘ - │ │ │ - v v v - ┌─ Worker 0 ──┐ ┌─ Worker 1 ──┐ ┌─ Worker 2 ──┐ - │ ActorPool │ │ ActorPool │ │ ActorPool │ - │ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │ - │ │mailbox │ │ │ │mailbox │ │ │ │mailbox │ │ - │ │ actor │ │ │ │ actor │ │ │ │ actor │ │ - │ └────────┘ │ │ └────────┘ │ │ └────────┘ │ - │ ┌────────┐ │ │ ┌────────┐ │ │ │ - │ │mailbox │ │ │ │mailbox │ │ └──────────────┘ - │ │ actor │ │ │ │ actor │ │ - │ └────────┘ │ │ └────────┘ │ - └──────────────┘ └──────────────┘ -``` - -Each worker runs a **four-phase tick loop**: - -1. **Drain spawn queue** — add newly spawned actors to the pool -2. **Drain transfer queue** — deliver cross-worker messages to mailboxes -3. **Tick all actors** — pop messages, call handlers, buffer outgoing sends -4. **Drain pending local** — deliver same-worker messages for the next tick - -Messages are type-erased (`Box`) in transit and downcast -back to the concrete type at delivery. Mismatched types are silently dropped. - -Detailed architecture docs live in `docs/`: - -| Document | Covers | -|----------|--------| -| [Worker Thread](docs/worker-thread.md) | Tick phases, backoff, message routing, full system topology | -| [Runtime](docs/runtime.md) | Runtime, Ctx, Inbox, RuntimeHandle, stats | -| [Actor Model](docs/actor-model.md) | Traits, type erasure, addresses | -| [Channels & Shared State](docs/channels.md) | HybridChannel, AddressMap, Placement | - -## Source Layout - -``` -src/ -├── lib.rs module root, feature gates, get_random() -├── actor.rs Message, ActorInterface, ActorAddress, type erasure -├── runtime.rs Runtime, Ctx, Inbox, RuntimeHandle, InboxRegistry -├── worker/ -│ ├── mod.rs Worker, WorkerContext, ActorPool, tick loop -│ └── tests.rs worker unit tests with step-based DSL -├── channel.rs HybridChannel (ArrayQueue + SegQueue), Sender/Receiver -├── config.rs RuntimeConfig, BackoffPolicy -├── address_map.rs AddressMap (RwLock), Placement (round-robin) -├── error.rs Error type -└── python.rs PyO3 bindings (feature = "python") - -wasm/ -├── Cargo.toml separate crate, depends on swactor with no_random -├── src/lib.rs wasm-bindgen wrapper (SwactorRuntime) -└── test.mjs Node.js test suite - -examples/ -├── hello.rs echo actor -├── ring.rs ring topology -└── python/ - ├── hello_single_thread.py minimal Python example - ├── hello_async.py multi-threaded + asyncio - └── getting_started.ipynb Jupyter notebook - -tests/ -├── runtime_api.rs single + multi-thread integration tests -├── stats_demo.rs stats snapshot tests -└── test_python.py Python binding tests -``` +See [docs/connectome.md](docs/connectome.md) for metric interpretation. ## Building & Testing ```bash -# Rust -cargo test # run all tests -cargo run --example hello # run an example +cargo test # all tests +cargo test --features transport # include transport tests +cargo run --example hello # single actor example +cargo run --example ring # 500-actor ring topology cargo bench # benchmarks (criterion) - -# Python bindings (requires Rust toolchain on PATH) -uv pip install . # build + install -uv run python3 tests/test_python.py # run Python tests - -# WASM bindings -cd wasm && wasm-pack build --target nodejs -node test.mjs # run WASM tests ``` ## Feature Flags @@ -261,19 +132,20 @@ node test.mjs # run WASM tests | Flag | Default | What it does | |------|---------|--------------| | `getrandom` | yes | System RNG for actor addresses | -| `no_random` | no | Deterministic counter (for WASM / reproducible tests) | -| `python` | no | PyO3 bindings, builds cdylib wheel | -## Connectome analysis +| `no_random` | no | Deterministic counter (WASM / reproducible tests) | +| `transport` | no | Pluggable remote messaging (codec + transport) | +| `tracing` | no | `tracing` instrumentation for runtime internals | +| `serde` | no | Serde derives for stats types | +| `python` | no | PyO3 bindings (cdylib wheel) | -Spectral analysis of the internal dependency graph, producing a Connectome Complexity Index (CCI) and visual dashboards. +## Documentation -```sh -# Generate the dependency DAG -cargo run --manifest-path tools/depgraph/Cargo.toml -- --src-dir src/ --output deps - -# Run spectral analysis (outputs to docs/connectome/) -source .venv/bin/activate -python tools/spectral/spectral_analysis.py deps.dot -``` - -This produces a text report, an interactive HTML dashboard, and a static PNG dashboard in `docs/connectome/`. See [docs/connectome.md](docs/connectome.md) for details on the metrics and interpretation. +| Document | Covers | +|----------|--------| +| [Actor Model](docs/actor-model.md) | Traits, type erasure, addresses | +| [Runtime](docs/runtime.md) | Runtime, Ctx, Inbox, RuntimeHandle, stats | +| [Worker Thread](docs/worker-thread.md) | Tick phases, backoff, routing, full system topology | +| [Channels](docs/channels.md) | HybridChannel, AddressMap, Placement | +| [Transport](docs/transport.md) | Codec, Transport, remote messaging, address resolution | +| [Connectome](docs/connectome.md) | CCI metrics, spectral analysis interpretation | +| [Dashboard](crates/runtime-dashboard/README.md) | Live web UI, trace recording, diagram index | diff --git a/crates/runtime-dashboard/README.md b/crates/runtime-dashboard/README.md index cc45ba0..149396b 100644 --- a/crates/runtime-dashboard/README.md +++ b/crates/runtime-dashboard/README.md @@ -1,36 +1,3 @@ # runtime-dashboard -Visual dashboard and architectural diagrams for the swactor runtime. - -## Generating Diagrams - -Render all `.dot` sources into SVGs: - -```bash -./render_docs.sh -``` - -**Prerequisites** (one of): -- [Graphviz](https://graphviz.org/) — `apt install graphviz` / `brew install graphviz` -- [Node.js](https://nodejs.org/) — the script auto-installs `@viz-js/viz` into `tools/` - -Generated SVGs are written to `docs/generated/` (gitignored). - -## Diagram Index - -### DOT sources (`docs/*.dot` → `docs/generated/*.svg`) - -| Diagram | Description | -|---------|-------------| -| `architecture.dot` | Structural map of all structs/traits, grouped by module, with ownership/Arc/borrow/trait-impl edges | -| `dataflow.dot` | 5 behavioral flows: cross-worker send, same-worker send, actor spawn, external inbox, 6-phase tick cycle | -| `tick_cycle.dot` | Focused view of the `Worker::tick_once` pipeline and its 6 phases | -| `type_erasure.dot` | How generic message/actor types are erased via `Box` and `Box` | - -### Hand-authored SVGs (`docs/*.svg`, committed) - -| Diagram | Description | -|---------|-------------| -| `actor_lifecycle.svg` | Lifecycle states of an actor from spawn to shutdown | -| `message_lifecycle.svg` | Path of a message from send through inbox to handler | -| `runtime_lifecycle.svg` | Runtime startup, worker creation, and shutdown sequence | +Visual dashboard for the swactor runtime. \ No newline at end of file diff --git a/crates/runtime-dashboard/docs/architecture.svg b/crates/runtime-dashboard/docs/architecture.svg deleted file mode 100644 index 4d216f8..0000000 --- a/crates/runtime-dashboard/docs/architecture.svg +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - -architecture - - -cluster_legend - -Legend - - -cluster_runtime - -runtime.rs - - -cluster_actor - -actor.rs - - -cluster_delivery - -delivery.rs - - -cluster_worker - -worker.rs - - -cluster_channel - -channel.rs - - -cluster_stats - -stats.rs - - -cluster_config - -config.rs - - - -legend - -─────── -Ownership (solid) -━━━━━━━ -Arc-shared (bold orange) -- - - - - - -Borrow / &'a (dashed purple) -· · · · · ·▷ -Trait impl (dotted green) - - - -Runtime - - - -Runtime - -config: RuntimeConfig - -address_map: Arc<AddressMap> - -inbox_registry: Arc<InboxRegistry> - -transfer_txs: Vec<Sender<Envelope>> - -spawn_txs: Vec<Sender<(Addr, Box<dyn AnyActor>)>> - -placement: Placement - -is_running: AtomicBool - -worker_stats: Vec<Arc<WorkerStats>> - -tick_workers: RefCell<Vec<Worker>> - - - -ContextInner - -«trait» ContextInner -fn send_any(addr, msg) -fn spawn_any(addr, actor) - - - -Runtime->ContextInner - - -impl - - - -AddressMap - - - -AddressMap - -inner: RwLock<HashMap<ActorAddress, WorkerId>> - - - -Runtime->AddressMap - - -Arc - - - -Placement - - - -Placement - -next: AtomicUsize - -num_workers: usize - - - -Runtime->Placement - - -owns - - - -InboxRegistry - - - -InboxRegistry - -senders: RwLock<HashMap<Addr, Arc<dyn SenderT>>> - - - -Runtime->InboxRegistry - - -Arc - - - -Worker - - - -Worker - -id: WorkerId - -pool: ActorPool - -transfer_rx: Receiver<Envelope> - -spawn_rx: Receiver<(Addr, Box<dyn AnyActor>)> - -stats: Arc<WorkerStats> - - - -Runtime->Worker - - -RefCell<Vec<>> - - - -SenderCh - - - -Sender<T> - -queue: Arc<HybridChannel<T>> - - - -Runtime->SenderCh - - -transfer_txs + -spawn_txs - - - -WorkerStats - - - -WorkerStats - -num_actors: AtomicUsize - -total_mailbox_depth: AtomicUsize - -messages_processed: AtomicU64 - - - -Runtime->WorkerStats - - -Vec<Arc> - - - -RuntimeConfig - - - -RuntimeConfig - -max_actors: usize - -actor_max_messages: usize - -num_threads: usize - -backoff_policy: BackoffPolicy - - - -Runtime->RuntimeConfig - - -owns - - - -RuntimeHandle - - - -RuntimeHandle - -runtime: Arc<Runtime> - -threads: Vec<JoinHandle<()>> - - - -RuntimeHandle->Runtime - - -Arc - - - -Inbox - - - -Inbox<M> - -addr: ActorAddress - -inner: Receiver<M> - - - -ActorAddress - - - -ActorAddress - -0: [u8; 32] - -Copy, Eq, Hash - - - -Inbox->ActorAddress - - -addr - - - -ReceiverCh - - - -Receiver<T> - -queue: Arc<HybridChannel<T>> - - - -Inbox->ReceiverCh - - -owns - - - -Actor - - - -Actor<A> - -0: A   -(where A: ActorInterface) - - - -ActorInterface - -«trait» ActorInterface -type Incoming: Message -type Response: Message -fn handle(&mut self, ctx, msg) - - - -Actor->ActorInterface - - -wraps A: impl - - - -AnyActor - -«trait» AnyActor -fn handle_any(&mut self, ctx, msg) - - - -Actor->AnyActor - - -impl - - - -Ctx - - - -Ctx<'a> - -inner: &'a dyn ContextInner - -self_addr: ActorAddress - - - -Ctx->ActorAddress - - -self_addr - - - -Ctx->ContextInner - - -&'a dyn - - - -MessageTrait - -«trait» Message -'static + Clone + Send + Sync - - - -Envelope - - - -Envelope - -dest: ActorAddress - -payload: Box<dyn Any + Send> - - - -Envelope->ActorAddress - - -dest - - - -WorkerId - - - -WorkerId - -0: usize - - - -AddressMap->ActorAddress - - -HashMap key - - - -AddressMap->WorkerId - - -HashMap val - - - -SenderT - -«trait» SenderT -fn try_send_any(msg: Box<dyn Any>) - - - -InboxRegistry->SenderT - - -Arc<dyn> - - - -TickContext - - - -TickContext<'a> - -address_map: &'a AddressMap - -transfer_txs: &'a [Sender<Envelope>] - -spawn_txs: &'a [Sender<...>] - -placement: &'a Placement - -inbox_registry: &'a InboxRegistry - -config: &'a RuntimeConfig - - - -TickContext->AddressMap - - -&'a - - - -TickContext->Placement - - -&'a - - - -TickContext->InboxRegistry - - -&'a - - - -TickContext->SenderCh - - -&'a [] - - - -TickContext->RuntimeConfig - - -&'a - - - -Worker->WorkerId - - -id - - - -ActorPool - - - -ActorPool - -actors: HashMap<ActorAddress, ActorSlot> - - - -Worker->ActorPool - - -owns - - - -Worker->ReceiverCh - - -transfer_rx + -spawn_rx - - - -Worker->WorkerStats - - -Arc - - - -WorkerContext - - - -WorkerContext<'a> - -worker_id: WorkerId - -tc: &'a TickContext<'a> - -pending_local: &'a RefCell<Vec<...>> - - - -WorkerContext->ContextInner - - -impl - - - -WorkerContext->TickContext - - -&'a - - - -ActorSlot - - - -ActorSlot - -mailbox: VecDeque<Box<dyn Any + Send>> - -actor: Box<dyn AnyActor> - - - -ActorPool->ActorSlot - - -HashMap<Addr, _> - - - -ActorSlot->AnyActor - - -Box<dyn> - - - -HybridChannel - - - -HybridChannel<T> - -ring: ArrayQueue<T> - -overflow: SegQueue<T> - - - -HybridChannel->HybridChannel - - - - -SenderCh->SenderT - - -impl for -Sender<M> - - - -SenderCh->HybridChannel - - -Arc - - - -ReceiverCh->HybridChannel - - -Arc - - - -WorkerInfo - - - -WorkerInfo - -id: usize - -num_actors: usize - -mailbox_depth: usize - -messages_processed: u64 - - - -RuntimeStats - - - -RuntimeStats - -num_workers: usize - -actors: Vec<(ActorAddress, usize)> - -workers: Vec<WorkerInfo> - - - -RuntimeStats->WorkerInfo - - -Vec<> - - - -BackoffPolicy - - - -BackoffPolicy - -spin_threshold: u32 - -yield_threshold: u32 - -sleep_increment_us: u64 - -sleep_max_us: u64 - - - -RuntimeConfig->BackoffPolicy - - -owns - - - diff --git a/crates/runtime-dashboard/docs/actor_lifecycle.svg b/docs/actor_lifecycle.svg similarity index 100% rename from crates/runtime-dashboard/docs/actor_lifecycle.svg rename to docs/actor_lifecycle.svg diff --git a/docs/architecture.svg b/docs/architecture.svg new file mode 100644 index 0000000..8ef737a --- /dev/null +++ b/docs/architecture.svg @@ -0,0 +1,1118 @@ + + + + + + +swactor + +swactor — internal dependency DAG + +cluster_actor + +actor + + +cluster_worker + +worker + + +cluster_channel + +channel + + +cluster_error + +error + + +cluster_config + +config + + +cluster_delivery + +delivery + + +cluster_stats + +stats + + +cluster_runtime + +runtime + + +cluster_transport + +transport  (feature-gated) + + + +Message + +«trait» Message + + + +ActorInterface + +«trait» ActorInterface + +Incoming(Message) +Response(Message) +handle((&self, &Ctx, Self::Incoming)) + + + +ActorInterface->Message + + +Incoming + + + +Ctx + +Ctx + +inner: &'a dyn ContextInner +self_addr: ActorAddress + + + +ActorInterface->Ctx + + +handle + + + +ActorAddress + +ActorAddress + +0: [u8; ..] + + + +Actor + +Actor + +0: A + + + +AnyActor + +«trait» AnyActor + +handle_any((&self, &Ctx, Box<dyn Any + Send>)) + + + +Actor->AnyActor + + +impl + + + +Actor->Ctx + + +handle_any() param + + + +AnyActor->Ctx + + +handle_any + + + +ContextInner + +«trait» ContextInner + +send_any((&self, ActorAddress, Box<dyn Any + Send>) → Result<(), Error>) +spawn_any((&self, ActorAddress, Box<dyn AnyActor>) → Result<(), Error>) + + + +ContextInner->ActorAddress + + +send_any + + + +ContextInner->AnyActor + + +spawn_any + + + +Error + +Error + +0: Box<dyn std :: error :: Error + Send + Sync + 'static> + + + +ContextInner->Error + + +send_any + + + +Ctx->ActorAddress + + +self_addr + + + +Ctx->ContextInner + + +inner + + + +Ctx->Error + + +send() param + + + +Worker + +Worker + +id: WorkerId +pool: ActorPool +transfer_rx: Receiver<Envelope> +spawn_rx: Receiver<(ActorAddress, Box<dyn AnyActor>)> +stats: Arc<WorkerStats> +mailbox_snapshot: Arc<std::sync::Mutex<Vec<(ActorAddress, usize)>>> + + + +Worker->ActorAddress + + +spawn_rx + + + +Worker->AnyActor + + +spawn_rx + + + +ActorPool + +ActorPool + +actors: HashMap<ActorAddress, ActorSlot> + + + +Worker->ActorPool + + +pool + + + +Receiver + +Receiver + +queue: Arc<HybridChannel<T>> + + + +Worker->Receiver + + +transfer_rx + + + +WorkerId + +WorkerId + +0: usize + + + +Worker->WorkerId + + +id + + + +Envelope + +Envelope + +dest: ActorAddress +payload: Box<dyn Any + Send> + + + +Worker->Envelope + + +transfer_rx + + + +TickContext + +TickContext + +address_map: &'a AddressMap +transfer_txs: &'a [Sender<Envelope>] +spawn_txs: &'a [Sender<(ActorAddress, Box<dyn AnyActor>)>] +placement: &'a Placement +inbox_registry: &'a InboxRegistry +config: &'a RuntimeConfig +codec_registry: Option<&'a crate::transport::CodecRegistry> +transport_router: Option<&'a crate::transport::TransportRouter> + + + +Worker->TickContext + + +tick_once() param + + + +WorkerStats + +WorkerStats + +num_actors: AtomicUsize +total_mailbox_depth: AtomicUsize +messages_processed: AtomicU64 +local_sends: AtomicU64 +cross_sends: AtomicU64 +inbox_sends: AtomicU64 +type_mismatches: AtomicU64 +panics: AtomicU64 +tick_timings: std::sync::Mutex<VecDeque<TickTiming>> + + + +Worker->WorkerStats + + +stats + + + +WorkerContext + +WorkerContext + +worker_id: WorkerId +tc: &'a TickContext<'a> +pending_local: &'a RefCell<Vec<(ActorAddress, Box<dyn Any + Send>)>> +stats: &'a WorkerStats + + + +WorkerContext->ActorAddress + + +pending_local + + + +WorkerContext->AnyActor + + +spawn_any() param + + + +WorkerContext->ContextInner + + +impl + + + +WorkerContext->Error + + +send_any() param + + + +WorkerContext->WorkerId + + +worker_id + + + +WorkerContext->TickContext + + +tc + + + +WorkerContext->WorkerStats + + +stats + + + +ActorSlot + +ActorSlot + +mailbox: VecDeque<Box<dyn Any + Send>> +actor: Box<dyn AnyActor> + + + +ActorSlot->AnyActor + + +actor + + + +ActorPool->ActorAddress + + +actors + + + +ActorPool->AnyActor + + +insert() param + + + +ActorPool->ContextInner + + +tick_all() param + + + +ActorPool->ActorSlot + + +actors + + + +ActorPool->WorkerStats + + +tick_all() param + + + +HybridChannel + +HybridChannel + +ring: ArrayQueue<T> +overflow: SegQueue<T> + + + +Receiver->HybridChannel + + +queue + + + +Sender + +Sender + +queue: Arc<HybridChannel<T>> + + + +Receiver->Sender + + +new_sender() param + + + +Sender->HybridChannel + + +queue + + + +SenderT + +«trait» SenderT + +try_send_any((&self, Box<dyn Any + Send>)) + + + +Sender->SenderT + + +impl + + + +BackoffPolicy + +BackoffPolicy + +spin_threshold: u32 +yield_threshold: u32 +sleep_increment_us: u64 +sleep_max_us: u64 + + + +RuntimeConfig + +RuntimeConfig + +max_actors: usize +actor_max_messages: usize +num_threads: usize +backoff_policy: BackoffPolicy + + + +RuntimeConfig->BackoffPolicy + + +backoff_policy + + + +AddressMap + +AddressMap + +inner: RwLock<HashMap<ActorAddress, WorkerId>> + + + +AddressMap->ActorAddress + + +inner + + + +AddressMap->WorkerId + + +inner + + + +Placement + +Placement + +next: AtomicUsize +num_workers: usize + + + +Placement->WorkerId + + +next_worker() param + + + +Envelope->ActorAddress + + +dest + + + +InboxRegistry + +InboxRegistry + +senders: RwLock<HashMap<ActorAddress, Arc<dyn SenderT>>> + + + +InboxRegistry->ActorAddress + + +senders + + + +InboxRegistry->Error + + +try_deliver() param + + + +InboxRegistry->SenderT + + +senders + + + +TickContext->ActorAddress + + +spawn_txs + + + +TickContext->AnyActor + + +spawn_txs + + + +TickContext->Sender + + +transfer_txs + + + +TickContext->Error + + +route_nonlocal() param + + + +TickContext->RuntimeConfig + + +config + + + +TickContext->AddressMap + + +address_map + + + +TickContext->Placement + + +placement + + + +TickContext->Envelope + + +transfer_txs + + + +TickContext->InboxRegistry + + +inbox_registry + + + +CodecRegistry + +CodecRegistry + +encoders: HashMap<TypeId, EncodeFn> +decoders: HashMap<String, DecodeFn> + + + +TickContext->CodecRegistry + + +codec_registry + + + +TransportRouter + +TransportRouter + +routes: RwLock<HashMap<ActorAddress, Arc<dyn Transport>>> + + + +TickContext->TransportRouter + + +transport_router + + + +TickTiming + +TickTiming + +phase_us: [u64; ..] +messages_processed: usize +did_work: bool + + + +WorkerStats->TickTiming + + +tick_timings + + + +WorkerInfo + +WorkerInfo + +id: usize +num_actors: usize +mailbox_depth: usize +messages_processed: u64 +local_sends: u64 +cross_sends: u64 +inbox_sends: u64 +type_mismatches: u64 +panics: u64 + + + +WorkerStats->WorkerInfo + + +snapshot() param + + + +ActorInfo + +ActorInfo + +address: ActorAddress +worker_id: usize +mailbox_depth: usize + + + +ActorInfo->ActorAddress + + +address + + + +RuntimeStats + +RuntimeStats + +num_workers: usize +actors: Vec<(ActorAddress, usize)> +workers: Vec<WorkerInfo> +actor_details: Vec<ActorInfo> +tick_timings: Vec<Vec<TickTiming>> + + + +RuntimeStats->ActorAddress + + +actors + + + +RuntimeStats->TickTiming + + +tick_timings + + + +RuntimeStats->WorkerInfo + + +workers + + + +RuntimeStats->ActorInfo + + +actor_details + + + +Inbox + +Inbox + +addr: ActorAddress +inner: Receiver<M> + + + +Inbox->ActorAddress + + +addr + + + +Inbox->Receiver + + +inner + + + +RuntimeHandle + +RuntimeHandle + +runtime: Arc<Runtime> +threads: Vec<JoinHandle<()>> + + + +Runtime + +Runtime + +config: RuntimeConfig +address_map: Arc<AddressMap> +inbox_registry: Arc<InboxRegistry> +transfer_txs: Vec<Sender<Envelope>> +spawn_txs: Vec<Sender<(ActorAddress, Box<dyn AnyActor>)>> +placement: Placement +is_running: AtomicBool +worker_stats: Vec<Arc<WorkerStats>> +mailbox_snapshots: Vec<Arc<std::sync::Mutex<Vec<(ActorAddress, usize)>>>> +tick_workers: RefCell<Vec<Worker>> +codec_registry: Option<Arc<crate::transport::CodecRegistry>> +transport_router: Option<Arc<crate::transport::TransportRouter>> + + + +RuntimeHandle->Runtime + + +runtime + + + +Runtime->ActorAddress + + +spawn_txs + + + +Runtime->AnyActor + + +spawn_txs + + + +Runtime->ContextInner + + +impl + + + +Runtime->Worker + + +tick_workers + + + +Runtime->Sender + + +transfer_txs + + + +Runtime->Error + + +spawn() param + + + +Runtime->RuntimeConfig + + +config + + + +Runtime->AddressMap + + +address_map + + + +Runtime->Placement + + +placement + + + +Runtime->Envelope + + +transfer_txs + + + +Runtime->InboxRegistry + + +inbox_registry + + + +Runtime->TickContext + + +make_tick_context() param + + + +Runtime->WorkerStats + + +worker_stats + + + +Runtime->RuntimeStats + + +stats() param + + + +Runtime->Inbox + + +new_inbox() param + + + +Runtime->RuntimeHandle + + +run() param + + + +Runtime->CodecRegistry + + +codec_registry + + + +Runtime->TransportRouter + + +transport_router + + + +Codec + +«trait» Codec + +encode((&self, &M) → Result<Vec<u8>, Error>) +decode((&self, &[u8]) → Result<M, Error>) + + + +Codec->Error + + +encode + + + +NetworkMessage + +«trait» NetworkMessage + +type_tag(() → &'static str) + + + +WireEnvelope + +WireEnvelope + +dest: ActorAddress +type_tag: String +payload: Vec<u8> + + + +WireEnvelope->ActorAddress + + +dest + + + +Transport + +«trait» Transport + +send((&self, WireEnvelope) → Result<(), Error>) + + + +Transport->Error + + +send + + + +Transport->WireEnvelope + + +send + + + +CodecRegistry->ActorAddress + + +receive() param + + + +CodecRegistry->Error + + +encode() param + + + +CodecRegistry->WireEnvelope + + +receive() param + + + +TransportRouter->ActorAddress + + +routes + + + +TransportRouter->Transport + + +routes + + + +InMemoryTransport + +InMemoryTransport + +tx: std::sync::Mutex<std::sync::mpsc::Sender<WireEnvelope>> + + + +InMemoryTransport->Receiver + + +pair() param + + + +InMemoryTransport->Sender + + +tx + + + +InMemoryTransport->Error + + +send() param + + + +InMemoryTransport->WireEnvelope + + +tx + + + +InMemoryTransport->Transport + + +impl + + + diff --git a/docs/connectome/connectome_dashboard.html b/docs/connectome/connectome_dashboard.html index 342b312..b8b68ab 100644 --- a/docs/connectome/connectome_dashboard.html +++ b/docs/connectome/connectome_dashboard.html @@ -76,11 +76,7 @@ svg text { user-select:none; } .hm-cell { cursor:pointer; transition:opacity 0.15s; } .hm-cell:hover { opacity:0.8; stroke:#4fc3f7; stroke-width:2; } -/* Eigenvalue bars */ -.ev-bar { cursor:pointer; transition:opacity 0.15s; } -.ev-bar:hover { opacity:0.8; } - -/* Fiedler bars */ +/* Cohesion / heatmap bars */ .fi-bar { cursor:pointer; transition:opacity 0.15s; } .fi-bar:hover { opacity:0.85; } @@ -89,11 +85,11 @@ svg text { user-select:none; }
swactor — dependency analysis
- - + +
-
+
@@ -104,16 +100,16 @@ svg text { user-select:none; }
Loading Graphviz…
-
+
-
-

λ Laplacian Eigenvalue Spectrum

- +
+

◉ Structural Properties

+
-
-

✂ Fiedler Vector — Spectral Bisection

- +
+

▨ Module Cohesion

+
@@ -133,8 +129,8 @@ svg text { user-select:none; }