sim_ring/
ring_builder.rs

1// Copyright (c) 2025 Graphcore Ltd. All rights reserved.
2
3//! Library functions to build parts of the sim-ring application.
4
5use std::rc::Rc;
6
7use gwr_components::arbiter::policy::WeightedRoundRobin;
8use gwr_components::flow_controls::limiter::Limiter;
9use gwr_components::rc_limiter;
10use gwr_components::router::Route;
11use gwr_components::sink::Sink;
12use gwr_components::source::Source;
13use gwr_engine::engine::Engine;
14use gwr_engine::traits::Routable;
15use gwr_engine::types::SimError;
16use gwr_models::ethernet_frame::{EthernetFrame, u64_to_mac};
17use gwr_models::fc_pipeline::{FcPipeline, FcPipelineConfig};
18use gwr_models::ring_node::{IO_INDEX, RING_INDEX, RingConfig, RingNode};
19
20use crate::frame_gen::FrameGen;
21
22// Define some types to aid readability
23pub type Limiters = Vec<Rc<Limiter<EthernetFrame>>>;
24pub type Nodes = Vec<Rc<RingNode<EthernetFrame>>>;
25pub type Pipes = Vec<Rc<FcPipeline<EthernetFrame>>>;
26pub type Sources = Vec<Rc<Source<EthernetFrame>>>;
27pub type Sinks = Vec<Rc<Sink<EthernetFrame>>>;
28
29pub struct Config {
30    pub ring_size: usize,
31    pub ring_priority: usize,
32    pub rx_buffer_frames: usize,
33    pub tx_buffer_frames: usize,
34    pub frame_payload_bytes: usize,
35    pub num_send_frames: usize,
36}
37
38struct RoutingAlgorithm(usize);
39
40impl<T> Route<T> for RoutingAlgorithm
41where
42    T: Routable,
43{
44    fn route(&self, obj: &T) -> Result<usize, SimError> {
45        // If the dest matches then exit via port 1, otherwise use port 0 as that is the
46        // ring
47        let dest = obj.destination() as usize;
48        Ok(if self.0 == dest { IO_INDEX } else { RING_INDEX })
49    }
50}
51
52pub fn build_ring_nodes(engine: &mut Engine, config: &Config) -> Nodes {
53    let spawner = engine.spawner().clone();
54    let clock = engine.default_clock().clone();
55    let limiter_128_gbps = rc_limiter!(clock.clone(), 128);
56    let ring_config = RingConfig::new(
57        config.rx_buffer_frames,
58        config.tx_buffer_frames,
59        limiter_128_gbps.clone(),
60    );
61    let top = engine.top();
62    let ring_nodes: Nodes = (0..config.ring_size)
63        .map(|i| {
64            let weights = vec![config.ring_priority, 1];
65            RingNode::new_and_register(
66                engine,
67                top,
68                format!("node{i}").as_str(),
69                spawner.clone(),
70                &ring_config,
71                Box::new(RoutingAlgorithm(i)),
72                Box::new(WeightedRoundRobin::new(weights, 2).unwrap()),
73            )
74            .unwrap()
75        })
76        .collect();
77    ring_nodes
78}
79
80pub fn build_source_sinks(engine: &mut Engine, config: &Config) -> (Sources, Sinks) {
81    let mut sources = Vec::with_capacity(config.ring_size);
82    let top = engine.top();
83
84    for i in 0..config.ring_size {
85        let neighbour_left = if i > 0 { i - 1 } else { config.ring_size - 1 };
86
87        sources.push(
88            Source::new_and_register(
89                engine,
90                top,
91                format!("source{i}").as_str(),
92                Some(Box::new(FrameGen::new(
93                    top,
94                    u64_to_mac(neighbour_left as u64),
95                    config.frame_payload_bytes,
96                    config.num_send_frames,
97                ))),
98            )
99            .unwrap(),
100        );
101    }
102
103    let sinks: Sinks = (0..config.ring_size)
104        .map(|i| Sink::new_and_register(engine, top, format!("sink{i}").as_str()).unwrap())
105        .collect();
106
107    (sources, sinks)
108}
109
110pub fn build_pipes(engine: &mut Engine, config: &Config) -> (Pipes, Pipes) {
111    let mut ingress_pipes = Vec::with_capacity(config.ring_size);
112    let mut ring_pipes = Vec::with_capacity(config.ring_size);
113
114    let clock = engine.default_clock();
115    let top = engine.top();
116    let spawner = engine.spawner();
117
118    let pipe_config = FcPipelineConfig::new(500, 500, 500);
119    for i in 0..config.ring_size {
120        ingress_pipes.push(
121            FcPipeline::new_and_register(
122                engine,
123                top,
124                format!("ingress_pipe{i}").as_str(),
125                clock.clone(),
126                spawner.clone(),
127                &pipe_config,
128            )
129            .unwrap(),
130        );
131        ring_pipes.push(
132            FcPipeline::new_and_register(
133                engine,
134                top,
135                format!("ring_pipe{i}").as_str(),
136                clock.clone(),
137                spawner.clone(),
138                &pipe_config,
139            )
140            .unwrap(),
141        );
142    }
143    (ingress_pipes, ring_pipes)
144}
145
146pub fn build_limiters(
147    engine: &mut Engine,
148    config: &Config,
149    gbps: usize,
150) -> (Limiters, Limiters, Limiters) {
151    let clock = engine.default_clock();
152    let limiter_gbps = rc_limiter!(clock, gbps);
153    let top = engine.top();
154    let source_limiters: Limiters = (0..config.ring_size)
155        .map(|i| {
156            Limiter::new_and_register(
157                engine,
158                top,
159                format!("src_limit{i}").as_str(),
160                limiter_gbps.clone(),
161            )
162            .unwrap()
163        })
164        .collect();
165
166    let ring_limiters: Limiters = (0..config.ring_size)
167        .map(|i| {
168            Limiter::new_and_register(
169                engine,
170                top,
171                format!("ring_limit{i}").as_str(),
172                limiter_gbps.clone(),
173            )
174            .unwrap()
175        })
176        .collect();
177
178    let sink_limiters: Limiters = (0..config.ring_size)
179        .map(|i| {
180            Limiter::new_and_register(
181                engine,
182                top,
183                format!("sink_limit{i}").as_str(),
184                limiter_gbps.clone(),
185            )
186            .unwrap()
187        })
188        .collect();
189    (source_limiters, ring_limiters, sink_limiters)
190}