Logo AND Algorithmique Numérique Distribuée

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