1 /* Copyright (c) 2019-2022. 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 #include "src/include/catch.hpp"
7 #include "src/kernel/lmm/bmf.hpp"
8 #include "src/surf/surf_interface.hpp"
11 namespace lmm = simgrid::kernel::lmm;
13 TEST_CASE("kernel::bmf Basic tests", "[kernel-bmf-basic]")
15 lmm::BmfSystem Sys(false);
16 xbt_log_control_set("ker_bmf.thres:debug");
18 SECTION("Single flow")
21 * A single variable using a single resource
24 * o System: a1 * p1 * \rho1 < C
25 * o consumption_weight: a1=1
26 * o sharing_penalty: p1=1
32 lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 3);
33 lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
35 Sys.expand(sys_cnst, rho_1, 1);
38 REQUIRE(double_equals(rho_1->get_value(), 3, sg_maxmin_precision));
44 * Two flows sharing a single resource
47 * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < C
48 * o consumption_weight: a1=1 ; a2=10
49 * o sharing_penalty: p1=1 ; p2=1
56 lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 3);
57 lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
58 lmm::Variable* rho_2 = Sys.variable_new(nullptr, 1);
60 Sys.expand(sys_cnst, rho_1, 1);
61 Sys.expand(sys_cnst, rho_2, 10);
64 REQUIRE(double_equals(rho_1->get_value(), 3.0 / 2.0, sg_maxmin_precision));
65 REQUIRE(double_equals(rho_2->get_value(), (3.0 / 2.0) / 10.0, sg_maxmin_precision));
68 SECTION("Disable variable doesn't count")
71 * Two flows sharing a single resource, but only disabled
74 * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < C
75 * o consumption_weight: a1=1 ; a2=10
76 * o sharing_penalty: p1=1 ; p2=0
82 lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 3);
83 lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
84 lmm::Variable* rho_2 = Sys.variable_new(nullptr, 0);
86 Sys.expand(sys_cnst, rho_1, 1);
87 Sys.expand(sys_cnst, rho_2, 10);
90 REQUIRE(double_equals(rho_1->get_value(), 3.0, sg_maxmin_precision));
91 REQUIRE(double_equals(rho_2->get_value(), 0.0, sg_maxmin_precision));
94 SECTION("No consumption variable")
97 * An empty variable, no consumption, just assure it receives something
99 * o System: a1 * p1 * \rho1 < C
100 * o consumption_weight: a1=0
101 * o sharing_penalty: p1=1
107 lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 3);
108 lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
109 lmm::Variable* rho_2 = Sys.variable_new(nullptr, 0);
111 Sys.expand(sys_cnst, rho_1, 1);
112 Sys.expand(sys_cnst, rho_2, 10);
115 REQUIRE(double_positive(rho_1->get_value(), sg_maxmin_precision));
118 Sys.variable_free_all();
121 TEST_CASE("kernel::bmf Advanced tests", "[kernel-bmf-advanced]")
123 lmm::BmfSystem Sys(false);
124 xbt_log_control_set("ker_bmf.thres:debug");
126 SECTION("2 flows, 2 resources")
129 * Two flows sharing 2 resources with opposite requirements
132 * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < C1
133 * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < C2
135 * o consumption_weight: a11=1, a12=10, a21=10, a22=1
136 * o sharing_penalty: p1=1, p2=1
139 * o rho1 = rho2 = C/11
142 * [1 10] * [rho1 rho2] = [1]
146 lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 1);
147 lmm::Constraint* sys_cnst2 = Sys.constraint_new(nullptr, 1);
148 lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1, -1, 2);
149 lmm::Variable* rho_2 = Sys.variable_new(nullptr, 1, -1, 2);
151 Sys.expand(sys_cnst, rho_1, 1);
152 Sys.expand(sys_cnst2, rho_1, 10);
153 Sys.expand(sys_cnst, rho_2, 10);
154 Sys.expand(sys_cnst2, rho_2, 1);
157 REQUIRE(double_equals(rho_1->get_value(), 1.0 / 11.0, sg_maxmin_precision));
158 REQUIRE(double_equals(rho_2->get_value(), 1.0 / 11.0, sg_maxmin_precision));
161 SECTION("BMF paper example")
164 * 3 flows sharing 3 resources
167 * [1 1 1/2] * [rho1 rho2 rho3] = [1]
171 * Expectations (several possible BMF allocations, our algorithm return this)
172 * o rho1 = rho2 = rho3 = 2/5
175 lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 1);
176 lmm::Constraint* sys_cnst2 = Sys.constraint_new(nullptr, 1);
177 lmm::Constraint* sys_cnst3 = Sys.constraint_new(nullptr, 1);
178 lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1, -1, 3);
179 lmm::Variable* rho_2 = Sys.variable_new(nullptr, 1, -1, 3);
180 lmm::Variable* rho_3 = Sys.variable_new(nullptr, 1, -1, 3);
182 Sys.expand(sys_cnst3, rho_1, 1.0); // put this expand first to force a singular A' matrix
183 Sys.expand(sys_cnst, rho_1, 1.0);
184 Sys.expand(sys_cnst2, rho_1, 1.0);
185 Sys.expand(sys_cnst, rho_2, 1.0);
186 Sys.expand(sys_cnst2, rho_2, 1.0 / 2.0);
187 Sys.expand(sys_cnst3, rho_2, 3.0 / 4.0);
188 Sys.expand(sys_cnst, rho_3, 1.0 / 2.0);
189 Sys.expand(sys_cnst2, rho_3, 1.0);
190 Sys.expand(sys_cnst3, rho_3, 3.0 / 4.0);
193 REQUIRE(double_equals(rho_1->get_value(), 1.0 / 3.0, sg_maxmin_precision));
194 REQUIRE(double_equals(rho_2->get_value(), 4.0 / 9.0, sg_maxmin_precision));
195 REQUIRE(double_equals(rho_3->get_value(), 4.0 / 9.0, sg_maxmin_precision));
198 Sys.variable_free_all();
201 TEST_CASE("kernel::bmf Subflows", "[kernel-bmf-subflow]")
203 lmm::BmfSystem Sys(false);
204 xbt_log_control_set("ker_bmf.thres:debug");
206 SECTION("2 subflows and 1 resource")
209 * 2 identical flows composed of 2 subflows
211 * They must receive the same share and use same amount of resources
214 * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < C
215 * o consumption_weight: a11=5, a12=7, a2=7, a2=5
216 * o sharing_penalty: p1=1, p2=1
219 * o rho1 = rho2 = (C/2)/12
222 * [12 12] * [rho1 rho2] = [1]
226 lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 5);
227 lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
228 lmm::Variable* rho_2 = Sys.variable_new(nullptr, 1);
230 Sys.expand_add(sys_cnst, rho_1, 5);
231 Sys.expand_add(sys_cnst, rho_1, 7);
232 Sys.expand_add(sys_cnst, rho_2, 7);
233 Sys.expand_add(sys_cnst, rho_2, 5);
236 REQUIRE(double_equals(rho_1->get_value(), 5.0 / 24.0, sg_maxmin_precision));
237 REQUIRE(double_equals(rho_2->get_value(), 5.0 / 24.0, sg_maxmin_precision));
240 SECTION("1 subflows, 1 flow and 1 resource")
243 * 2 flows, 1 resource
244 * 1 flow composed of 2 subflows
246 * Same share/rho, but subflow uses 50% more resources since it has a second connection/subflow
249 * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < C
250 * o consumption_weight: a11=10, a12=5 a2=10
251 * o sharing_penalty: p1=1, p2=1
258 * [15 10] * [rho1 rho2] = [1]
262 lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 5);
263 lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1);
264 lmm::Variable* rho_2 = Sys.variable_new(nullptr, 1);
266 Sys.expand_add(sys_cnst, rho_1, 10);
267 Sys.expand_add(sys_cnst, rho_1, 5);
268 Sys.expand(sys_cnst, rho_2, 10);
271 REQUIRE(double_equals(rho_1->get_value(), (5.0 / 25.0), sg_maxmin_precision));
272 REQUIRE(double_equals(rho_2->get_value(), (5.0 / 25.0), sg_maxmin_precision));
273 REQUIRE(double_equals(15 * rho_1->get_value(), 10 * rho_2->get_value() * 3 / 2, sg_maxmin_precision));
276 SECTION("1 subflows using 2 resources: different max for each resource")
279 * Test condition that we may have different max for different resources
282 * o System: a1 * p1 * \rho1 + a2 * p2 * \rho2 < C
283 * o consumption_weight: a11=1, a12=1, a2=1
284 * o consumption_weight: a21=1/2, a12=1/2 a2=3/2
285 * o sharing_penalty: p1=1, p2=1
292 * [2 1 ] * [rho1 rho2] = [1]
296 lmm::Constraint* sys_cnst = Sys.constraint_new(nullptr, 1);
297 lmm::Constraint* sys_cnst2 = Sys.constraint_new(nullptr, 1);
298 lmm::Variable* rho_1 = Sys.variable_new(nullptr, 1, -1, 2);
299 lmm::Variable* rho_2 = Sys.variable_new(nullptr, 1, -1, 2);
301 Sys.expand_add(sys_cnst, rho_1, 1.0);
302 Sys.expand_add(sys_cnst, rho_1, 1.0);
303 Sys.expand(sys_cnst, rho_2, 1);
304 Sys.expand_add(sys_cnst2, rho_1, 1.0 / 2.0);
305 Sys.expand_add(sys_cnst2, rho_1, 1.0 / 2.0);
306 Sys.expand(sys_cnst2, rho_2, 3.0 / 2.0);
309 REQUIRE(double_equals(rho_1->get_value(), (1.0 / 3.0), sg_maxmin_precision));
310 REQUIRE(double_equals(rho_2->get_value(), (1.0 / 3.0), sg_maxmin_precision));
313 Sys.variable_free_all();