1 /* Copyright (c) 2017-2021. 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. */
6 /* This tutorial presents how to faithful emulate disk operation in SimGrid
9 #include <boost/property_tree/json_parser.hpp>
10 #include <boost/property_tree/ptree.hpp>
12 #include <simgrid/s4u.hpp>
14 namespace sg4 = simgrid::s4u;
16 XBT_LOG_NEW_DEFAULT_CATEGORY(disk_test, "Messages specific for this simulation");
18 /** @brief Calculates the bandwidth for disk doing async operations */
19 static void estimate_bw(const sg4::Disk* disk, int n, int n_flows, bool read)
21 unsigned long long size = 100000;
22 double cur_time = sg4::Engine::get_clock();
23 std::vector<sg4::IoPtr> activities;
24 for (int i = 0; i < n_flows; i++) {
27 act = disk->read_async(size);
29 act = disk->write_async(size);
31 activities.push_back(act);
34 for (const auto& act : activities)
37 double elapsed_time = sg4::Engine::get_clock() - cur_time;
38 printf("%s,%s,%d,%d,%d,%lf\n", disk->get_cname(), read ? "read" : "write", n, n_flows, size, elapsed_time);
43 /* - Estimating bw for each disk and considering concurrent flows */
44 for (int i = 0; i < 20; i++) {
45 for (int flows = 1; flows <= 15; flows++) {
46 for (auto* disk : sg4::Host::current()->get_disks()) {
47 estimate_bw(disk, i, flows, true);
48 estimate_bw(disk, i, flows, false);
54 /*************************************************************************************************/
55 /** @brief Auxiliary class to generate noise in disk operations */
58 std::vector<double> breaks_;
59 std::vector<double> heights_;
63 DiskNoise(double capacity, std::mt19937& gen, const std::vector<double>& b, const std::vector<double> h)
64 : bw_(capacity), breaks_(b), heights_(h), gen_(gen)
67 double operator()(sg_size_t /*size*/) const
69 std::piecewise_constant_distribution<double> d(breaks_.begin(), breaks_.end(), heights_.begin());
75 /** @brief Auxiliary method to get list of values from json in a vector */
76 static std::vector<double> get_list_from_json(const boost::property_tree::ptree& pt, const std::string& path)
78 std::vector<double> v;
79 for (const auto& it : pt.get_child(path)) {
80 double value = it.second.get_value<double>();
81 v.push_back(value * 1e6);
85 /*************************************************************************************************/
87 * @brief Non-linear resource callback for disks
89 * @param degradation Vector with effective read/write bandwidth
90 * @param capacity Resource current capacity in SimGrid
91 * @param n Number of activities sharing this resource
93 static double disk_dynamic_sharing(const std::vector<double>& degradation, double capacity, int n)
96 if (n >= degradation.size())
98 return degradation[n];
102 * @brief Noise for I/O operations
104 * @param data Map with noise information
105 * @param size I/O size in bytes
106 * @param op I/O operation: read/write
108 static double disk_variability(const std::unordered_map<sg4::Io::OpType, DiskNoise>& data, sg_size_t size,
111 auto it = data.find(op);
112 if (it == data.end())
114 double value = it->second(size);
118 /** @brief Creates a disk */
119 static void create_disk(sg4::Host* host, std::mt19937& gen, const std::string& disk_name,
120 const boost::property_tree::ptree& pt)
122 double read_bw = pt.get_child("read_bw").begin()->second.get_value<double>() * 1e6;
123 double write_bw = pt.get_child("write_bw").begin()->second.get_value<double>() * 1e6;
124 auto* disk = host->create_disk(disk_name, read_bw, write_bw);
125 std::vector<double> read_deg = get_list_from_json(pt, "degradation.read");
126 std::vector<double> write_deg = get_list_from_json(pt, "degradation.write");
128 /* get maximum possible disk speed for read/write disk constraint */
129 double max_bw = std::max(*std::max_element(read_deg.begin(), read_deg.end()),
130 *std::max_element(write_deg.begin(), write_deg.end()));
131 disk->set_readwrite_bandwidth(max_bw);
133 disk->set_sharing_policy(sg4::Disk::Operation::READ, sg4::Disk::SharingPolicy::NONLINEAR,
134 std::bind(&disk_dynamic_sharing, read_deg, std::placeholders::_1, std::placeholders::_2));
135 disk->set_sharing_policy(sg4::Disk::Operation::WRITE, sg4::Disk::SharingPolicy::NONLINEAR,
136 std::bind(&disk_dynamic_sharing, write_deg, std::placeholders::_1, std::placeholders::_2));
137 /* this is the default behavior, expliciting only to make it clearer */
138 disk->set_sharing_policy(sg4::Disk::Operation::READWRITE, sg4::Disk::SharingPolicy::LINEAR);
140 /* configuring variability */
141 DiskNoise read_noise(read_bw, gen, get_list_from_json(pt, "noise.read.breaks"),
142 get_list_from_json(pt, "noise.read.heights"));
143 DiskNoise write_noise(write_bw, gen, get_list_from_json(pt, "noise.write.breaks"),
144 get_list_from_json(pt, "noise.write.heights"));
146 std::unordered_map<sg4::Io::OpType, DiskNoise> noise{{sg4::Io::OpType::READ, read_noise},
147 {sg4::Io::OpType::WRITE, write_noise}};
148 disk->set_factor_cb(std::bind(&disk_variability, noise, std::placeholders::_1, std::placeholders::_2));
152 /*************************************************************************************************/
153 int main(int argc, char** argv)
155 sg4::Engine e(&argc, argv);
156 std::mt19937 gen(42);
157 /* simple platform containing 1 host and 2 disk */
158 auto* zone = sg4::create_full_zone("bob_zone");
159 auto* bob = zone->create_host("bob", 1e6);
160 std::ifstream jsonFile("IO_noise.json");
161 boost::property_tree::ptree pt;
162 boost::property_tree::read_json(jsonFile, pt);
163 for (const auto& it : pt.get_child("")) {
164 create_disk(bob, gen, it.first, it.second);
168 sg4::Actor::create("", bob, host);
170 printf("disk,op,n,flows,size,elapsed\n");