File: io-degradation.py

package info (click to toggle)
simgrid 4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 39,192 kB
  • sloc: cpp: 124,913; ansic: 66,744; python: 8,560; java: 6,773; fortran: 6,079; f90: 5,123; xml: 4,587; sh: 2,194; perl: 1,436; makefile: 111; lisp: 49; javascript: 7; sed: 6
file content (127 lines) | stat: -rw-r--r-- 5,066 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# Copyright (c) 2006-2025. The SimGrid Team. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the license (GNU LGPL) which comes with this package.

"""
This example shows how to simulate a non-linear resource sharing for disk
operations.

It is inspired on the paper
"Adding Storage Simulation Capacities to the SimGridToolkit: Concepts, Models, and API"
Available at : https://hal.inria.fr/hal-01197128/document

It shows how to simulate concurrent operations degrading overall performance of IO
operations (specifically the effects presented in Fig. 8 of the paper).
"""


import functools
import sys
from simgrid import Actor, Engine, NetZone, Host, Disk, this_actor


def estimate_bw(disk: Disk, n_flows: int, read: bool):
    """ Calculates the bandwidth for disk doing async operations """
    size = 100000
    cur_time = Engine.clock
    activities = [disk.read_async(size) if read else disk.write_async(
        size) for _ in range(n_flows)]

    for act in activities:
        act.wait()

    elapsed_time = Engine.clock - cur_time
    estimated_bw = float(size * n_flows) / elapsed_time
    this_actor.info("Disk: %s, concurrent %s: %d, estimated bandwidth: %f" % (
        disk.name, "read" if read else "write", n_flows, estimated_bw))


def host_runner():
    # Estimating bw for each disk and considering concurrent flows
    for n in range(1, 15, 2):
        for disk in Host.current().get_disks():
            estimate_bw(disk, n, True)
            estimate_bw(disk, n, False)


def ssd_dynamic_sharing(disk: Disk, op: str, capacity: float, n: int) -> float:
    """
    Non-linear resource callback for SSD disks

    In this case, we have measurements for some resource sharing and directly use them to return the
    correct value
    :param disk: Disk on which the operation is happening (defined by the user through the std::bind)
    :param op: read or write operation (defined by the user through the std::bind)
    :param capacity: Resource current capacity in SimGrid
    :param n: Number of activities sharing this resource
    """
    # measurements for SSD disks
    speed = {
        "write": {1: 131.},
        "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.}
    }

    # no special bandwidth for this disk sharing N flows, just returns maximal capacity
    if n in speed[op]:
        capacity = speed[op][n]

    return capacity


def sata_dynamic_sharing(disk: Disk, capacity: float, n: int) -> float:
    """
    Non-linear resource callback for SATA disks

    In this case, the degradation for read operations is linear and we have a formula that represents it.

    :param disk: Disk on which the operation is happening (defined by the user through the std::bind)
    :param capacity: Resource current capacity in SimGrid
    :param n: Number of activities sharing this resource
    :return: New disk capacity
    """
    return 68.3 - 1.7 * n


def create_ssd_disk(host: Host, disk_name: str):
    """ Creates an SSD disk, setting the appropriate callback for non-linear resource sharing """
    disk = host.add_disk(disk_name, "240MBps", "170MBps")
    disk.set_sharing_policy(Disk.Operation.READ, Disk.SharingPolicy.NONLINEAR,
                            functools.partial(ssd_dynamic_sharing, disk, "read"))
    disk.set_sharing_policy(Disk.Operation.WRITE, Disk.SharingPolicy.NONLINEAR,
                            functools.partial(ssd_dynamic_sharing, disk, "write"))
    disk.set_sharing_policy(Disk.Operation.READWRITE,
                            Disk.SharingPolicy.LINEAR)


def create_sata_disk(host: Host, disk_name: str):
    """ Same for a SATA disk, only read operation follows a non-linear resource sharing """
    disk = host.add_disk(disk_name, "68MBps", "50MBps")
    disk.set_sharing_policy(Disk.Operation.READ, Disk.SharingPolicy.NONLINEAR,
                            functools.partial(sata_dynamic_sharing, disk))
    # this is the default behavior, expliciting only to make it clearer
    disk.set_sharing_policy(Disk.Operation.WRITE, Disk.SharingPolicy.LINEAR)
    disk.set_sharing_policy(Disk.Operation.READWRITE,
                            Disk.SharingPolicy.LINEAR)


if __name__ == '__main__':
    e = Engine(sys.argv)
    # simple platform containing 1 host and 2 disk
    zone = e.netzone_root.add_netzone_full("bob_zone")
    bob = zone.add_host("bob", 1e6)
    create_ssd_disk(bob, "Edel (SSD)")
    create_sata_disk(bob, "Griffon (SATA II)")
    zone.seal()

    bob.add_actor("runner", host_runner)

    e.run()
    this_actor.info("Simulated time: %g" % e.clock)

    # explicitly deleting Engine object to avoid segfault during cleanup phase.
    # During Engine destruction, the cleanup of std::function linked to non_linear callback is called.
    # If we let the cleanup by itself, it fails trying on its destruction because the python main program
    # has already freed its variables
    del e