Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'issue105' into 'master'
[simgrid.git] / teshsuite / s4u / monkey-masterworkers / monkey-masterworkers.py
1 # Copyright (c) 2007-2022. The SimGrid Team. All rights reserved.          
2 #
3 # This program is free software; you can redistribute it and/or modify it
4 # under the terms of the license (GNU LGPL) which comes with this package. 
5
6 """
7  This is a version of the masterworkers that (hopefully) survives to the chaos monkey.
8  It tests synchronous send/receive as well as synchronous computations.
9
10  It is not written to be pleasant to read, but instead to resist the aggressions of the monkey:
11  - Workers keep going until after a global variable `todo` reaches 0.
12  - The master is a daemon that just sends infinitely tasks
13    (simgrid simulations stop as soon as all non-daemon actors are done).
14  - The platform is created programmatically to remove path issues and control the problem size.
15
16  See the simgrid-monkey script for more information.
17
18  Inline configuration items:
19  - host-count: how many actors to start (including the master
20  - task-count: initial value of the `todo` global
21  - deadline: time at which the simulation is known to be failed (to detect infinite loops).
22
23 """
24
25 # Configuration items:
26 host_count = 3 # Host count (master on one, workers on the others)
27 task_count = 1 # Amount of tasks that must be executed to succeed
28 deadline = 120 # When to fail the simulation (infinite loop detection)
29 # End of configuration
30
31 import sys
32 from simgrid import Actor, Engine, Host, this_actor, Mailbox, NetZone, LinkInRoute, TimeoutException, NetworkFailureException
33
34 todo = task_count # remaining amount of tasks to execute, a global variable
35
36 def master():
37   comp_size = int(1e6)
38   comm_size = int(1e6)
39   this_actor.info("Master booting")
40   Actor.self().daemonize()
41   this_actor.on_exit(lambda killed: this_actor.info("Master dying forcefully." if killed else "Master dying peacefully."))
42
43   while True: # This is a daemon
44     assert Engine.clock < deadline, f"Failed to run all tasks in less than {deadline} seconds. Is this an infinite loop?"
45
46     try: 
47       this_actor.info("Try to send a message")
48       mailbox.put(comp_size, comm_size, 10.)
49     except TimeoutException:
50       this_actor.info("Timeouted while sending a task")
51     except NetworkFailureException:
52       this_actor.info("Got a NetworkFailureException. Wait a second before starting again.")
53       this_actor.sleep_for(1.)
54
55   assert False, "The impossible just happened (yet again): daemons shall not finish."
56
57 def worker(my_id):
58   global todo
59   this_actor.info(f"Worker {my_id} booting")
60   this_actor.on_exit(lambda killed: this_actor.info(f"Worker {my_id} dying {'forcefully' if killed else 'peacefully'}."))
61
62   while todo > 0:
63     assert Engine.clock < deadline, f"Failed to run all tasks in less than {deadline} seconds. Is this an infinite loop?"
64
65     try:
66       this_actor.info(f"Waiting a message on mailbox")
67       compute_cost = mailbox.get()
68
69       this_actor.info("Start execution...")
70       this_actor.execute(compute_cost)
71       todo = todo - 1
72       this_actor.info(f"Execution complete. Still {todo} to go.")
73
74     except NetworkFailureException:
75       this_actor.info("Got a NetworkFailureException. Wait a second before starting again.")
76       this_actor.sleep_for(1.)
77     except TimeoutException:
78       this_actor.info("Timeouted while getting a task.")
79
80 if __name__ == '__main__':
81   e = Engine(sys.argv)
82
83   assert host_count > 2, "You need at least 2 workers (i.e., 3 hosts) or the master will be auto-killed when the only worker gets killed."
84   assert todo > 0, "Please give some tasks to do to the workers."
85
86   mailbox = Mailbox.by_name("mailbox")
87
88   rootzone = NetZone.create_full_zone("Zone1")
89   main = rootzone.create_host("lilibeth 0", 1e9)
90   Actor.create("master", main, master).set_auto_restart(True)
91
92   for i in range(1, host_count):
93     link = rootzone.create_split_duplex_link(f"link {i}", "1MBps").set_latency("24us")
94     host = rootzone.create_host(f"lilibeth {i}", 1e9)
95     rootzone.add_route(main.netpoint, host.netpoint, None, None, [LinkInRoute(link, LinkInRoute.Direction.UP)], True)
96     Actor.create("worker", host, worker, i).set_auto_restart(True)
97
98   e.netzone_root.seal()
99   e.run()
100
101   this_actor.info("WE SURVIVED!")