1#![feature(associated_type_defaults)]
12#![feature(impl_trait_in_bindings)]
13#![feature(get_disjoint_mut_helpers)]
14#![feature(exact_size_is_empty)]
15#![feature(async_fn_track_caller)]
16#![allow(unused_assignments)]
21#![allow(clippy::result_large_err)]
24
25pub mod actor_mesh;
26mod assign;
27pub mod bootstrap;
28pub mod casting;
29pub mod client_root;
30pub mod config;
31pub mod config_dump;
32pub mod connect;
33pub mod global_context;
34pub mod host;
35pub mod host_mesh;
36pub mod introspect;
37pub mod logging;
38pub mod mesh;
39pub mod mesh_admin;
40pub mod mesh_admin_client;
41pub mod mesh_controller;
42pub mod mesh_id;
43pub mod mesh_selection;
44mod metrics;
45pub mod monitor;
46pub mod proc_agent;
47pub mod proc_launcher;
48pub mod proc_mesh;
49pub mod pyspy;
50pub mod reference;
51pub mod resource;
52pub mod shared_cell;
53pub mod shortuuid;
54pub mod supervision;
55#[cfg(target_os = "linux")]
56mod systemd;
57pub mod test_utils;
58pub mod testactor;
59pub mod testing;
60mod testresource;
61pub mod transport;
62pub mod value_mesh {
63 pub use hyperactor::value_mesh::*;
64}
65
66use std::io;
67
68pub use actor_mesh::ActorMesh;
69pub use actor_mesh::ActorMeshRef;
70pub use actor_mesh::DataActorMesh;
71pub use bootstrap::Bootstrap;
72pub use bootstrap::HostBootstrapReady;
73pub use bootstrap::bootstrap;
74pub use bootstrap::bootstrap_or_die;
75pub use casting::CastError;
76pub use dashmap;
77use enum_as_inner::EnumAsInner;
78pub use global_context::GlobalClientActor;
79pub use global_context::GlobalContext;
80pub use global_context::context;
81pub use global_context::this_host;
82pub use global_context::this_proc;
83pub use host_mesh::HostMeshRef;
84use hyperactor::ActorAddr;
85use hyperactor::ActorRef;
86use hyperactor::ProcAddr;
87use hyperactor::mailbox::MailboxSenderError;
88pub use hyperactor_mesh_macros::sel;
89pub use mesh::Mesh;
90pub use monitor::MeshMonitor;
91pub use ndslice::extent;
93use ndslice::view;
94pub use proc_mesh::ProcMesh;
95pub use proc_mesh::ProcMeshRef;
96pub use value_mesh::ValueMesh;
97
98use crate::host::HostError;
99use crate::host_mesh::HostAgent;
100use crate::host_mesh::HostMeshRefParseError;
101use crate::host_mesh::host_agent::ProcState;
102use crate::resource::RankedValues;
103use crate::resource::Status;
104
105pub type StatusMesh = ValueMesh<Status>;
113
114pub type StatusOverlay = value_mesh::ValueOverlay<Status>;
123
124inventory::submit! {
125 hyperactor::accum::ReducerFactory {
126 typehash_f: <hyperactor::value_mesh::ValueOverlayReducer<crate::resource::Status> as typeuri::Named>::typehash,
127 builder_f: |_| Ok(Box::new(hyperactor::value_mesh::ValueOverlayReducer::<crate::resource::Status>::new())),
128 }
129}
130
131inventory::submit! {
134 hyperactor::accum::ReducerFactory {
135 typehash_f: <hyperactor::value_mesh::ValueOverlayReducer<crate::resource::State<crate::host_mesh::host_agent::ProcState>> as typeuri::Named>::typehash,
136 builder_f: |_| Ok(Box::new(hyperactor::value_mesh::ValueOverlayReducer::<crate::resource::State<crate::host_mesh::host_agent::ProcState>>::new())),
137 }
138}
139
140#[derive(Debug, EnumAsInner, thiserror::Error)]
142pub enum Error {
143 #[error("invalid mesh ref: expected {expected} ranks, but contains {actual} ranks")]
144 InvalidRankCardinality { expected: usize, actual: usize },
145
146 #[error(transparent)]
147 ResourceIdParseError(#[from] mesh_id::ResourceIdParseError),
148
149 #[error(transparent)]
150 HostMeshRefParseError(#[from] HostMeshRefParseError),
151
152 #[error(transparent)]
153 ChannelError(#[from] Box<hyperactor::channel::ChannelError>),
154
155 #[error(transparent)]
156 MailboxError(#[from] Box<hyperactor::mailbox::MailboxError>),
157
158 #[error(transparent)]
159 CodecError(#[from] CodecError),
160
161 #[error("error during mesh configuration: {0}")]
162 ConfigurationError(anyhow::Error),
163
164 #[error("configuration error: mesh is unroutable")]
167 UnroutableMesh(),
168
169 #[error("error while calling actor {0}: {1}")]
170 CallError(ActorAddr, anyhow::Error),
171
172 #[error("actor not registered for type {0}")]
173 ActorTypeNotRegistered(String),
174
175 #[error(transparent)]
176 ClientRootError(#[from] crate::client_root::ClientRootError),
177
178 #[error("client-root capability is absent from this actor's environment")]
179 MissingClientRoot,
180
181 #[error("error while spawning actor {0}: {1}")]
183 GspawnError(mesh_id::ActorMeshId, String),
184
185 #[error("error while sending message to actor {0}: {1}")]
186 SendingError(ActorAddr, Box<MailboxSenderError>),
187
188 #[error("error while casting message to {0}: {1}")]
189 CastingError(mesh_id::ActorMeshId, anyhow::Error),
190
191 #[error("error configuring host mesh agent {0}: {1}")]
192 HostMeshAgentConfigurationError(ActorAddr, String),
193
194 #[error(transparent)]
198 ConfigPushFailed(#[from] crate::host_mesh::ConfigPushError),
199
200 #[error(
201 "error creating proc (host rank {host_rank}) on host mesh agent {mesh_agent}, state: {state}"
202 )]
203 ProcCreationError {
204 state: Box<resource::State<ProcState>>,
205 host_rank: usize,
206 mesh_agent: ActorRef<HostAgent>,
207 },
208
209 #[error(
210 "error spawning proc mesh: statuses: {}",
211 RankedValues::invert(statuses)
212 )]
213 ProcSpawnError { statuses: RankedValues<Status> },
214
215 #[error(
216 "error spawning actor mesh: statuses: {}",
217 RankedValues::invert(statuses)
218 )]
219 ActorSpawnError { statuses: RankedValues<Status> },
220
221 #[error(
222 "error stopping actor mesh: statuses: {}",
223 RankedValues::invert(statuses)
224 )]
225 ActorStopError { statuses: RankedValues<Status> },
226
227 #[error(
228 "error stopping proc mesh: statuses: {}",
229 RankedValues::invert(statuses)
230 )]
231 ProcMeshStopError { statuses: RankedValues<Status> },
232
233 #[error("error spawning actor: {0}")]
234 SingletonActorSpawnError(anyhow::Error),
235
236 #[error("error spawning controller actor for mesh {0}: {1}")]
237 ControllerActorSpawnError(mesh_id::ResourceId, anyhow::Error),
238
239 #[error("proc {0} must be direct-addressable")]
240 RankedProc(ProcAddr),
241
242 #[error("error: {0} does not exist")]
243 NotExist(mesh_id::ResourceId),
244
245 #[error(transparent)]
246 Io(#[from] io::Error),
247
248 #[error(transparent)]
249 Host(#[from] HostError),
250
251 #[error(transparent)]
252 Other(#[from] anyhow::Error),
253}
254
255#[derive(Debug, thiserror::Error)]
257pub enum CodecError {
258 #[error(transparent)]
259 BincodeEncodeError(#[from] Box<bincode::error::EncodeError>),
260 #[error(transparent)]
261 BincodeDecodeError(#[from] Box<bincode::error::DecodeError>),
262 #[error(transparent)]
263 JsonError(#[from] Box<serde_json::Error>),
264 #[error(transparent)]
265 Base64Error(#[from] Box<base64::DecodeError>),
266 #[error(transparent)]
267 Utf8Error(#[from] Box<std::str::Utf8Error>),
268}
269
270impl From<bincode::error::EncodeError> for Error {
271 fn from(e: bincode::error::EncodeError) -> Self {
272 Error::CodecError(Box::new(e).into())
273 }
274}
275
276impl From<bincode::error::DecodeError> for Error {
277 fn from(e: bincode::error::DecodeError) -> Self {
278 Error::CodecError(Box::new(e).into())
279 }
280}
281
282impl From<serde_json::Error> for Error {
283 fn from(e: serde_json::Error) -> Self {
284 Error::CodecError(Box::new(e).into())
285 }
286}
287
288impl From<base64::DecodeError> for Error {
289 fn from(e: base64::DecodeError) -> Self {
290 Error::CodecError(Box::new(e).into())
291 }
292}
293
294impl From<std::str::Utf8Error> for Error {
295 fn from(e: std::str::Utf8Error) -> Self {
296 Error::CodecError(Box::new(e).into())
297 }
298}
299
300impl From<hyperactor::channel::ChannelError> for Error {
301 fn from(e: hyperactor::channel::ChannelError) -> Self {
302 Error::ChannelError(Box::new(e))
303 }
304}
305
306impl From<hyperactor::mailbox::MailboxError> for Error {
307 fn from(e: hyperactor::mailbox::MailboxError) -> Self {
308 Error::MailboxError(Box::new(e))
309 }
310}
311
312impl From<view::InvalidCardinality> for Error {
313 fn from(e: view::InvalidCardinality) -> Self {
314 Error::InvalidRankCardinality {
315 expected: e.expected,
316 actual: e.actual,
317 }
318 }
319}
320
321impl From<hyperactor::value_mesh::ValueMeshError> for Error {
322 fn from(e: hyperactor::value_mesh::ValueMeshError) -> Self {
323 match e {
324 hyperactor::value_mesh::ValueMeshError::InvalidRankCardinality { expected, actual } => {
325 Error::InvalidRankCardinality { expected, actual }
326 }
327 }
328 }
329}
330
331pub type Result<T> = std::result::Result<T, Error>;
333
334pub(crate) fn actor_display_name(base: &str, point: &view::Point) -> String {
339 if point.is_empty() {
340 return base.to_string();
341 }
342 let coords = point.format_as_dict();
343 if let Some(pos) = base.rfind('>') {
344 format!("{}{}{}", &base[..pos], coords, &base[pos..])
345 } else {
346 format!("{}{}", base, coords)
347 }
348}
349
350#[cfg(test)]
351mod tests {
352
353 #[test]
354 fn basic() {
355 use ndslice::selection::dsl;
356 use ndslice::selection::structurally_equal;
357
358 let actual = sel!(*, 0:4, *);
359 let expected = dsl::all(dsl::range(
360 ndslice::shape::Range(0, Some(4), 1),
361 dsl::all(dsl::true_()),
362 ));
363 assert!(structurally_equal(&actual, &expected));
364 }
365
366 #[cfg(false)]
367 #[test]
368 fn shouldnt_compile() {
369 let _ = sel!(foobar);
370 }
371 use hyperactor_mesh_macros::sel;
381 use ndslice::assert_round_trip;
382 use ndslice::assert_structurally_eq;
383 use ndslice::selection::Selection;
384
385 macro_rules! assert_round_trip_match {
386 ($left:expr, $right:expr) => {{
387 assert_structurally_eq!($left, $right);
388 assert_round_trip!($left);
389 assert_round_trip!($right);
390 }};
391 }
392
393 #[test]
394 fn token_parser() {
395 use ndslice::selection::dsl::*;
396 use ndslice::shape;
397
398 assert_round_trip_match!(all(true_()), sel!(*));
399 assert_round_trip_match!(range(3, true_()), sel!(3));
400 assert_round_trip_match!(range(1..4, true_()), sel!(1:4));
401 assert_round_trip_match!(all(range(1..4, true_())), sel!(*, 1:4));
402 assert_round_trip_match!(range(shape::Range(0, None, 1), true_()), sel!(:));
403 assert_round_trip_match!(any(true_()), sel!(?));
404 assert_round_trip_match!(any(range(1..4, all(true_()))), sel!(?, 1:4, *));
405 assert_round_trip_match!(union(range(0, true_()), range(1, true_())), sel!(0 | 1));
406 assert_round_trip_match!(
407 intersection(range(0..4, true_()), range(2..6, true_())),
408 sel!(0:4 & 2:6)
409 );
410 assert_round_trip_match!(range(shape::Range(0, None, 1), true_()), sel!(:));
411 assert_round_trip_match!(all(true_()), sel!(*));
412 assert_round_trip_match!(any(true_()), sel!(?));
413 assert_round_trip_match!(all(all(all(true_()))), sel!(*, *, *));
414 assert_round_trip_match!(intersection(all(true_()), all(true_())), sel!(* & *));
415 assert_round_trip_match!(
416 all(all(union(
417 range(0..2, true_()),
418 range(shape::Range(6, None, 1), true_())
419 ))),
420 sel!(*, *, (:2|6:))
421 );
422 assert_round_trip_match!(
423 all(all(range(shape::Range(1, None, 2), true_()))),
424 sel!(*, *, 1::2)
425 );
426 assert_round_trip_match!(
427 range(
428 shape::Range(0, Some(1), 1),
429 any(range(shape::Range(0, Some(4), 1), true_()))
430 ),
431 sel!(0, ?, :4)
432 );
433 assert_round_trip_match!(range(shape::Range(1, Some(4), 2), true_()), sel!(1:4:2));
434 assert_round_trip_match!(range(shape::Range(0, None, 2), true_()), sel!(::2));
435 assert_round_trip_match!(
436 union(range(0..4, true_()), range(4..8, true_())),
437 sel!(0:4 | 4:8)
438 );
439 assert_round_trip_match!(
440 intersection(range(0..4, true_()), range(2..6, true_())),
441 sel!(0:4 & 2:6)
442 );
443 assert_round_trip_match!(
444 all(union(range(1..4, all(true_())), range(5..6, all(true_())))),
445 sel!(*, (1:4 | 5:6), *)
446 );
447 assert_round_trip_match!(
448 range(
449 0,
450 intersection(
451 range(1..4, range(7, true_())),
452 range(2..5, range(7, true_()))
453 )
454 ),
455 sel!(0, (1:4 & 2:5), 7)
456 );
457 assert_round_trip_match!(
458 all(all(union(
459 union(range(0..2, true_()), range(4..6, true_())),
460 range(shape::Range(6, None, 1), true_())
461 ))),
462 sel!(*, *, (:2 | 4:6 | 6:))
463 );
464 assert_round_trip_match!(intersection(all(true_()), all(true_())), sel!(* & *));
465 assert_round_trip_match!(union(all(true_()), all(true_())), sel!(* | *));
466 assert_round_trip_match!(
467 intersection(
468 range(0..2, true_()),
469 union(range(1, true_()), range(2, true_()))
470 ),
471 sel!(0:2 & (1 | 2))
472 );
473 assert_round_trip_match!(
474 all(all(intersection(
475 range(1..2, true_()),
476 range(2..3, true_())
477 ))),
478 sel!(*,*,(1:2&2:3))
479 );
480 assert_round_trip_match!(
481 intersection(all(all(all(true_()))), all(all(all(true_())))),
482 sel!((*,*,*) & (*,*,*))
483 );
484 assert_round_trip_match!(
485 intersection(
486 range(0, all(all(true_()))),
487 range(0, union(range(1, all(true_())), range(3, all(true_()))))
488 ),
489 sel!((0, *, *) & (0, (1 | 3), *))
490 );
491 assert_round_trip_match!(
492 intersection(
493 range(0, all(all(true_()))),
494 range(
495 0,
496 union(
497 range(1, range(2..5, true_())),
498 range(3, range(2..5, true_()))
499 )
500 )
501 ),
502 sel!((0, *, *) & (0, (1 | 3), 2:5))
503 );
504 assert_round_trip_match!(all(true_()), sel!((*)));
505 assert_round_trip_match!(range(1..4, range(2, true_())), sel!(((1:4), 2)));
506 assert_round_trip_match!(sel!(1:4 & 5:6 | 7:8), sel!((1:4 & 5:6) | 7:8));
507 assert_round_trip_match!(
508 union(
509 intersection(all(all(true_())), all(all(true_()))),
510 all(all(true_()))
511 ),
512 sel!((*,*) & (*,*) | (*,*))
513 );
514 assert_round_trip_match!(all(true_()), sel!(*));
515 assert_round_trip_match!(sel!(((1:4))), sel!(1:4));
516 assert_round_trip_match!(sel!(*, (*)), sel!(*, *));
517 assert_round_trip_match!(
518 intersection(
519 range(0, range(1..4, true_())),
520 range(0, union(range(2, all(true_())), range(3, all(true_()))))
521 ),
522 sel!((0,1:4)&(0,(2|3),*))
523 );
524
525 assert_round_trip_match!(
528 sel!(0 & (0, (1|3), *)),
529 intersection(
530 range(0, true_()),
531 range(0, union(range(1, all(true_())), range(3, all(true_()))))
532 )
533 );
534 assert_round_trip_match!(
535 sel!(0 & (0, (3|1), *)),
536 intersection(
537 range(0, true_()),
538 range(0, union(range(3, all(true_())), range(1, all(true_()))))
539 )
540 );
541 assert_round_trip_match!(
542 sel!((*, *, *) & (*, *, (2 | 4))),
543 intersection(
544 all(all(all(true_()))),
545 all(all(union(range(2, true_()), range(4, true_()))))
546 )
547 );
548 assert_round_trip_match!(
549 sel!((*, *, *) & (*, *, (4 | 2))),
550 intersection(
551 all(all(all(true_()))),
552 all(all(union(range(4, true_()), range(2, true_()))))
553 )
554 );
555 assert_round_trip_match!(
556 sel!((*, (1|2)) & (*, (2|1))),
557 intersection(
558 all(union(range(1, true_()), range(2, true_()))),
559 all(union(range(2, true_()), range(1, true_())))
560 )
561 );
562 assert_round_trip_match!(
563 sel!((*, *, *) & *),
564 intersection(all(all(all(true_()))), all(true_()))
565 );
566 assert_round_trip_match!(
567 sel!(* & (*, *, *)),
568 intersection(all(true_()), all(all(all(true_()))))
569 );
570
571 assert_round_trip_match!(
572 sel!( (*, *, *) & ((*, *, *) & (*, *, *)) ),
573 intersection(
574 all(all(all(true_()))),
575 intersection(all(all(all(true_()))), all(all(all(true_()))))
576 )
577 );
578 assert_round_trip_match!(
579 sel!((1, *, *) | (0 & (0, 3, *))),
580 union(
581 range(1, all(all(true_()))),
582 intersection(range(0, true_()), range(0, range(3, all(true_()))))
583 )
584 );
585 assert_round_trip_match!(
586 sel!(((0, *)| (1, *)) & ((1, *) | (0, *))),
587 intersection(
588 union(range(0, all(true_())), range(1, all(true_()))),
589 union(range(1, all(true_())), range(0, all(true_())))
590 )
591 );
592 assert_round_trip_match!(sel!(*, 8:8), all(range(8..8, true_())));
593 assert_round_trip_match!(
594 sel!((*, 1) & (*, 8 : 8)),
595 intersection(all(range(1..2, true_())), all(range(8..8, true_())))
596 );
597 assert_round_trip_match!(
598 sel!((*, 8 : 8) | (*, 1)),
599 union(all(range(8..8, true_())), all(range(1..2, true_())))
600 );
601 assert_round_trip_match!(
602 sel!((*, 1) | (*, 2:8)),
603 union(all(range(1..2, true_())), all(range(2..8, true_())))
604 );
605 assert_round_trip_match!(
606 sel!((*, *, *) & (*, *, 2:8)),
607 intersection(all(all(all(true_()))), all(all(range(2..8, true_()))))
608 );
609 }
610}