artdaq  v3_12_02
PreferSameHost_policy.cc
1 #include "artdaq/DAQdata/Globals.hh"
2 #define TRACE_NAME (app_name + "_PreferSameHost_policy").c_str()
3 #include "TRACE/tracemf.h"
4 
5 #include "artdaq/DAQdata/HostMap.hh"
6 #include "artdaq/RoutingPolicies/PolicyMacros.hh"
7 #include "artdaq/RoutingPolicies/RoutingManagerPolicy.hh"
8 
9 #include "fhiclcpp/ParameterSet.h"
10 
11 #include <map>
12 
13 namespace artdaq {
18 {
19 public:
27  explicit PreferSameHostPolicy(const fhicl::ParameterSet& ps)
29  , minimum_participants_(ps.get<int>("minimum_participants", 0))
30  , host_map_(MakeHostMap(ps))
31  {
32  }
33 
37  ~PreferSameHostPolicy() override = default;
38 
47  void CreateRoutingTable(detail::RoutingPacket& output) override;
54  detail::RoutingPacketEntry CreateRouteForSequenceID(artdaq::Fragment::sequence_id_t seq, int requesting_rank) override;
55 
56 private:
59  PreferSameHostPolicy& operator=(PreferSameHostPolicy const&) = delete;
60  PreferSameHostPolicy& operator=(PreferSameHostPolicy&&) = delete;
61 
62  std::map<int, int> sortTokens_();
63  void restoreUnusedTokens_(std::map<int, int> const& sorted_tokens_);
64  int calculateMinimum_();
65 
66  int minimum_participants_;
67  hostMap_t host_map_;
68 };
69 
71 {
72  TLOG(TLVL_DEBUG + 35) << "PreferSameHostPolicy::GetCurrentTable token list size is " << tokens_.size();
73  auto table = sortTokens_();
74  TLOG(TLVL_DEBUG + 36) << "PreferSameHostPolicy::GetCurrentTable table size is " << table.size();
75 
76  int minimum = calculateMinimum_();
77  bool endCondition = table.size() < static_cast<size_t>(minimum);
78  TLOG(TLVL_DEBUG + 37) << "PreferSameHostPolicy::GetCurrentTable initial endCondition is " << endCondition << ", minimum is " << minimum;
79 
80  while (!endCondition)
81  {
82  for (auto it = table.begin(); it != table.end();)
83  {
84  TLOG(TLVL_DEBUG + 38) << "PreferSameHostPolicy::GetCurrentTable assigning sequenceID " << next_sequence_id_ << " to rank " << it->first;
85  output.emplace_back(detail::RoutingPacketEntry(next_sequence_id_++, it->first));
86  table[it->first]--;
87 
88  if (table[it->first] <= 0)
89  {
90  it = table.erase(it);
91  }
92  else
93  {
94  ++it;
95  }
96  }
97  endCondition = table.size() < static_cast<size_t>(minimum);
98  }
99 
100  restoreUnusedTokens_(table);
101  TLOG(TLVL_DEBUG + 36) << "PreferSameHostPolicy::GetCurrentTable " << tokens_.size() << " unused tokens will be saved for later";
102 
103  TLOG(TLVL_DEBUG + 35) << "PreferSameHostPolicy::GetCurrentTable return with table size " << output.size();
104 }
105 detail::RoutingPacketEntry PreferSameHostPolicy::CreateRouteForSequenceID(artdaq::Fragment::sequence_id_t seq, int requesting_rank)
106 {
108  auto table = sortTokens_();
109 
110  // Trivial case: no tokens
111  if (table.empty()) return output;
112 
113  if (host_map_.count(requesting_rank) == 0)
114  {
115  TLOG(TLVL_WARNING) << "Received Routing Request from rank " << requesting_rank << ", which is not in my Host Map!";
116  }
117  auto host = host_map_[requesting_rank];
118 
119  // First try to find a match
120  std::set<int> matching_ranks_;
121  int max_rank = -1;
122  int max_rank_tokens = 0;
123  for (auto& entry : table)
124  {
125  if (entry.second == 0) continue;
126  if (host_map_.count(entry.first) == 0)
127  {
128  TLOG(TLVL_WARNING) << "Receiver rank " << entry.first << " is not in the host map! Is this policy configured correctly?!";
129  }
130  else
131  {
132  if (host_map_[entry.first] == host)
133  {
134  matching_ranks_.insert(entry.first);
135  }
136  }
137  if (entry.second > max_rank_tokens)
138  {
139  max_rank = entry.first;
140  max_rank_tokens = entry.second;
141  }
142  }
143 
144  if (matching_ranks_.size() == 0)
145  {
146  output = detail::RoutingPacketEntry(seq, max_rank);
147  table[max_rank]--;
148  }
149  else if (matching_ranks_.size() == 1)
150  {
151  output = detail::RoutingPacketEntry(seq, *matching_ranks_.begin());
152  table[*matching_ranks_.begin()]--;
153  }
154  else
155  {
156  // Find the most tokens in matching_ranks_
157  int max = 0;
158  int max_rank = -1;
159  for (auto& rank : matching_ranks_)
160  {
161  if (table[rank] > max)
162  {
163  max = table[rank];
164  max_rank = rank;
165  }
166  }
167  output = detail::RoutingPacketEntry(seq, max_rank);
168  table[max_rank]--;
169  }
170 
171  restoreUnusedTokens_(table);
172  return output;
173 }
174 std::map<int, int> PreferSameHostPolicy::sortTokens_()
175 {
176  auto output = std::map<int, int>();
177  for (auto token : tokens_)
178  {
179  output[token]++;
180  }
181  tokens_.clear();
182  return output;
183 }
184 
185 void PreferSameHostPolicy::restoreUnusedTokens_(std::map<int, int> const& sorted_tokens)
186 {
187  for (auto r : sorted_tokens)
188  {
189  for (auto i = 0; i < r.second; ++i)
190  {
191  tokens_.push_back(r.first);
192  }
193  }
194 }
195 
196 int PreferSameHostPolicy::calculateMinimum_()
197 {
198  // If 0 or negative, add minimum_participants_ to GetRecevierCount to ensure that it's correct
199  // 02-Apr-2019, KAB: changed the declared type of "minimum" from 'auto' to 'int' to avoid the
200  // situation in which the compiler chooses a type of 'unsigned int', the minimum_participants_ is
201  // a negative number that is larger (in absolute value) to the receiver count, and "minimum"
202  // ends up with a large positive value.
203  int minimum = minimum_participants_ > 0 ? minimum_participants_ : GetReceiverCount() + minimum_participants_;
204  if (minimum < 1)
205  {
206  minimum = 1; // Can't go below 1
207  }
208  return minimum;
209 }
210 
211 } // namespace artdaq
212 
213 DEFINE_ARTDAQ_ROUTING_POLICY(artdaq::PreferSameHostPolicy)
A row of the Routing Table.
PreferSameHostPolicy(const fhicl::ParameterSet &ps)
PreferSameHostPolicy Constructor.
Fragment::sequence_id_t next_sequence_id_
The next sequence ID to be assigned.
The interface through which RoutingManagerCore obtains Routing Tables using received Routing Tokens...
detail::RoutingPacketEntry CreateRouteForSequenceID(artdaq::Fragment::sequence_id_t seq, int requesting_rank) override
Get an artdaq::detail::RoutingPacketEntry for a given sequence ID and rank. Used by RequestBasedEvent...
void CreateRoutingTable(detail::RoutingPacket &output) override
Generate a set of Routing Tables using received tokens.
~PreferSameHostPolicy() override=default
Default virtual Destructor.
std::vector< RoutingPacketEntry > RoutingPacket
A RoutingPacket is simply a vector of RoutingPacketEntry objects. It is not suitable for network tran...
A RoutingManagerPolicy which tries to keep data on the same host. For EventBuilding mode...
size_t GetReceiverCount() const
Get the number of configured receivers.
std::deque< int > tokens_
The list of tokens which are available for use.
std::map< int, std::string > hostMap_t
The host_map is a map associating ranks with artdaq::DestinationInfo objects.
Definition: HostMap.hh:42
hostMap_t MakeHostMap(fhicl::ParameterSet const &pset, hostMap_t map=hostMap_t())
Make a hostMap_t from a HostMap::Config ParameterSet
Definition: HostMap.hh:68