Skip to main content

moirai_executor/schedule/route/
summary.rs

1//! Route sequence summaries.
2
3use super::{AcceleratorKind, AsyncLaneId, SchedulerRoute};
4
5/// Value summary of a route sequence.
6#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
7pub struct RouteSummary {
8    /// Number of local thread routes.
9    pub thread_routes: usize,
10    /// Number of process routes.
11    pub process_routes: usize,
12    /// Number of server routes.
13    pub server_routes: usize,
14    /// Number of accelerator metadata routes.
15    pub accelerator_routes: usize,
16    /// Number of CPU accelerator metadata routes.
17    pub cpu_routes: usize,
18    /// Number of GPU accelerator metadata routes.
19    pub gpu_routes: usize,
20    /// Number of TPU accelerator metadata routes.
21    pub tpu_routes: usize,
22    /// Number of NPU accelerator metadata routes.
23    pub npu_routes: usize,
24    /// Number of routes with an async lane.
25    pub async_lane_routes: usize,
26    /// Deterministic checksum over route placements.
27    pub checksum: usize,
28}
29
30impl RouteSummary {
31    /// Return the total number of summarized route decisions.
32    #[inline]
33    pub const fn total_routes(self) -> usize {
34        self.thread_routes + self.process_routes + self.server_routes + self.accelerator_routes
35    }
36
37    #[inline]
38    pub(crate) fn record(&mut self, route: SchedulerRoute) {
39        match route {
40            SchedulerRoute::Thread(route) => {
41                self.thread_routes += 1;
42                self.checksum = mix_route_checksum(
43                    self.checksum,
44                    1,
45                    0,
46                    route.process.get(),
47                    route.thread.get(),
48                    None,
49                );
50            }
51            SchedulerRoute::Process(route) => {
52                self.process_routes += 1;
53                if route.async_lane.is_some() {
54                    self.async_lane_routes += 1;
55                }
56                self.checksum = mix_route_checksum(
57                    self.checksum,
58                    2,
59                    0,
60                    route.process.get(),
61                    route.thread.get(),
62                    route.async_lane,
63                );
64            }
65            SchedulerRoute::Server(route) => {
66                self.server_routes += 1;
67                if route.async_lane.is_some() {
68                    self.async_lane_routes += 1;
69                }
70                self.checksum = mix_route_checksum(
71                    self.checksum,
72                    3,
73                    route.server.get(),
74                    route.process.get(),
75                    route.thread.get(),
76                    route.async_lane,
77                );
78            }
79            SchedulerRoute::Accelerator(route) => {
80                self.accelerator_routes += 1;
81                if route.async_lane.is_some() {
82                    self.async_lane_routes += 1;
83                }
84                match route.kind {
85                    AcceleratorKind::Cpu => self.cpu_routes += 1,
86                    AcceleratorKind::Gpu => self.gpu_routes += 1,
87                    AcceleratorKind::Tpu => self.tpu_routes += 1,
88                    AcceleratorKind::Npu => self.npu_routes += 1,
89                }
90                self.checksum = mix_route_checksum(
91                    self.checksum,
92                    4,
93                    route
94                        .kind
95                        .checksum_tag()
96                        .wrapping_mul(1_009)
97                        .wrapping_add(route.accelerator.get()),
98                    route.process.get(),
99                    route.thread.get(),
100                    route.async_lane,
101                );
102            }
103        }
104    }
105}
106
107#[inline]
108fn mix_route_checksum(
109    current: usize,
110    route_kind: usize,
111    server: usize,
112    process: usize,
113    thread: usize,
114    async_lane: Option<AsyncLaneId>,
115) -> usize {
116    current
117        .wrapping_mul(1_000_003)
118        .wrapping_add(route_kind.wrapping_mul(97))
119        .wrapping_add(server.wrapping_mul(31))
120        .wrapping_add(process.wrapping_mul(17))
121        .wrapping_add(thread.wrapping_mul(13))
122        .wrapping_add(async_lane.map_or(0, |lane| lane.get().wrapping_add(1)))
123}