cervo_runtime/lib.rs
1// Author: Tom Solberg <tom.solberg@embark-studios.com>
2// Copyright © 2022, Embark Studios, all rights reserved.
3// Created: 28 July 2022
4
5/*!
6The Cervo runtime is a combined front for multiple inference models,
7managing data routing and offering higher-level constructs for
8execution.
9
10The goal of the runtime is to simplify batched execution, especially
11in the face of time-slotted execution.
12
13```no_run
14use cervo_asset::{AssetData, AssetKind};
15use cervo_runtime::{BrainId, Runtime, AgentId};
16use std::time::Duration;
17# fn load_bytes(s: &str) -> Vec<u8> { vec![] }
18# fn load_model(name: &str) -> AssetData { AssetData::new(AssetKind::Onnx, load_bytes(name)) }
19# mod game {
20# use std::collections::HashMap;
21# use cervo_runtime::{BrainId, Runtime, AgentId};
22# pub fn observe_trucks(key: BrainId, r: &mut Runtime) {}
23# pub fn observe_racecars(key: BrainId, r: &mut Runtime) {}
24# pub fn assign_actions(response: HashMap<BrainId, HashMap<AgentId, cervo_core::prelude::Response<'_>>>) {}
25# }
26
27let mut runtime = Runtime::new();
28
29let racer_asset = load_model("racing-car");
30let racer_inferer = racer_asset.load_basic()?;
31let racer_infer_key = runtime.add_inferer(racer_inferer);
32
33let truck_asset = load_model("monster-truck");
34let truck_inferer = truck_asset.load_basic()?;
35let truck_infer_key = runtime.add_inferer(truck_inferer);
36
37game::observe_racecars(racer_infer_key, &mut runtime);
38game::observe_trucks(truck_infer_key, &mut runtime);
39
40let responses = runtime.run_for(Duration::from_millis(1))?;
41game::assign_actions(responses);
42
43# Ok::<(), Box<dyn std::error::Error>>(())
44```
45
46## Notes on time-slotted execution
47
48There is a very experimental feature for using time-slotted execution
49based on collected performance metrics. Each time a model is executed
50the runtime records the batch size and time-cost. This is then used to
51estimate the cost of future batches.
52
53The implementation currently requires that whichever model is first in
54the queue for execution gets to run. This is to ensure that models
55don't end up in back-off. This means that
56`Runtime::run_for(Duration::from_millis(0))` will still execute one
57model.
58
59Once the first model has executed, models will be processed in order,
60starting by the one that has waited longest for running. Models that
61would take too long to run will be skipped and end up at the back of
62the queue. This ensures that the first skipped model is at the start
63of the queue next round.
64
65The estimation algorithm uses Welford's Online Algorithm which can
66integrate mean and variance without requiring extra storage. However,
67this update method can be quite unstable with few samples. This can
68lead to some stuttering early on by underestimating cost, or running
69too few models by overestimation.
70
71 */
72
73#![warn(rust_2018_idioms)]
74
75mod error;
76mod runtime;
77mod state;
78mod timing;
79
80#[doc(inline)]
81pub use crate::error::CervoError;
82#[doc(inline)]
83pub use runtime::Runtime;
84
85/// Identifier for a specific brain.
86#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Ord)]
87#[must_use = "the BrainId is required when you submit data to the runtime"]
88pub struct BrainId(pub u16);
89
90/// Identifier for a specific agent.
91pub type AgentId = u64;