1 # Copyright (c) 2006-2023. The SimGrid Team. All rights reserved.
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.
7 This example shows how to simulate a non-linear resource sharing for disk
10 It is inspired on the paper
11 "Adding Storage Simulation Capacities to the SimGridToolkit: Concepts, Models, and API"
12 Available at : https://hal.inria.fr/hal-01197128/document
14 It shows how to simulate concurrent operations degrading overall performance of IO
15 operations (specifically the effects presented in Fig. 8 of the paper).
21 from simgrid import Actor, Engine, NetZone, Host, Disk, this_actor
24 def estimate_bw(disk: Disk, n_flows: int, read: bool):
25 """ Calculates the bandwidth for disk doing async operations """
27 cur_time = Engine.clock
28 activities = [disk.read_async(size) if read else disk.write_async(
29 size) for _ in range(n_flows)]
31 for act in activities:
34 elapsed_time = Engine.clock - cur_time
35 estimated_bw = float(size * n_flows) / elapsed_time
36 this_actor.info("Disk: %s, concurrent %s: %d, estimated bandwidth: %f" % (
37 disk.name, "read" if read else "write", n_flows, estimated_bw))
41 # Estimating bw for each disk and considering concurrent flows
42 for n in range(1, 15, 2):
43 for disk in Host.current().get_disks():
44 estimate_bw(disk, n, True)
45 estimate_bw(disk, n, False)
48 def ssd_dynamic_sharing(disk: Disk, op: str, capacity: float, n: int) -> float:
50 Non-linear resource callback for SSD disks
52 In this case, we have measurements for some resource sharing and directly use them to return the
54 :param disk: Disk on which the operation is happening (defined by the user through the std::bind)
55 :param op: read or write operation (defined by the user through the std::bind)
56 :param capacity: Resource current capacity in SimGrid
57 :param n: Number of activities sharing this resource
59 # measurements for SSD disks
62 "read": {1: 152., 2: 161., 3: 184., 4: 197., 5: 207., 6: 215., 7: 220., 8: 224., 9: 227., 10: 231., 11: 233.,
63 12: 235., 13: 237., 14: 238., 15: 239.}
66 # no special bandwidth for this disk sharing N flows, just returns maximal capacity
68 capacity = speed[op][n]
73 def sata_dynamic_sharing(disk: Disk, capacity: float, n: int) -> float:
75 Non-linear resource callback for SATA disks
77 In this case, the degradation for read operations is linear and we have a formula that represents it.
79 :param disk: Disk on which the operation is happening (defined by the user through the std::bind)
80 :param capacity: Resource current capacity in SimGrid
81 :param n: Number of activities sharing this resource
82 :return: New disk capacity
87 def create_ssd_disk(host: Host, disk_name: str):
88 """ Creates an SSD disk, setting the appropriate callback for non-linear resource sharing """
89 disk = host.create_disk(disk_name, "240MBps", "170MBps")
90 disk.set_sharing_policy(Disk.Operation.READ, Disk.SharingPolicy.NONLINEAR,
91 functools.partial(ssd_dynamic_sharing, disk, "read"))
92 disk.set_sharing_policy(Disk.Operation.WRITE, Disk.SharingPolicy.NONLINEAR,
93 functools.partial(ssd_dynamic_sharing, disk, "write"))
94 disk.set_sharing_policy(Disk.Operation.READWRITE,
95 Disk.SharingPolicy.LINEAR)
98 def create_sata_disk(host: Host, disk_name: str):
99 """ Same for a SATA disk, only read operation follows a non-linear resource sharing """
100 disk = host.create_disk(disk_name, "68MBps", "50MBps")
101 disk.set_sharing_policy(Disk.Operation.READ, Disk.SharingPolicy.NONLINEAR,
102 functools.partial(sata_dynamic_sharing, disk))
103 # this is the default behavior, expliciting only to make it clearer
104 disk.set_sharing_policy(Disk.Operation.WRITE, Disk.SharingPolicy.LINEAR)
105 disk.set_sharing_policy(Disk.Operation.READWRITE,
106 Disk.SharingPolicy.LINEAR)
109 if __name__ == '__main__':
111 # simple platform containing 1 host and 2 disk
112 zone = NetZone.create_full_zone("bob_zone")
113 bob = zone.create_host("bob", 1e6)
114 create_ssd_disk(bob, "Edel (SSD)")
115 create_sata_disk(bob, "Griffon (SATA II)")
118 Actor.create("runner", bob, host_runner)
121 this_actor.info("Simulated time: %g" % e.clock)
123 # explicitly deleting Engine object to avoid segfault during cleanup phase.
124 # During Engine destruction, the cleanup of std::function linked to non_linear callback is called.
125 # If we let the cleanup by itself, it fails trying on its destruction because the python main program
126 # has already freed its variables