Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
18c28de9c7952553542f92f7be91301cce22bb7f
[simgrid.git] / src / smpi / plugins / load_balancer / LoadBalancer.cpp
1 /* Copyright (c) 2006-2018. 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 #include <algorithm>
7 #include <queue>
8 #include <simgrid/plugins/load.h>
9 #include <simgrid/s4u.hpp>
10 #include <simgrid/smpi/loadbalancer/load_balancer.hpp>
11
12 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(plugin_load_balancer_impl, smpi, "Logging specific to the SMPI load balancing plugin");
13
14 namespace simgrid {
15 namespace plugin {
16 namespace loadbalancer {
17
18 static std::map<simgrid::s4u::Host*, double> additional_load;
19
20 static bool compare_by_avg_load(simgrid::s4u::Host* a, simgrid::s4u::Host* b)
21 {
22   return sg_host_get_avg_load(a) + additional_load[a] > sg_host_get_avg_load(b) + additional_load[b];
23 }
24
25 LoadBalancer::LoadBalancer()
26 {
27 }
28
29 LoadBalancer::~LoadBalancer()
30 {
31 }
32
33 void LoadBalancer::run()
34 {
35   simgrid::s4u::Engine* engine                     = simgrid::s4u::Engine::get_instance();
36   std::vector<simgrid::s4u::Host*> available_hosts = engine->get_filtered_hosts([](simgrid::s4u::Host* host) {
37     return not host->is_off();
38   });
39   xbt_assert(available_hosts.size() > 0, "No hosts available; are they all switched off?");
40   for (auto& host : available_hosts) {
41     additional_load[host] = 0;
42   }
43
44   // TODO: Account for daemon background load (-> use especially the availability file)
45
46   std::vector<simgrid::s4u::ActorPtr> all_actors =
47       engine->get_filtered_actors([](simgrid::s4u::ActorPtr actor) { return not actor->is_daemon(); });
48   for (auto& actor : all_actors) {
49     new_mapping[actor] = actor->get_host();
50   }
51   // Sort the actors, from highest to lowest load; we then just iterate over these actors
52   std::sort(all_actors.begin(), all_actors.end(), [this](simgrid::s4u::ActorPtr a, simgrid::s4u::ActorPtr b) {
53     return actor_computation[a->get_pid()] < actor_computation[b->get_pid()];
54   });
55   for (auto& actor : all_actors) {
56     XBT_INFO("Order: %li", actor->get_pid());
57   }
58   // Sort the hosts. Use a heap datastructure, because we re-insert a host
59   // that got an actor assigned in a possibly different position
60   // This is equivalent to a std::greater<Host*> implementation that uses the load to compare the two objects.
61   // --> The least loaded host will be in the first position
62   std::priority_queue</*datatype*/ simgrid::s4u::Host*, /*container*/ std::vector<simgrid::s4u::Host*>,
63                       /*comparison function*/ std::function<bool(simgrid::s4u::Host*, simgrid::s4u::Host*)>>
64       usable_hosts(compare_by_avg_load, std::move(available_hosts));
65
66   for (auto& actor : all_actors) {
67     simgrid::s4u::Host* target_host = usable_hosts.top(); // This is the host with the lowest load
68
69     if (target_host != actor->get_host() && actor->get_host()->get_actor_count() > 1) {
70       usable_hosts.pop();
71
72       assign(actor, target_host); // This updates also the load
73       usable_hosts.push(target_host);
74     }
75   }
76 }
77
78 void LoadBalancer::assign(simgrid::s4u::ActorPtr actor, simgrid::s4u::Host* host)
79 {
80   // If an actor gets re-assigned twice, we don't want to subtract
81   // the load from the same host twice so we have to use the old value of new_mapping here
82   additional_load[new_mapping[actor]] -= 1; // actor->load();
83   additional_load[host] += 1;               // actor->load();
84   new_mapping[actor] = host;
85
86   XBT_INFO("Assigning actor %li to host %s", actor->get_pid(), host->get_cname());
87 }
88
89 simgrid::s4u::Host* LoadBalancer::get_mapping()
90 {
91   return new_mapping[simgrid::s4u::Actor::self()];
92 }
93
94 void LoadBalancer::record_actor_computation(simgrid::s4u::ActorPtr actor, double load)
95 {
96   actor_computation[actor->get_pid()] += load;
97 }
98 }
99 }
100 }