99/// A naive implementation of the Dining Philosophers problem using Hyperactor.
1010/// https://en.wikipedia.org/wiki/Dining_philosophers_problem
1111use std:: collections:: HashMap ;
12+ use std:: ops:: Deref ;
1213use std:: process:: ExitCode ;
1314
1415use anyhow:: Result ;
@@ -20,19 +21,14 @@ use hyperactor::Handler;
2021use hyperactor:: Instance ;
2122use hyperactor:: Named ;
2223use hyperactor:: PortRef ;
23- use hyperactor:: Proc ;
2424use hyperactor:: Unbind ;
25- use hyperactor:: channel:: ChannelTransport ;
26- use hyperactor_mesh:: ProcMesh ;
27- use hyperactor_mesh:: actor_mesh:: ActorMesh ;
28- use hyperactor_mesh:: alloc:: AllocSpec ;
29- use hyperactor_mesh:: alloc:: Allocator ;
30- use hyperactor_mesh:: alloc:: LocalAllocator ;
25+ use hyperactor:: context;
3126use hyperactor_mesh:: comm:: multicast:: CastInfo ;
3227use hyperactor_mesh:: extent;
33- use hyperactor_mesh:: selection:: dsl:: all;
34- use hyperactor_mesh:: selection:: dsl:: true_;
35- use ndslice:: selection:: selection_from;
28+ use hyperactor_mesh:: proc_mesh:: global_root_client;
29+ use hyperactor_mesh:: v1:: ActorMeshRef ;
30+ use hyperactor_mesh:: v1:: host_mesh:: HostMesh ;
31+ use ndslice:: ViewExt ;
3632use serde:: Deserialize ;
3733use serde:: Serialize ;
3834use tokio:: sync:: OnceCell ;
@@ -124,9 +120,11 @@ impl PhilosopherActor {
124120
125121 async fn release_chopsticks ( & mut self , cx : & Instance < Self > ) -> Result < ( ) > {
126122 let ( left, right) = self . chopstick_indices ( ) ;
127- eprintln ! (
123+ tracing :: debug !(
128124 "philosopher {} releasing chopsticks, {} and {}" ,
129- self . rank, left, right
125+ self . rank,
126+ left,
127+ right
130128 ) ;
131129 self . waiter
132130 . get ( )
@@ -145,14 +143,16 @@ impl Handler<PhilosopherMessage> for PhilosopherActor {
145143 message : PhilosopherMessage ,
146144 ) -> Result < ( ) , anyhow:: Error > {
147145 let point = cx. cast_point ( ) ;
148- self . rank = point. rank ( ) ;
149146 match message {
150147 PhilosopherMessage :: Start ( waiter) => {
151148 self . waiter . set ( waiter) ?;
152149 self . request_chopsticks ( cx) . await ?;
150+ // Start is always broadcasted to all philosophers; so this is
151+ // our global rank.
152+ self . rank = point. rank ( ) ;
153153 }
154154 PhilosopherMessage :: GrantChopstick ( chopstick) => {
155- eprintln ! ( "philosopher {} granted chopstick {}" , self . rank, chopstick) ;
155+ tracing :: debug !( "philosopher {} granted chopstick {}" , self . rank, chopstick) ;
156156 let ( left, right) = self . chopstick_indices ( ) ;
157157 if left == chopstick {
158158 self . chopsticks = ( ChopstickStatus :: Granted , self . chopsticks . 1 . clone ( ) ) ;
@@ -162,7 +162,7 @@ impl Handler<PhilosopherMessage> for PhilosopherActor {
162162 unreachable ! ( "shouldn't be granted a chopstick that is not left or right" ) ;
163163 }
164164 if self . chopsticks == ( ChopstickStatus :: Granted , ChopstickStatus :: Granted ) {
165- eprintln ! ( "philosopher {} starts dining" , self . rank) ;
165+ tracing :: debug !( "philosopher {} starts dining" , self . rank) ;
166166 self . release_chopsticks ( cx) . await ?;
167167 self . request_chopsticks ( cx) . await ?;
168168 }
@@ -172,20 +172,17 @@ impl Handler<PhilosopherMessage> for PhilosopherActor {
172172 }
173173}
174174
175- struct Waiter < A > {
175+ struct Waiter {
176176 /// A map from chopstick to the rank of the philosopher who holds it.
177177 chopstick_assignments : HashMap < usize , usize > ,
178178 /// A map from chopstick to the rank of the philosopher who requested it.
179179 chopstick_requests : HashMap < usize , usize > ,
180180 /// ActorMesh of the philosophers.
181- philosophers : A ,
181+ philosophers : ActorMeshRef < PhilosopherActor > ,
182182}
183183
184- impl < A > Waiter < A >
185- where
186- A : ActorMesh < Actor = PhilosopherActor > ,
187- {
188- fn new ( philosophers : A ) -> Self {
184+ impl Waiter {
185+ fn new ( philosophers : ActorMeshRef < PhilosopherActor > ) -> Self {
189186 Self {
190187 chopstick_assignments : Default :: default ( ) ,
191188 chopstick_requests : Default :: default ( ) ,
@@ -202,68 +199,70 @@ where
202199 self . chopstick_assignments . insert ( chopstick, rank) ;
203200 }
204201
205- fn handle_request_chopstick ( & mut self , rank : usize , chopstick : usize ) -> Result < ( ) > {
202+ fn handle_request_chopstick (
203+ & mut self ,
204+ cx : & impl context:: Actor ,
205+ rank : usize ,
206+ chopstick : usize ,
207+ ) -> Result < ( ) > {
206208 if self . is_chopstick_available ( chopstick) {
207209 self . grant_chopstick ( chopstick, rank) ;
208- self . philosophers . cast (
209- self . philosophers . proc_mesh ( ) . client ( ) ,
210- selection_from ( self . philosophers . shape ( ) , & [ ( "replica" , rank..rank + 1 ) ] ) ?,
211- PhilosopherMessage :: GrantChopstick ( chopstick) ,
212- ) ?
210+ self . philosophers
211+ . range ( "replica" , rank) ?
212+ . cast ( cx, PhilosopherMessage :: GrantChopstick ( chopstick) ) ?
213213 } else {
214214 self . chopstick_requests . insert ( chopstick, rank) ;
215215 }
216216 Ok ( ( ) )
217217 }
218218
219- fn handle_release_chopstick ( & mut self , chopstick : usize ) -> Result < ( ) > {
219+ fn handle_release_chopstick (
220+ & mut self ,
221+ cx : & impl context:: Actor ,
222+ chopstick : usize ,
223+ ) -> Result < ( ) > {
220224 self . chopstick_assignments . remove ( & chopstick) ;
221225 if let Some ( rank) = self . chopstick_requests . remove ( & chopstick) {
222226 // now just handle the request again to grant the chopstick
223- self . handle_request_chopstick ( rank, chopstick) ?;
227+ self . handle_request_chopstick ( cx , rank, chopstick) ?;
224228 }
225229 Ok ( ( ) )
226230 }
227231}
228232
229233#[ tokio:: main]
230234async fn main ( ) -> Result < ExitCode > {
235+ hyperactor_telemetry:: initialize_logging_for_test ( ) ;
236+ let host_mesh = HostMesh :: local ( ) . await ?;
237+
231238 let group_size = 5 ;
232- let alloc = LocalAllocator
233- . allocate ( AllocSpec {
234- extent : extent ! { replica = group_size} ,
235- constraints : Default :: default ( ) ,
236- proc_name : None ,
237- transport : ChannelTransport :: Local ,
238- } )
239+ let instance = global_root_client ( ) ;
240+ let proc_mesh = host_mesh
241+ . spawn ( instance, "philosophers" , extent ! ( replica = group_size) )
239242 . await ?;
240243
241- let ( instance, _) = Proc :: local ( ) . instance ( "client" ) . unwrap ( ) ;
242-
243- let proc_mesh = ProcMesh :: allocate ( alloc) . await ?;
244244 let params = PhilosopherActorParams { size : group_size } ;
245245 let actor_mesh = proc_mesh
246246 . spawn :: < PhilosopherActor > ( & instance, "philosopher" , & params)
247247 . await ?;
248- let ( dining_message_handle, mut dining_message_rx) = proc_mesh . client ( ) . open_port ( ) ;
248+ let ( dining_message_handle, mut dining_message_rx) = instance . open_port ( ) ;
249249 actor_mesh
250250 . cast (
251- proc_mesh. client ( ) ,
252- all ( true_ ( ) ) ,
251+ instance,
253252 PhilosopherMessage :: Start ( dining_message_handle. bind ( ) ) ,
254253 )
255254 . unwrap ( ) ;
256- let mut waiter = Waiter :: new ( actor_mesh) ;
255+ let mut waiter = Waiter :: new ( actor_mesh. deref ( ) . clone ( ) ) ;
257256 while let Ok ( message) = dining_message_rx. recv ( ) . await {
258- eprintln ! ( "waiter received message: {:?}" , & message) ;
257+ tracing :: debug !( "waiter received message: {:?}" , & message) ;
259258 match message {
260259 WaiterMessage :: RequestChopsticks ( ( rank, left, right) ) => {
261- waiter. handle_request_chopstick ( rank, left) ?;
262- waiter. handle_request_chopstick ( rank, right) ?;
260+ waiter. handle_request_chopstick ( instance , rank, left) ?;
261+ waiter. handle_request_chopstick ( instance , rank, right) ?;
263262 }
264263 WaiterMessage :: ReleaseChopsticks ( ( left, right) ) => {
265- waiter. handle_release_chopstick ( left) ?;
266- waiter. handle_release_chopstick ( right) ?;
264+ waiter. handle_release_chopstick ( instance , left) ?;
265+ waiter. handle_release_chopstick ( instance , right) ?;
267266 }
268267 }
269268 let mut sorted_chopstick_assignments = waiter
@@ -272,7 +271,7 @@ async fn main() -> Result<ExitCode> {
272271 . map ( |( k, v) | ( * k, * v) )
273272 . collect :: < Vec < _ > > ( ) ;
274273 sorted_chopstick_assignments. sort ( ) ;
275- eprintln ! (
274+ tracing :: debug !(
276275 "assignments [(CHO, PHI)]: {:?}" ,
277276 sorted_chopstick_assignments
278277 ) ;
@@ -282,7 +281,7 @@ async fn main() -> Result<ExitCode> {
282281 . map ( |( k, v) | ( * k, * v) )
283282 . collect :: < Vec < _ > > ( ) ;
284283 sorted_chopstick_requests. sort ( ) ;
285- eprintln ! (
284+ tracing :: debug !(
286285 "pending requests [(CHO, PHI)]:: {:?}" ,
287286 sorted_chopstick_requests
288287 ) ;
0 commit comments