EMANE  1.2.1
queuemetricmanager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013,2016 - Adjacent Link LLC, Bridgewater, New Jersey
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * * Neither the name of Adjacent Link LLC nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <math.h>
34 #include <map>
35 
36 #include "emane/types.h"
38 #include "emane/constants.h"
39 
40 #include <mutex>
41 
42 class EMANE::QueueMetricManager::Implementation
43  {
44  public:
45  Implementation(EMANE::NEMId id) :
46  id_{id}
47  { }
48 
49 
50  ~Implementation()
51  { }
52 
53  void updateQueueMetric(std::uint16_t u16QueueId,
54  std::uint32_t u32MaxQueueSize,
55  std::uint32_t u32CurrentQueueDepth,
56  std::uint32_t u32NumDiscards,
57  const EMANE::Microseconds & delayMicroseconds)
58  {
59  std::lock_guard<std::mutex> m(mutex_);
60 
61  QueueData & rData = getQueueData_i(u16QueueId);
62 
63  // bump num samples
64  rData.u32NumSamples_ += 1;
65 
66  // bump the delay sum
67  rData.sumDelayMicroseconds_ += delayMicroseconds;
68 
69  // check max size change
70  if(rData.u32MaxQueueSize_ != u32MaxQueueSize)
71  {
72  // set new max size
73  rData.u32MaxQueueSize_ = u32MaxQueueSize;
74 
75  // reset high water mark
76  rData.u32QueueHighWaterMark_ = 0;
77  }
78 
79  // check queue depth high water
80  if(rData.u32QueueHighWaterMark_ < u32CurrentQueueDepth)
81  {
82  rData.u32QueueHighWaterMark_ = u32CurrentQueueDepth;
83  }
84 
85  // check discards high water
86  if(rData.u32NumDiscardsHighWaterMark_ < u32NumDiscards)
87  {
88  rData.u32NumDiscardsHighWaterMark_ = u32NumDiscards;
89  }
90  }
91 
92 
94  {
95  std::lock_guard<std::mutex> m(mutex_);
96 
98 
99  for(auto & iter : queueDataMap_)
100  {
101  // get avg delay time
102  const EMANE::Microseconds avgDelayMicroseconds{getAvg_i(iter.second.sumDelayMicroseconds_,
103  iter.second.u32NumSamples_)};
104 
105  EMANE::Controls::R2RIQueueMetric metric{iter.first, // queue id
106  iter.second.u32MaxQueueSize_, // queue max size
107  iter.second.u32QueueHighWaterMark_, // queue current depth high water
108  iter.second.u32NumDiscardsHighWaterMark_, // num discards high water
109  avgDelayMicroseconds}; // avg delay
110 
111  metrics.push_back(metric);
112 
113  // reset data
114  iter.second.reset();
115  }
116 
117  return metrics;
118  }
119 
120 
121  bool addQueueMetric(std::uint16_t queueId, std::uint32_t u32MaxQueueSize)
122  {
123  std::lock_guard<std::mutex> m(mutex_);
124 
125  return queueDataMap_.insert(std::make_pair(queueId, QueueData(u32MaxQueueSize))).second;
126  }
127 
128 
129  bool removeQueueMetric(std::uint16_t queueId)
130  {
131  std::lock_guard<std::mutex> m(mutex_);
132 
133  auto iter = queueDataMap_.find(queueId);
134 
135  if(iter != queueDataMap_.end())
136  {
137  // remove entry
138  queueDataMap_.erase(iter);
139 
140  return true;
141  }
142  else
143  {
144  return false;
145  }
146  }
147 
148  private:
149  struct QueueData {
150  // metrics observed over the report interval
151  std::uint32_t u32MaxQueueSize_; // queue max size
152  std::uint32_t u32QueueHighWaterMark_; // queue depth high water
153  std::uint32_t u32NumSamples_; // num samples
154  std::uint32_t u32NumDiscardsHighWaterMark_; // num discards high water
155  EMANE::Microseconds sumDelayMicroseconds_; // total delay
156 
157  QueueData() :
158  u32MaxQueueSize_{},
159  u32QueueHighWaterMark_{},
160  u32NumSamples_{},
161  u32NumDiscardsHighWaterMark_{},
162  sumDelayMicroseconds_{}
163  { }
164 
165  QueueData(std::uint32_t u32MaxSize) :
166  u32MaxQueueSize_(u32MaxSize),
167  u32QueueHighWaterMark_{},
168  u32NumSamples_{},
169  u32NumDiscardsHighWaterMark_{},
170  sumDelayMicroseconds_{}
171  { }
172 
173  void reset()
174  {
175  u32NumDiscardsHighWaterMark_ = 0;
176 
177  sumDelayMicroseconds_ = EMANE::Microseconds::zero();
178 
179  u32NumSamples_ = 0;
180 
181  u32QueueHighWaterMark_ = 0;
182  }
183  };
184 
185  using QueueDataMap = std::map<std::uint16_t, QueueData>;
186 
187  EMANE::NEMId id_;
188 
189  QueueDataMap queueDataMap_;
190 
191  std::mutex mutex_;
192 
193 
194  QueueData & getQueueData_i(std::uint16_t queueId)
195  {
196  auto iter = queueDataMap_.find(queueId);
197 
198  if(iter == queueDataMap_.end())
199  {
200  // add new queue
201  iter = queueDataMap_.insert(std::make_pair(queueId, QueueData())).first;
202  }
203 
204  return iter->second;
205  }
206 
207 
208  EMANE::Microseconds getAvg_i(const EMANE::Microseconds & delayMicroseconds, size_t samples)
209  {
210  if(samples > 1)
211  {
212  DoubleSeconds doubleSeconds{delayMicroseconds.count() / (USEC_PER_SEC_F * samples)};
213 
214  return std::chrono::duration_cast<EMANE::Microseconds>(doubleSeconds);
215  }
216  else if(samples == 1)
217  {
218  return delayMicroseconds;
219  }
220  else
221  {
222  return EMANE::Microseconds::zero();
223  }
224  }
225  };
226 
227 
229  pImpl_{new Implementation{id}}
230 { }
231 
232 
234 { }
235 
236 
239 {
240  return pImpl_->getQueueMetrics();
241 }
242 
243 
244 void
246  std::uint32_t u32MaxQueueSize,
247  std::uint32_t u32CurrentQueueDepth,
248  std::uint32_t u32NumDiscards,
249  const Microseconds & delayMicroseconds)
250 {
251  pImpl_->updateQueueMetric(u16QueueId,
252  u32MaxQueueSize,
253  u32CurrentQueueDepth,
254  u32NumDiscards,
255  delayMicroseconds);
256 }
257 
258 
259 bool
260 EMANE::QueueMetricManager::addQueueMetric(std::uint16_t u16QueueId, std::uint32_t u32MaxQueueSize)
261 {
262  return pImpl_->addQueueMetric(u16QueueId, u32MaxQueueSize);
263 }
264 
265 
266 bool
268 {
269  return pImpl_->removeQueueMetric(u16QueueId);
270 }
bool removeQueueMetric(std::uint16_t u16QueueId)
Controls::R2RIQueueMetrics getQueueMetrics()
std::chrono::microseconds Microseconds
Definition: types.h:45
std::chrono::duration< double > DoubleSeconds
Definition: types.h:47
std::uint16_t NEMId
Definition: types.h:52
void updateQueueMetric(std::uint16_t u16QueueId, std::uint32_t u32QueueSize, std::uint32_t u32QueueDepth, std::uint32_t u32NumDiscards, const Microseconds &queueDelay)
const float USEC_PER_SEC_F
Definition: constants.h:61
std::list< R2RIQueueMetric > R2RIQueueMetrics
R2RI queue metrics are used in conjunction with the R2RIQueueMetricControlMessage to inform an NEM&#39;s ...
bool addQueueMetric(std::uint16_t u16QueueId, std::uint32_t u32QueueSize)