artdaq_pcp_mmv_plugin  v1_00_05a
pcpmmv_metric.cc
1 // PCPMMV_metric.cc: PCPMMV Metric Plugin
2 // Author: Eric Flumerfelt
3 // Last Modified: 3/22/2019
4 //
5 // An implementation of the MetricPlugin interface for PCPMMV
6 
7 #ifndef __PCPMMV_METRIC__
8 #define __PCPMMV_METRIC__ 1
9 
10 #define TRACE_NAME "PCPMMVMetric"
11 #include "tracemf.h"
12 
13 #include "artdaq-utilities/Plugins/MetricMacros.hh"
14 #include "fhiclcpp/fwd.h"
15 
16 // pmapi.h must be included before mmv_stats.h
17 #include <pcp/pmapi.h>
18 
19 #include <pcp/mmv_stats.h>
20 
21 #include <utility>
22 
26 namespace artdaq {
34 class PCPMMVMetric final : public MetricPlugin
35 {
36 private:
37  std::unordered_map<std::string, int> registered_metric_types_;
38  std::vector<mmv_metric_t> registered_metrics_;
39 
40  void* mmvAddr_;
41  int domain_;
42 
43  size_t initial_metric_collection_time_;
44  std::chrono::steady_clock::time_point metric_start_time_;
45 
46  void copy_string(char* dest, size_t dstsize, const std::string& src)
47  {
48  if (src.size() <= dstsize - 1)
49  {
50  dstsize = src.size() + 1;
51  }
52  memcpy(dest, src.c_str(), dstsize);
53  }
54 
55  void init_mmv()
56  {
57  if (!registered_metrics_.empty())
58  {
59  mmv_stats_flags_t flags{};
60  TLOG(TLVL_INFO) << "Going to initialize mmv metric with name " << normalize_name_(app_name_) << ", metric count " << registered_metrics_.size();
61  TLOG(TLVL_INFO) << "First metric name: " << registered_metrics_[0].name << ", type " << registered_metrics_[0].type << ", item " << registered_metrics_[0].item;
62  mmvAddr_ = mmv_stats_init(normalize_name_(app_name_).c_str(), domain_, flags, &registered_metrics_[0], registered_metrics_.size(), nullptr, 0);
63  }
64  }
65 
66  void stop_mmv()
67  {
68  if (mmvAddr_ != nullptr)
69  {
70  mmv_stats_stop(normalize_name_(app_name_).c_str(), mmvAddr_);
71  mmvAddr_ = nullptr;
72  }
73  }
74 
75  std::string normalize_name_(std::string name)
76  {
77  auto nameTemp(std::move(name));
78 
79  auto pos = nameTemp.find('%');
80  while (pos != std::string::npos)
81  {
82  nameTemp = nameTemp.replace(pos, 1, "Percent");
83  pos = nameTemp.find('%');
84  }
85  std::replace(nameTemp.begin(), nameTemp.end(), ' ', '_');
86 
87  if (nameTemp.size() > MMV_NAMEMAX - 1)
88  {
89  nameTemp = nameTemp.substr(0, MMV_NAMEMAX - 1);
90  }
91  return nameTemp;
92  }
93 
94  bool check_time_()
95  {
96  auto dur = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - metric_start_time_).count();
97  TLOG(TLVL_INFO) << "Duration since start: " << dur << " seconds. (initial = " << initial_metric_collection_time_ << " seconds)";
98  if (dur < 0)
99  {
100  return false;
101  }
102  return static_cast<size_t>(dur) > initial_metric_collection_time_;
103  }
104 
105  pmUnits infer_units_(std::string unitString)
106  {
107  pmUnits output;
108  output.scaleCount = PM_COUNT_ONE;
109  output.scaleSpace = PM_SPACE_BYTE;
110  output.scaleTime = PM_TIME_SEC;
111  output.dimTime = 0;
112  output.dimSpace = 0;
113  output.dimCount = 0;
114 
115  std::transform(unitString.begin(), unitString.end(), unitString.begin(), ::tolower);
116  std::string before = unitString;
117  std::string after;
118 
119  if (auto pos = unitString.find('/') != std::string::npos)
120  {
121  before = unitString.substr(0, static_cast<int>(pos) - 1);
122  after = unitString.substr(pos);
123  }
124  std::istringstream iss(before);
125  std::vector<std::string> before_tokens{std::istream_iterator<std::string>{iss},
126  std::istream_iterator<std::string>{}};
127 
128  iss.str(after);
129  std::vector<std::string> after_tokens{std::istream_iterator<std::string>{iss},
130  std::istream_iterator<std::string>{}};
131 
132  for (const auto& token : before_tokens)
133  {
134  if (token.empty())
135  {
136  continue;
137  }
138  if (token == "s" || token.find("sec") == 0)
139  {
140  output.dimTime++;
141  }
142  else if (token == "b" || token.find("byte") == 0)
143  {
144  output.dimSpace++;
145  }
146  else
147  {
148  output.dimCount++;
149  }
150  }
151 
152  for (const auto& token : after_tokens)
153  {
154  if (token.empty())
155  {
156  continue;
157  }
158  if (token == "s" || token.find("sec") == 0)
159  {
160  output.dimTime--;
161  }
162  else if (token == "b" || token.find("byte") == 0)
163  {
164  output.dimSpace--;
165  }
166  else
167  {
168  output.dimCount--;
169  }
170  }
171 
172  return output;
173  }
174 
175  PCPMMVMetric(PCPMMVMetric const&) = delete;
176  PCPMMVMetric(PCPMMVMetric&&) = delete;
177  PCPMMVMetric& operator=(PCPMMVMetric const&) = delete;
178  PCPMMVMetric& operator=(PCPMMVMetric&&) = delete;
179 
180 public:
189  explicit PCPMMVMetric(fhicl::ParameterSet const& pset, std::string const& app_name)
190  : MetricPlugin(pset, app_name)
191  , mmvAddr_(nullptr)
192  , domain_(pset.get<int>("pcp_domain_number", 0))
193  , initial_metric_collection_time_(pset.get<size_t>("seconds_before_init", 30))
194  {}
195 
196  ~PCPMMVMetric() override { MetricPlugin::stopMetrics(); }
197 
202  std::string getLibName() const override { return "pcpmmv"; }
203 
207  void stopMetrics_() override {}
208 
212  void startMetrics_() override { metric_start_time_ = std::chrono::steady_clock::now(); }
213 
220  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
221  {
222  auto nname = normalize_name_(name);
223  if (registered_metric_types_.count(nname) == 0u)
224  {
225  TLOG(TLVL_INFO) << "Adding string metric named " << nname;
226  mmv_metric_t newMetric;
227  copy_string(newMetric.name, MMV_NAMEMAX, nname);
228  newMetric.item = registered_metrics_.size();
229  newMetric.type = MMV_TYPE_STRING;
230  newMetric.semantics = MMV_SEM_INSTANT;
231  newMetric.dimension = infer_units_(unit);
232  newMetric.indom = 0;
233  newMetric.helptext = nullptr;
234  newMetric.shorttext = nullptr;
235 
236  registered_metrics_.push_back(newMetric);
237  registered_metric_types_[nname] = MMV_TYPE_STRING;
238  stop_mmv();
239  }
240 
241  if (registered_metric_types_[nname] != MMV_TYPE_STRING)
242  {
243  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
244  << ", got std::string";
245  return;
246  }
247 
248  if ((mmvAddr_ == nullptr) && check_time_())
249  {
250  init_mmv();
251  }
252 
253  if (mmvAddr_ != nullptr)
254  {
255  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), nullptr);
256  auto val = value;
257  if (val.size() > MMV_STRINGMAX - 1)
258  {
259  val = val.substr(0, MMV_STRINGMAX - 1);
260  }
261 
262  mmv_set_string(mmvAddr_, base, value.c_str(), value.size());
263  }
264  }
265 
272  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
273  {
274  auto nname = normalize_name_(name);
275  if (registered_metric_types_.count(nname) == 0u)
276  {
277  TLOG(TLVL_INFO) << "Adding int metric named " << nname;
278  mmv_metric_t newMetric;
279  copy_string(newMetric.name, MMV_NAMEMAX, nname);
280  newMetric.item = registered_metrics_.size();
281  newMetric.type = MMV_TYPE_I64;
282  newMetric.semantics = MMV_SEM_INSTANT;
283  newMetric.dimension = infer_units_(unit);
284  newMetric.indom = 0;
285  newMetric.helptext = nullptr;
286  newMetric.shorttext = nullptr;
287 
288  registered_metrics_.push_back(newMetric);
289  registered_metric_types_[nname] = MMV_TYPE_I64;
290  stop_mmv();
291  }
292 
293  if (registered_metric_types_[nname] != MMV_TYPE_I64)
294  {
295  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
296  << ", got int";
297  return;
298  }
299 
300  if ((mmvAddr_ == nullptr) && check_time_())
301  {
302  init_mmv();
303  }
304 
305  if (mmvAddr_ != nullptr)
306  {
307  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), nullptr);
308  mmv_set_value(mmvAddr_, base, value);
309  }
310  }
311 
318  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
319  {
320  auto nname = normalize_name_(name);
321  if (registered_metric_types_.count(nname) == 0u)
322  {
323  TLOG(TLVL_INFO) << "Adding double metric named " << nname;
324  mmv_metric_t newMetric;
325  copy_string(newMetric.name, MMV_NAMEMAX, nname);
326  newMetric.item = registered_metrics_.size();
327  newMetric.type = MMV_TYPE_DOUBLE;
328  newMetric.semantics = MMV_SEM_INSTANT;
329  newMetric.dimension = infer_units_(unit);
330  newMetric.indom = 0;
331  newMetric.helptext = nullptr;
332  newMetric.shorttext = nullptr;
333 
334  registered_metrics_.push_back(newMetric);
335  registered_metric_types_[nname] = MMV_TYPE_DOUBLE;
336  stop_mmv();
337  }
338 
339  if (registered_metric_types_[nname] != MMV_TYPE_DOUBLE)
340  {
341  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
342  << ", got double";
343  return;
344  }
345 
346  if ((mmvAddr_ == nullptr) && check_time_())
347  {
348  init_mmv();
349  }
350 
351  if (mmvAddr_ != nullptr)
352  {
353  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), nullptr);
354  mmv_set_value(mmvAddr_, base, value);
355  }
356  }
357 
364  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
365  {
366  auto nname = normalize_name_(name);
367  if (registered_metric_types_.count(nname) == 0u)
368  {
369  TLOG(TLVL_INFO) << "Adding float metric named " << nname;
370  mmv_metric_t newMetric;
371  copy_string(newMetric.name, MMV_NAMEMAX, nname);
372  newMetric.item = registered_metrics_.size();
373  newMetric.type = MMV_TYPE_FLOAT;
374  newMetric.semantics = MMV_SEM_INSTANT;
375  newMetric.dimension = infer_units_(unit);
376  newMetric.indom = 0;
377  newMetric.helptext = nullptr;
378  newMetric.shorttext = nullptr;
379 
380  registered_metrics_.push_back(newMetric);
381  registered_metric_types_[nname] = MMV_TYPE_FLOAT;
382  stop_mmv();
383  }
384 
385  if (registered_metric_types_[nname] != MMV_TYPE_FLOAT)
386  {
387  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
388  << ", got float";
389  return;
390  }
391 
392  if ((mmvAddr_ == nullptr) && check_time_())
393  {
394  init_mmv();
395  }
396 
397  if (mmvAddr_ != nullptr)
398  {
399  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), nullptr);
400  mmv_set_value(mmvAddr_, base, value);
401  }
402  }
403 
410  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit) override
411  {
412  auto nname = normalize_name_(name);
413  if (registered_metric_types_.count(nname) == 0u)
414  {
415  TLOG(TLVL_INFO) << "Adding unsigned metric named " << nname;
416  mmv_metric_t newMetric;
417  copy_string(newMetric.name, MMV_NAMEMAX, nname);
418  newMetric.item = registered_metrics_.size();
419  newMetric.type = MMV_TYPE_U64;
420  newMetric.semantics = MMV_SEM_INSTANT;
421  newMetric.dimension = infer_units_(unit);
422  newMetric.indom = 0;
423  newMetric.helptext = nullptr;
424  newMetric.shorttext = nullptr;
425 
426  registered_metrics_.push_back(newMetric);
427  registered_metric_types_[nname] = MMV_TYPE_U64;
428  stop_mmv();
429  }
430 
431  if (registered_metric_types_[nname] != MMV_TYPE_U64)
432  {
433  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
434  << ", got unsigned int";
435  return;
436  }
437 
438  if ((mmvAddr_ == nullptr) && check_time_())
439  {
440  init_mmv();
441  }
442 
443  if (mmvAddr_ != nullptr)
444  {
445  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), nullptr);
446  mmv_set_value(mmvAddr_, base, value);
447  }
448  }
449 };
450 } // End namespace artdaq
451 
452 DEFINE_ARTDAQ_METRIC(artdaq::PCPMMVMetric)
453 
454 #endif // End ifndef __PCPMMV_METRIC__
void sendMetric_(const std::string &name, const uint64_t &value, const std::string &unit) override
Send an unsigned long metric to PCPMMV.
void sendMetric_(const std::string &name, const int &value, const std::string &unit) override
Send a integer metric to PCPMMV.
PCPMMVMetric(fhicl::ParameterSet const &pset, std::string const &app_name)
Construct an instance of the PCPMMV metric.
std::string getLibName() const override
Gets the unique library name of this plugin.
void sendMetric_(const std::string &name, const std::string &value, const std::string &unit) override
Send a string metric to PCPMMV.
void stopMetrics_() override
PCPMMV does not need any specific action on stop.
void startMetrics_() override
PCPMMV does not need any specific action on start.
void sendMetric_(const std::string &name, const double &value, const std::string &unit) override
Send a double metric to PCPMMV.
void sendMetric_(const std::string &name, const float &value, const std::string &unit) override
Send a float metric to PCPMMV.
An instance of the MetricPlugin class that sends metric data to PCPMMV.