include examples/cpp/exec-waitfor/s4u-exec-waitfor.tesh
include examples/cpp/io-async/s4u-io-async.cpp
include examples/cpp/io-async/s4u-io-async.tesh
+include examples/cpp/io-degradation/s4u-io-degradation.cpp
+include examples/cpp/io-degradation/s4u-io-degradation.tesh
include examples/cpp/io-dependent/s4u-io-dependent.cpp
include examples/cpp/io-dependent/s4u-io-dependent.tesh
include examples/cpp/io-disk-raw/s4u-io-disk-raw.cpp
maestro-set
mc-bugged1 mc-bugged2 mc-electric-fence mc-failing-assert
network-wifi
- io-async io-file-system io-file-remote io-disk-raw io-dependent
+ io-async io-degradation io-file-system io-file-remote io-disk-raw io-dependent
platform-failures platform-profile platform-properties
plugin-host-load plugin-link-load plugin-prodcons
replay-comm replay-io
--- /dev/null
+/* Copyright (c) 2017-2021. 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).
+ */
+
+#include <simgrid/s4u.hpp>
+
+namespace sg4 = simgrid::s4u;
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(disk_test, "Messages specific for this simulation");
+
+/** @brief Calculates the bandwidth for disk doing async operations */
+static void estimate_bw(sg4::Disk* disk, int n_flows, bool read)
+{
+ unsigned long long size = 100000;
+ double cur_time = sg4::Engine::get_clock();
+ std::vector<sg4::IoPtr> activities;
+ for (int i = 0; i < n_flows; i++) {
+ sg4::IoPtr act;
+ if (read)
+ act = disk->read_async(size);
+ else
+ act = disk->write_async(size);
+
+ activities.push_back(act);
+ }
+
+ for (auto& act : activities)
+ act->wait();
+
+ double elapsed_time = sg4::Engine::get_clock() - cur_time;
+ double estimated_bw = size * n_flows / elapsed_time;
+ XBT_INFO("Disk: %s, concurrent %s: %d, estimated bandwidth: %lf", disk->get_cname(), read ? "read" : "write", n_flows,
+ estimated_bw);
+}
+
+static void host()
+{
+ /* - Estimating bw for each disk and considering concurrent flows */
+ for (int n = 1; n < 15; n += 2) {
+ for (auto* disk : sg4::Host::current()->get_disks()) {
+ estimate_bw(disk, n, true);
+ estimate_bw(disk, n, false);
+ }
+ }
+}
+
+/**
+ * @brief 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
+ */
+static double ssd_dynamic_sharing(const sg4::Disk* disk, const std::string& op, double capacity, int n)
+{
+ /* measurements for SSD disks */
+ using DiskCapacity = std::unordered_map<int, double>;
+ static const std::unordered_map<std::string, DiskCapacity> SSD_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.}}}};
+
+ const auto& data = SSD_SPEED.at(op);
+ /* no special bandwidth for this disk sharing N flows, just returns maximal capacity */
+ if (data.find(n) != data.end())
+ capacity = data.at(n);
+
+ // XBT_INFO("Disk %s, %s operation between %d flows, capacity %lf", disk->get_cname(), op.c_str(), n, capacity);
+
+ return capacity;
+}
+
+/**
+ * @brief 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
+ */
+static double sata_dynamic_sharing(const sg4::Disk* disk, double capacity, int n)
+{
+ capacity = 68.3 - 1.7 * n;
+ // XBT_INFO("Disk %s, read operation between %d flows, capacity %lf", disk->get_cname(), n, capacity);
+
+ return capacity;
+}
+
+/** @brief Creates an SSD disk, setting the appropriate callback for non-linear resource sharing */
+static void create_ssd_disk(sg4::Host* host, const std::string& disk_name)
+{
+ auto* disk = host->create_disk(disk_name, "240MBps", "170MBps");
+ disk->set_sharing_policy(sg4::Disk::Operation::READ, sg4::Disk::SharingPolicy::NONLINEAR,
+ std::bind(&ssd_dynamic_sharing, disk, "read", std::placeholders::_1, std::placeholders::_2));
+ disk->set_sharing_policy(
+ sg4::Disk::Operation::WRITE, sg4::Disk::SharingPolicy::NONLINEAR,
+ std::bind(&ssd_dynamic_sharing, disk, "write", std::placeholders::_1, std::placeholders::_2));
+ disk->set_sharing_policy(sg4::Disk::Operation::READWRITE, sg4::Disk::SharingPolicy::LINEAR);
+}
+
+/** @brief Same for a SATA disk, only read operation follows a non-linear resource sharing */
+static void create_sata_disk(sg4::Host* host, const std::string& disk_name)
+{
+ auto* disk = host->create_disk(disk_name, "68MBps", "50MBps");
+ disk->set_sharing_policy(sg4::Disk::Operation::READ, sg4::Disk::SharingPolicy::NONLINEAR,
+ std::bind(&sata_dynamic_sharing, disk, std::placeholders::_1, std::placeholders::_2));
+ /* this is the default behavior, expliciting only to make it clearer */
+ disk->set_sharing_policy(sg4::Disk::Operation::WRITE, sg4::Disk::SharingPolicy::LINEAR);
+ disk->set_sharing_policy(sg4::Disk::Operation::READWRITE, sg4::Disk::SharingPolicy::LINEAR);
+}
+
+int main(int argc, char** argv)
+{
+ sg4::Engine e(&argc, argv);
+ /* simple platform containing 1 host and 2 disk */
+ auto* zone = sg4::create_full_zone("bob_zone");
+ auto* bob = zone->create_host("bob", 1e6);
+ create_ssd_disk(bob, "Edel (SSD)");
+ create_sata_disk(bob, "Griffon (SATA II)");
+ zone->seal();
+
+ simgrid::s4u::Actor::create("", bob, host);
+
+ e.run();
+ XBT_INFO("Simulated time: %g", simgrid::s4u::Engine::get_clock());
+
+ return 0;
+}
--- /dev/null
+#!/usr/bin/env tesh
+
+$ ${bindir}/s4u-io-degradation "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
+> [657.894737] (1:@bob) Disk: Edel (SSD), concurrent read: 1, estimated bandwidth: 152.000000
+> [1421.253515] (1:@bob) Disk: Edel (SSD), concurrent write: 1, estimated bandwidth: 131.000000
+> [2922.755017] (1:@bob) Disk: Griffon (SATA II), concurrent read: 1, estimated bandwidth: 66.600000
+> [2922.757017] (1:@bob) Disk: Griffon (SATA II), concurrent write: 1, estimated bandwidth: 50000000.001182
+> [4553.191800] (1:@bob) Disk: Edel (SSD), concurrent read: 3, estimated bandwidth: 184.000000
+> [4553.193564] (1:@bob) Disk: Edel (SSD), concurrent write: 3, estimated bandwidth: 170000000.022058
+> [9300.029007] (1:@bob) Disk: Griffon (SATA II), concurrent read: 3, estimated bandwidth: 63.200000
+> [9300.035007] (1:@bob) Disk: Griffon (SATA II), concurrent write: 3, estimated bandwidth: 50000000.004972
+> [11715.493945] (1:@bob) Disk: Edel (SSD), concurrent read: 5, estimated bandwidth: 207.000000
+> [11715.496886] (1:@bob) Disk: Edel (SSD), concurrent write: 5, estimated bandwidth: 170000000.039581
+> [20076.700899] (1:@bob) Disk: Griffon (SATA II), concurrent read: 5, estimated bandwidth: 59.800000
+> [20076.710899] (1:@bob) Disk: Griffon (SATA II), concurrent write: 5, estimated bandwidth: 50000000.008004
+> [23258.529081] (1:@bob) Disk: Edel (SSD), concurrent read: 7, estimated bandwidth: 220.000000
+> [23258.533199] (1:@bob) Disk: Edel (SSD), concurrent write: 7, estimated bandwidth: 170000000.009542
+> [35669.880716] (1:@bob) Disk: Griffon (SATA II), concurrent read: 7, estimated bandwidth: 56.400000
+> [35669.894716] (1:@bob) Disk: Griffon (SATA II), concurrent write: 7, estimated bandwidth: 49999999.989814
+> [39634.652426] (1:@bob) Disk: Edel (SSD), concurrent read: 9, estimated bandwidth: 227.000000
+> [39634.657720] (1:@bob) Disk: Edel (SSD), concurrent write: 9, estimated bandwidth: 169999999.992853
+> [56615.789795] (1:@bob) Disk: Griffon (SATA II), concurrent read: 9, estimated bandwidth: 53.000000
+> [56615.807795] (1:@bob) Disk: Griffon (SATA II), concurrent write: 9, estimated bandwidth: 50000000.010025
+> [61336.837838] (1:@bob) Disk: Edel (SSD), concurrent read: 11, estimated bandwidth: 233.000000
+> [61336.844309] (1:@bob) Disk: Edel (SSD), concurrent write: 11, estimated bandwidth: 170000000.077813
+> [83514.263663] (1:@bob) Disk: Griffon (SATA II), concurrent read: 11, estimated bandwidth: 49.600000
+> [83514.285663] (1:@bob) Disk: Griffon (SATA II), concurrent write: 11, estimated bandwidth: 50000000.006350
+> [88999.517731] (1:@bob) Disk: Edel (SSD), concurrent read: 13, estimated bandwidth: 237.000000
+> [88999.525378] (1:@bob) Disk: Edel (SSD), concurrent write: 13, estimated bandwidth: 169999999.974881
+> [117138.053517] (1:@bob) Disk: Griffon (SATA II), concurrent read: 13, estimated bandwidth: 46.200000
+> [117138.079517] (1:@bob) Disk: Griffon (SATA II), concurrent write: 13, estimated bandwidth: 50000000.003806
+> [117138.079517] (0:maestro@) Simulated time: 117138
XBT_PUBLIC void intrusive_ptr_add_ref(const Semaphore* m);
class Disk;
+/**
+ * @brief Callback to dynamically change the resource's capacity
+ *
+ * Allows user to change resource's capacity depending on the number of concurrent activities
+ * running on the resource at a given instant
+ */
+using NonLinearResourceCb = std::function<double(double capacity, int n_activities)>;
} // namespace s4u
namespace config {
IoPtr write_async(sg_size_t size) const;
sg_size_t write(sg_size_t size) const;
+ /** @brief Policy for sharing the disk among activities */
+ enum class SharingPolicy { NONLINEAR = 1, LINEAR = 0 };
+ enum class Operation { READ = 2, WRITE = 1, READWRITE = 0 };
+
+ /**
+ * @brief Describes how the disk is shared between activities for each operation
+ *
+ * Disks have different bandwidths for read and write operations. This method
+ * allows you to set different sharing policies for each operation:
+ * - Read: resource sharing for read operation
+ * - Write: resource sharing for write
+ * - ReadWrite: global sharing for read and write operations
+ *
+ * @param op Operation type
+ * @param policy Sharing policy
+ * @param cb Callback for NONLINEAR policies
+ */
+ Disk* set_sharing_policy(Operation op, SharingPolicy policy, const s4u::NonLinearResourceCb& cb = {});
+ SharingPolicy get_sharing_policy(Operation op) const;
+
Disk* seal();
/* The signals */
for (Constraint& cnst : cnst_list) {
/* INIT: Collect constraints that actually need to be saturated (i.e remaining and usage are strictly positive)
* into cnst_light_tab. */
- cnst.remaining_ = cnst.bound_;
- if (not double_positive(cnst.remaining_, cnst.bound_ * sg_maxmin_precision))
+ cnst.dynamic_bound_ = cnst.bound_;
+ if (cnst.get_sharing_policy() == Constraint::SharingPolicy::NONLINEAR && cnst.dyn_constraint_cb_) {
+ cnst.dynamic_bound_ = cnst.dyn_constraint_cb_(cnst.bound_, cnst.concurrency_current_);
+ }
+ cnst.remaining_ = cnst.dynamic_bound_;
+ if (not double_positive(cnst.remaining_, cnst.dynamic_bound_ * sg_maxmin_precision))
continue;
cnst.usage_ = 0;
for (Element& elem : cnst.enabled_element_set_) {
Constraint* cnst = elem.constraint;
if (cnst->sharing_policy_ != Constraint::SharingPolicy::FATPIPE) {
// Remember: shared constraints require that sum(elem.value * var.value) < cnst->bound
- double_update(&(cnst->remaining_), elem.consumption_weight * var.value_, cnst->bound_ * sg_maxmin_precision);
+ double_update(&(cnst->remaining_), elem.consumption_weight * var.value_,
+ cnst->dynamic_bound_ * sg_maxmin_precision);
double_update(&(cnst->usage_), elem.consumption_weight / var.sharing_penalty_, sg_maxmin_precision);
// If the constraint is saturated, remove it from the set of active constraints (light_tab)
if (not double_positive(cnst->usage_, sg_maxmin_precision) ||
- not double_positive(cnst->remaining_, cnst->bound_ * sg_maxmin_precision)) {
+ not double_positive(cnst->remaining_, cnst->dynamic_bound_ * sg_maxmin_precision)) {
if (cnst->cnst_light_) {
size_t index = (cnst->cnst_light_ - cnst_light_tab);
XBT_DEBUG("index: %zu \t cnst_light_num: %d \t || usage: %f remaining: %f bound: %f ", index,
- cnst_light_num, cnst->usage_, cnst->remaining_, cnst->bound_);
+ cnst_light_num, cnst->usage_, cnst->remaining_, cnst->dynamic_bound_);
cnst_light_tab[index] = cnst_light_tab[cnst_light_num - 1];
cnst_light_tab[index].cnst->cnst_light_ = &cnst_light_tab[index];
cnst_light_num--;
}
// If the constraint is saturated, remove it from the set of active constraints (light_tab)
if (not double_positive(cnst->usage_, sg_maxmin_precision) ||
- not double_positive(cnst->remaining_, cnst->bound_ * sg_maxmin_precision)) {
+ not double_positive(cnst->remaining_, cnst->dynamic_bound_ * sg_maxmin_precision)) {
if (cnst->cnst_light_) {
size_t index = (cnst->cnst_light_ - cnst_light_tab);
XBT_DEBUG("index: %zu \t cnst_light_num: %d \t || \t cnst: %p \t cnst->cnst_light: %p "
"\t cnst_light_tab: %p usage: %f remaining: %f bound: %f ",
index, cnst_light_num, cnst, cnst->cnst_light_, cnst_light_tab, cnst->usage_, cnst->remaining_,
- cnst->bound_);
+ cnst->dynamic_bound_);
cnst_light_tab[index] = cnst_light_tab[cnst_light_num - 1];
cnst_light_tab[index].cnst->cnst_light_ = &cnst_light_tab[index];
cnst_light_num--;
[](const Element& elem) { return elem.consumption_weight > 0; }));
}
+void Constraint::set_sharing_policy(SharingPolicy policy, const s4u::NonLinearResourceCb& cb)
+{
+ xbt_assert(!cb || (cb && policy == SharingPolicy::NONLINEAR),
+ "Invalid sharing policy for constraint. Callback should be used with NONLINEAR sharing policy");
+ sharing_policy_ = policy;
+ dyn_constraint_cb_ = cb;
+}
+
} // namespace lmm
} // namespace kernel
} // namespace simgrid
#define SURF_MAXMIN_HPP
#include "simgrid/kernel/resource/Action.hpp"
+#include "simgrid/kernel/resource/Model.hpp"
#include "simgrid/s4u/Link.hpp"
#include "src/surf/surf_interface.hpp"
#include "xbt/asserts.h"
*/
class XBT_PUBLIC Constraint {
public:
- enum class SharingPolicy { SHARED = 1, FATPIPE = 0 };
+ enum class SharingPolicy { NONLINEAR = 2, SHARED = 1, FATPIPE = 0 };
+
Constraint() = delete;
Constraint(resource::Resource* id_value, double bound_value);
void unshare() { sharing_policy_ = SharingPolicy::FATPIPE; }
/** @brief Set how a constraint is shared */
- void set_sharing_policy(SharingPolicy policy) { sharing_policy_ = policy; }
+ void set_sharing_policy(SharingPolicy policy, const s4u::NonLinearResourceCb& cb);
/** @brief Check how a constraint is shared */
SharingPolicy get_sharing_policy() const { return sharing_policy_; }
double remaining_ = 0.0;
double usage_ = 0.0;
double bound_;
+ double dynamic_bound_; //!< dynamic bound for this constraint, defined by user's callback
// TODO MARTIN Check maximum value across resources at the end of simulation and give a warning is more than e.g. 500
int concurrency_current_ = 0; /* The current concurrency */
int concurrency_maximum_ = 0; /* The maximum number of (enabled and disabled) variables associated to the constraint
double lambda_ = 0.0;
double new_lambda_ = 0.0;
ConstraintLight* cnst_light_ = nullptr;
+ s4u::NonLinearResourceCb dyn_constraint_cb_;
private:
static int next_rank_; // To give a separate rank_ to each constraint
Sys.variable_free_all();
}
+
+TEST_CASE("kernel::lmm dynamic constraint shared systems", "[kernel-lmm-shared-single-sys]")
+{
+ auto cb = [](double bound, int flows) -> double {
+ // decrease 10 % for each extra flow sharing this resource
+ return bound - (flows - 1) * .10 * bound;
+ };
+ lmm::System Sys(false);
+ lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 10);
+ sys_cnst->set_sharing_policy(lmm::Constraint::SharingPolicy::NONLINEAR, cb);
+
+ SECTION("1 activity, 100% C")
+ {
+ /*
+ * A single variable gets all the share
+ *
+ * In details:
+ * o System: a1 * p1 * \rho1 < C
+ * o consumption_weight: a1=1
+ * o sharing_penalty: p1=1
+ *
+ * Expectations
+ * o rho1 = C (because all weights are 1)
+ */
+
+ lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
+
+ Sys.expand(sys_cnst, rho_1, 1);
+ Sys.solve();
+
+ REQUIRE(double_equals(rho_1->get_value(), 10, sg_maxmin_precision));
+ }
+
+ SECTION("2 activities, but ignore crosstraffic 100% C")
+ {
+ /*
+ * Ignore small activities (e.g. crosstraffic)
+ *
+ * In details:
+ * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < C
+ * o consumption_weight: a1=1 ; a2=0.05
+ * o sharing_penalty: p1=1 ; p2=1
+ *
+ * Expectations
+ * o rho1 = C/1.05
+ * o rho2 = C/1.05
+ * o rho1 = rho2 (because rho1 and rho2 has the same penalty)
+ */
+
+ lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
+ lmm::Variable* rho_2 = Sys.variable_new(nullptr, 1);
+
+ Sys.expand(sys_cnst, rho_1, 1);
+ Sys.expand(sys_cnst, rho_2, 0.05);
+ Sys.solve();
+
+ REQUIRE(double_equals(rho_1->get_value(), 10 / 1.05, sg_maxmin_precision));
+ REQUIRE(double_equals(rho_1->get_value(), rho_2->get_value(), sg_maxmin_precision));
+ }
+
+ SECTION("2 activities, 1 inactive 100% C")
+ {
+ /*
+ * 2 activities but 1 is inactive (sharing_penalty = 0)
+ *
+ * In details:
+ * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < C
+ * o consumption_weight: a1=1 ; a2=1
+ * o sharing_penalty: p1=1 ; p2=0
+ *
+ * Expectations
+ * o rho1 = C
+ * o rho2 = 0
+ */
+
+ lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
+ lmm::Variable* rho_2 = Sys.variable_new(nullptr, 0);
+
+ Sys.expand(sys_cnst, rho_1, 1);
+ Sys.expand(sys_cnst, rho_2, 1);
+ Sys.solve();
+
+ REQUIRE(double_equals(rho_1->get_value(), 10, sg_maxmin_precision));
+ REQUIRE(double_equals(rho_2->get_value(), 0, sg_maxmin_precision));
+ }
+
+ SECTION("2 activity, 90% C")
+ {
+ /*
+ * 2 similar variables degrades performance, but get same share
+ *
+ * In details:
+ * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < .9C
+ * o consumption_weight: a1=1 ; a2=1
+ * o sharing_penalty: p1=1 ; p2=1
+ *
+ * Expectations
+ * o rho1 = rho2
+ * o rho1 + rho2 = C (because all weights are 1)
+ */
+
+ lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
+ lmm::Variable* rho_2 = Sys.variable_new(nullptr, 1);
+
+ Sys.expand(sys_cnst, rho_1, 1);
+ Sys.expand(sys_cnst, rho_2, 1);
+ Sys.solve();
+
+ REQUIRE(double_equals(rho_1->get_value(), 4.5, sg_maxmin_precision));
+ REQUIRE(double_equals(rho_1->get_value(), 4.5, sg_maxmin_precision));
+ }
+
+ SECTION("3 activity, 80% C")
+ {
+ /*
+ * 3 similar variables degrades performance, sharing proportional to penalty
+ *
+ * In details:
+ * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 + a3 * p3 * \rho3 < .8C
+ * o consumption_weight: a1=1 ; a2=1 ; a3=1
+ * o sharing_penalty: p1=1 ; p2=3 ; p3=4
+ *
+ * Expectations
+ * o rho1 = 2*rho2 = 2*rho3
+ * 0 rho1 = 4, rho2 = 2, rho3 = 2
+ * o rho1 + rho2 + rho3 = .8C (because all weights are 1)
+ */
+
+ lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
+ lmm::Variable* rho_2 = Sys.variable_new(nullptr, 2);
+ lmm::Variable* rho_3 = Sys.variable_new(nullptr, 2);
+
+ Sys.expand(sys_cnst, rho_1, 1);
+ Sys.expand(sys_cnst, rho_2, 1);
+ Sys.expand(sys_cnst, rho_3, 1);
+ Sys.solve();
+
+ REQUIRE(double_equals(rho_1->get_value(), 4, sg_maxmin_precision));
+ REQUIRE(double_equals(rho_2->get_value(), 2, sg_maxmin_precision));
+ REQUIRE(double_equals(rho_3->get_value(), 2, sg_maxmin_precision));
+ }
+
+ Sys.variable_free_all();
+}
\ No newline at end of file
this->set_read_constraint(maxmin_system->constraint_new(this, read_bw_.peak * read_bw_.scale))
->set_write_constraint(maxmin_system->constraint_new(this, write_bw_.peak * write_bw_.scale))
->set_constraint(maxmin_system->constraint_new(this, std::max(read_bw_.peak, write_bw_.peak)));
+ apply_sharing_policy_cfg();
XBT_DEBUG("Create resource with read_bw '%f' write_bw '%f'", read_bw_.peak, write_bw_.peak);
Resource::seal();
turn_on();
}
+constexpr kernel::lmm::Constraint::SharingPolicy to_maxmin_policy(s4u::Disk::SharingPolicy policy)
+{
+ switch (policy) {
+ case s4u::Disk::SharingPolicy::NONLINEAR:
+ return kernel::lmm::Constraint::SharingPolicy::NONLINEAR;
+ case s4u::Disk::SharingPolicy::LINEAR:
+ default:
+ return kernel::lmm::Constraint::SharingPolicy::SHARED;
+ }
+}
+
+void DiskImpl::set_sharing_policy(s4u::Disk::Operation op, s4u::Disk::SharingPolicy policy,
+ const s4u::NonLinearResourceCb& cb)
+{
+ sharing_policy_[op] = policy;
+ sharing_policy_cb_[op] = cb;
+ apply_sharing_policy_cfg();
+}
+
+s4u::Disk::SharingPolicy DiskImpl::get_sharing_policy(s4u::Disk::Operation op) const
+{
+ return sharing_policy_.at(op);
+}
+
+void DiskImpl::apply_sharing_policy_cfg()
+{
+ if (get_constraint())
+ get_constraint()->set_sharing_policy(to_maxmin_policy(sharing_policy_[s4u::Disk::Operation::READWRITE]),
+ sharing_policy_cb_[s4u::Disk::Operation::READWRITE]);
+ if (constraint_read_)
+ constraint_read_->set_sharing_policy(to_maxmin_policy(sharing_policy_[s4u::Disk::Operation::READ]),
+ sharing_policy_cb_[s4u::Disk::Operation::READ]);
+ if (constraint_write_)
+ constraint_write_->set_sharing_policy(to_maxmin_policy(sharing_policy_[s4u::Disk::Operation::WRITE]),
+ sharing_policy_cb_[s4u::Disk::Operation::WRITE]);
+}
+
/**********
* Action *
**********/
s4u::Host* host_ = nullptr;
lmm::Constraint* constraint_write_ = nullptr; /* Constraint for maximum write bandwidth*/
lmm::Constraint* constraint_read_ = nullptr; /* Constraint for maximum read bandwidth*/
+ std::unordered_map<s4u::Disk::Operation, s4u::Disk::SharingPolicy> sharing_policy_ = {
+ {s4u::Disk::Operation::READ, s4u::Disk::SharingPolicy::LINEAR},
+ {s4u::Disk::Operation::WRITE, s4u::Disk::SharingPolicy::LINEAR},
+ {s4u::Disk::Operation::READWRITE, s4u::Disk::SharingPolicy::LINEAR}};
+ std::unordered_map<s4u::Disk::Operation, s4u::NonLinearResourceCb> sharing_policy_cb_ = {};
+
+ void apply_sharing_policy_cfg();
protected:
~DiskImpl() override = default; // Disallow direct deletion. Call destroy() instead.
DiskImpl* set_read_bandwidth_profile(profile::Profile* profile);
DiskImpl* set_write_bandwidth_profile(profile::Profile* profile);
+ void set_sharing_policy(s4u::Disk::Operation op, s4u::Disk::SharingPolicy policy, const s4u::NonLinearResourceCb& cb);
+ s4u::Disk::SharingPolicy get_sharing_policy(s4u::Disk::Operation op) const;
+
/** @brief Check if the Disk is used (if an action currently uses its resources) */
bool is_used() const override;
void turn_on() override;
return IoPtr(io_init(size, Io::OpType::WRITE))->vetoable_start()->wait()->get_performed_ioops();
}
+Disk* Disk::set_sharing_policy(Disk::Operation op, Disk::SharingPolicy policy, const NonLinearResourceCb& cb)
+{
+ kernel::actor::simcall([this, op, policy, &cb] { pimpl_->set_sharing_policy(op, policy, cb); });
+ return this;
+}
+
+Disk::SharingPolicy Disk::get_sharing_policy(Operation op) const
+{
+ return this->pimpl_->get_sharing_policy(op);
+}
+
Disk* Disk::seal()
{
kernel::actor::simcall([this]{ pimpl_->seal(); });
lmm::Constraint::SharingPolicy ct_policy = lmm::Constraint::SharingPolicy::SHARED;
if (policy == s4u::Link::SharingPolicy::FATPIPE)
ct_policy = lmm::Constraint::SharingPolicy::FATPIPE;
- get_constraint()->set_sharing_policy(ct_policy);
+ get_constraint()->set_sharing_policy(ct_policy, {});
sharing_policy_ = policy;
}
s4u::Link::SharingPolicy LinkImpl::get_sharing_policy() const