artdaq  v3_12_02
RoundRobin_policy.cc
1 #include "artdaq/DAQdata/Globals.hh"
2 #define TRACE_NAME (app_name + "_RoundRobin_policy").c_str()
3 #include "TRACE/tracemf.h"
4 
5 #include "artdaq/RoutingPolicies/PolicyMacros.hh"
6 #include "artdaq/RoutingPolicies/RoutingManagerPolicy.hh"
7 
8 #include "fhiclcpp/ParameterSet.h"
9 
10 namespace artdaq {
16 {
17 public:
25  explicit RoundRobinPolicy(const fhicl::ParameterSet& ps)
27  , minimum_participants_(ps.get<int>("minimum_participants", 0))
28  {
29  }
30 
34  ~RoundRobinPolicy() override = default;
35 
44  void CreateRoutingTable(detail::RoutingPacket& output) override;
51  detail::RoutingPacketEntry CreateRouteForSequenceID(artdaq::Fragment::sequence_id_t seq, int requesting_rank) override;
52 
53 private:
54  RoundRobinPolicy(RoundRobinPolicy const&) = delete;
56  RoundRobinPolicy& operator=(RoundRobinPolicy const&) = delete;
57  RoundRobinPolicy& operator=(RoundRobinPolicy&&) = delete;
58 
59  std::map<int, int> sortTokens_();
60  void restoreUnusedTokens_(std::map<int, int> const& sorted_tokens_);
61  int calculateMinimum_();
62 
63  int minimum_participants_;
64  std::set<int> receivers_in_current_round_;
65 };
66 
68 {
69  TLOG(TLVL_DEBUG + 35) << "RoundRobinPolicy::GetCurrentTable token list size is " << tokens_.size();
70  auto table = sortTokens_();
71  TLOG(TLVL_DEBUG + 36) << "RoundRobinPolicy::GetCurrentTable table size is " << table.size();
72 
73  int minimum = calculateMinimum_();
74  bool endCondition = table.size() < static_cast<size_t>(minimum);
75  TLOG(TLVL_DEBUG + 37) << "RoundRobinPolicy::GetCurrentTable initial endCondition is " << endCondition << ", minimum is " << minimum;
76 
77  while (!endCondition)
78  {
79  for (auto it = table.begin(); it != table.end();)
80  {
81  TLOG(TLVL_DEBUG + 38) << "RoundRobinPolicy::GetCurrentTable assigning sequenceID " << next_sequence_id_ << " to rank " << it->first;
82  output.emplace_back(detail::RoutingPacketEntry(next_sequence_id_++, it->first));
83  table[it->first]--;
84 
85  if (table[it->first] <= 0)
86  {
87  it = table.erase(it);
88  }
89  else
90  {
91  ++it;
92  }
93  }
94  endCondition = table.size() < static_cast<size_t>(minimum);
95  }
96 
97  restoreUnusedTokens_(table);
98  TLOG(TLVL_DEBUG + 36) << "RoundRobinPolicy::GetCurrentTable " << tokens_.size() << " unused tokens will be saved for later";
99 
100  TLOG(TLVL_DEBUG + 35) << "RoundRobinPolicy::GetCurrentTable return with table size " << output.size();
101 }
103 {
105 
106  // Trivial case: We've already started a round
107  if (!receivers_in_current_round_.empty())
108  {
109  output = detail::RoutingPacketEntry(seq, *receivers_in_current_round_.begin());
110  receivers_in_current_round_.erase(receivers_in_current_round_.begin());
111  return output;
112  }
113 
114  // We need to set up the next round...
115  auto table = sortTokens_();
116 
117  // Can't route anything until a full "turn" is available
118  int minimum = calculateMinimum_();
119  if (table.size() < static_cast<size_t>(minimum))
120  {
121  TLOG(TLVL_WARNING) << "Do not have tokens from a minimum set of receivers to start a round";
122  }
123  else
124  {
125  for (auto& entry : table)
126  {
127  receivers_in_current_round_.insert(entry.first);
128  entry.second--;
129  }
130  output = detail::RoutingPacketEntry(seq, *receivers_in_current_round_.begin());
131  receivers_in_current_round_.erase(receivers_in_current_round_.begin());
132  }
133 
134  restoreUnusedTokens_(table);
135  return output;
136 }
137 std::map<int, int> RoundRobinPolicy::sortTokens_()
138 {
139  auto output = std::map<int, int>();
140  for (auto token : tokens_)
141  {
142  output[token]++;
143  }
144  tokens_.clear();
145  return output;
146 }
147 
148 void RoundRobinPolicy::restoreUnusedTokens_(std::map<int, int> const& sorted_tokens)
149 {
150  for (auto r : sorted_tokens)
151  {
152  for (auto i = 0; i < r.second; ++i)
153  {
154  tokens_.push_back(r.first);
155  }
156  }
157 }
158 
159 int RoundRobinPolicy::calculateMinimum_()
160 {
161  // If 0 or negative, add minimum_participants_ to GetRecevierCount to ensure that it's correct
162  // 02-Apr-2019, KAB: changed the declared type of "minimum" from 'auto' to 'int' to avoid the
163  // situation in which the compiler chooses a type of 'unsigned int', the minimum_participants_ is
164  // a negative number that is larger (in absolute value) to the receiver count, and "minimum"
165  // ends up with a large positive value.
166  int minimum = minimum_participants_ > 0 ? minimum_participants_ : GetReceiverCount() + minimum_participants_;
167  if (minimum < 1)
168  {
169  minimum = 1; // Can't go below 1
170  }
171  return minimum;
172 }
173 
174 } // namespace artdaq
175 
176 DEFINE_ARTDAQ_ROUTING_POLICY(artdaq::RoundRobinPolicy)
~RoundRobinPolicy() override=default
Default virtual Destructor.
A row of the Routing Table.
A RoutingManagerPolicy which evenly distributes Sequence IDs to all receivers. If an uneven number of...
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...
void CreateRoutingTable(detail::RoutingPacket &output) override
Add entries to the given RoutingPacket using currently-held tokens.
std::vector< RoutingPacketEntry > RoutingPacket
A RoutingPacket is simply a vector of RoutingPacketEntry objects. It is not suitable for network tran...
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...
size_t GetReceiverCount() const
Get the number of configured receivers.
std::deque< int > tokens_
The list of tokens which are available for use.
RoundRobinPolicy(const fhicl::ParameterSet &ps)
RoundRobinPolicy Constructor.