Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
d64b98fae2bbbc0564026094853842d624ce5784
[simgrid.git] / docs / source / tuto_disk / tuto_disk.cpp
1 /* Copyright (c) 2017-2021. 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 tutorial presents how to faithful emulate disk operation in SimGrid
7  */
8
9 #include <boost/property_tree/json_parser.hpp>
10 #include <boost/property_tree/ptree.hpp>
11 #include <random>
12 #include <simgrid/s4u.hpp>
13
14 namespace sg4 = simgrid::s4u;
15
16 XBT_LOG_NEW_DEFAULT_CATEGORY(disk_test, "Messages specific for this simulation");
17
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)
20 {
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++) {
25     sg4::IoPtr act;
26     if (read)
27       act = disk->read_async(size);
28     else
29       act = disk->write_async(size);
30
31     activities.push_back(act);
32   }
33
34   for (const auto& act : activities)
35     act->wait();
36
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);
39 }
40
41 static void host()
42 {
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);
49       }
50     }
51   }
52 }
53
54 /*************************************************************************************************/
55 /** @brief Auxiliary class to generate noise in disk operations */
56 class DiskNoise {
57   double bw_;
58   std::vector<double> breaks_;
59   std::vector<double> heights_;
60   std::mt19937& gen_;
61
62 public:
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)
65   {
66   }
67   double operator()(sg_size_t /*size*/) const
68   {
69     std::piecewise_constant_distribution<double> d(breaks_.begin(), breaks_.end(), heights_.begin());
70     auto value = d(gen_);
71     return value / bw_;
72   }
73 };
74
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)
77 {
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);
82   }
83   return v;
84 }
85 /*************************************************************************************************/
86 /**
87  * @brief Non-linear resource callback for disks
88  *
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
92  */
93 static double disk_dynamic_sharing(const std::vector<double>& degradation, double capacity, int n)
94 {
95   n--;
96   if (n >= degradation.size())
97     return capacity;
98   return degradation[n];
99 }
100
101 /**
102  * @brief Noise for I/O operations
103  *
104  * @param data Map with noise information
105  * @param size I/O size in bytes
106  * @param op I/O operation: read/write
107  */
108 static double disk_variability(const std::unordered_map<sg4::Io::OpType, DiskNoise>& data, sg_size_t size,
109                                sg4::Io::OpType op)
110 {
111   auto it = data.find(op);
112   if (it == data.end())
113     return 1.0;
114   double value = it->second(size);
115   return value;
116 }
117
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)
121 {
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");
127
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);
132
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);
139
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"));
145
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));
149   disk->seal();
150 }
151
152 /*************************************************************************************************/
153 int main(int argc, char** argv)
154 {
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);
165   }
166   zone->seal();
167
168   sg4::Actor::create("", bob, host);
169
170   printf("disk,op,n,flows,size,elapsed\n");
171
172   e.run();
173
174   return 0;
175 }