artdaq_pcp_mmv_plugin  v1_00_00
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 #include <pcp/pmapi.h>
17 
18 #include <pcp/mmv_stats.h>
19 
23 namespace artdaq {
31 class PCPMMVMetric : public MetricPlugin
32 {
33 private:
34  std::unordered_map<std::string, int> registered_metric_types_;
35  std::vector<mmv_metric_t> registered_metrics_;
36 
37  void* mmvAddr_;
38  int domain_;
39 
40  size_t initial_metric_collection_time_;
41  std::chrono::steady_clock::time_point metric_start_time_;
42 
43  void init_mmv()
44  {
45  if (registered_metrics_.size() > 0)
46  {
47  mmv_stats_flags_t flags{};
48  TLOG(TLVL_INFO) << "Going to initialize mmv metric with name " << normalize_name_(app_name_) << ", metric count " << registered_metrics_.size();
49  TLOG(TLVL_INFO) << "First metric name: " << registered_metrics_[0].name << ", type " << registered_metrics_[0].type << ", item " << registered_metrics_[0].item;
50  mmvAddr_ = mmv_stats_init(normalize_name_(app_name_).c_str(), domain_, flags, &registered_metrics_[0], registered_metrics_.size(), 0, 0);
51  }
52  }
53 
54  void stop_mmv()
55  {
56  if (mmvAddr_)
57  {
58  mmv_stats_stop(normalize_name_(app_name_).c_str(), mmvAddr_);
59  mmvAddr_ = nullptr;
60  }
61  }
62 
63  std::string normalize_name_(std::string name)
64  {
65  auto nameTemp(name);
66 
67  auto pos = nameTemp.find('%');
68  while (pos != std::string::npos)
69  {
70  nameTemp = nameTemp.replace(pos, 1, "Percent");
71  pos = nameTemp.find('%');
72  }
73  std::replace(nameTemp.begin(), nameTemp.end(), ' ', '_');
74 
75  if (nameTemp.size() > MMV_NAMEMAX - 1)
76  {
77  nameTemp = nameTemp.substr(0, MMV_NAMEMAX - 1);
78  }
79  return nameTemp;
80  }
81 
82  bool check_time_()
83  {
84  auto dur = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - metric_start_time_).count();
85  TLOG(TLVL_INFO) << "Duration since start: " << dur << " seconds. (initial = " << initial_metric_collection_time_ << " seconds)";
86  if (dur < 0) return false;
87  return static_cast<size_t>(dur) > initial_metric_collection_time_;
88  }
89 
90  pmUnits infer_units_(std::string unitString)
91  {
92  pmUnits output;
93  output.scaleCount = PM_COUNT_ONE;
94  output.scaleSpace = PM_SPACE_BYTE;
95  output.scaleTime = PM_TIME_SEC;
96 
97  std::transform(unitString.begin(), unitString.end(), unitString.begin(), ::tolower);
98  std::string before = unitString;
99  std::string after = "";
100 
101  if (auto pos = unitString.find('/') != std::string::npos)
102  {
103  before = unitString.substr(0, pos - 1);
104  after = unitString.substr(pos);
105  }
106  std::istringstream iss(before);
107  std::vector<std::string> before_tokens{std::istream_iterator<std::string>{iss},
108  std::istream_iterator<std::string>{}};
109 
110  iss.str(after);
111  std::vector<std::string> after_tokens{std::istream_iterator<std::string>{iss},
112  std::istream_iterator<std::string>{}};
113 
114  for (auto token : before_tokens)
115  {
116  if (token == "") continue;
117  if (token == "s" || token.find("sec") == 0)
118  {
119  output.dimTime++;
120  }
121  else if (token == "b" || token.find("byte") == 0)
122  {
123  output.dimSpace++;
124  }
125  else
126  {
127  output.dimCount++;
128  }
129  }
130 
131  for (auto token : after_tokens)
132  {
133  if (token == "") continue;
134  if (token == "s" || token.find("sec") == 0)
135  {
136  output.dimTime--;
137  }
138  else if (token == "b" || token.find("byte") == 0)
139  {
140  output.dimSpace--;
141  }
142  else
143  {
144  output.dimCount--;
145  }
146  }
147 
148  return output;
149  }
150 
151 public:
160  explicit PCPMMVMetric(fhicl::ParameterSet const& pset, std::string const& app_name)
161  : MetricPlugin(pset, app_name)
162  , registered_metric_types_()
163  , registered_metrics_()
164  , mmvAddr_(nullptr)
165  , domain_(pset.get<int>("pcp_domain_number", 0))
166  , initial_metric_collection_time_(pset.get<size_t>("seconds_before_init", 30))
167  {}
168 
169  virtual ~PCPMMVMetric() { MetricPlugin::stopMetrics(); }
170 
175  std::string getLibName() const override { return "pcpmmv"; }
176 
180  void stopMetrics_() override {}
181 
185  void startMetrics_() override { metric_start_time_ = std::chrono::steady_clock::now(); }
186 
193  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
194  {
195  auto nname = normalize_name_(name);
196  if (!registered_metric_types_.count(nname))
197  {
198  TLOG(TLVL_INFO) << "Adding string metric named " << nname;
199  mmv_metric_t newMetric;
200  strcpy(newMetric.name, nname.c_str());
201  newMetric.item = registered_metrics_.size();
202  newMetric.type = MMV_TYPE_STRING;
203  newMetric.semantics = MMV_SEM_INSTANT;
204  newMetric.dimension = infer_units_(unit);
205  newMetric.indom = 0;
206  newMetric.helptext = 0;
207  newMetric.shorttext = 0;
208 
209  registered_metrics_.push_back(newMetric);
210  registered_metric_types_[nname] = MMV_TYPE_STRING;
211  stop_mmv();
212  }
213 
214  if (registered_metric_types_[nname] != MMV_TYPE_STRING)
215  {
216  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
217  << ", got std::string";
218  return;
219  }
220 
221  if (!mmvAddr_ && check_time_())
222  {
223  init_mmv();
224  }
225 
226  if (mmvAddr_)
227  {
228  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), 0);
229  auto val = value;
230  if (val.size() > MMV_STRINGMAX - 1)
231  {
232  val = val.substr(0, MMV_STRINGMAX - 1);
233  }
234 
235  mmv_set_string(mmvAddr_, base, value.c_str(), value.size());
236  }
237  }
238 
245  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
246  {
247  auto nname = normalize_name_(name);
248  if (!registered_metric_types_.count(nname))
249  {
250  TLOG(TLVL_INFO) << "Adding int metric named " << nname;
251  mmv_metric_t newMetric;
252  strcpy(newMetric.name, nname.c_str());
253  newMetric.item = registered_metrics_.size();
254  newMetric.type = MMV_TYPE_I64;
255  newMetric.semantics = MMV_SEM_INSTANT;
256  newMetric.dimension = infer_units_(unit);
257  newMetric.indom = 0;
258  newMetric.helptext = 0;
259  newMetric.shorttext = 0;
260 
261  registered_metrics_.push_back(newMetric);
262  registered_metric_types_[nname] = MMV_TYPE_I64;
263  stop_mmv();
264  }
265 
266  if (registered_metric_types_[nname] != MMV_TYPE_I64)
267  {
268  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
269  << ", got int";
270  return;
271  }
272 
273  if (!mmvAddr_ && check_time_())
274  {
275  init_mmv();
276  }
277 
278  if (mmvAddr_)
279  {
280  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), 0);
281  mmv_set_value(mmvAddr_, base, value);
282  }
283  }
284 
291  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
292  {
293  auto nname = normalize_name_(name);
294  if (!registered_metric_types_.count(nname))
295  {
296  TLOG(TLVL_INFO) << "Adding double metric named " << nname;
297  mmv_metric_t newMetric;
298  strcpy(newMetric.name, nname.c_str());
299  newMetric.item = registered_metrics_.size();
300  newMetric.type = MMV_TYPE_DOUBLE;
301  newMetric.semantics = MMV_SEM_INSTANT;
302  newMetric.dimension = infer_units_(unit);
303  newMetric.indom = 0;
304  newMetric.helptext = 0;
305  newMetric.shorttext = 0;
306 
307  registered_metrics_.push_back(newMetric);
308  registered_metric_types_[nname] = MMV_TYPE_DOUBLE;
309  stop_mmv();
310  }
311 
312  if (registered_metric_types_[nname] != MMV_TYPE_DOUBLE)
313  {
314  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
315  << ", got double";
316  return;
317  }
318 
319  if (!mmvAddr_ && check_time_())
320  {
321  init_mmv();
322  }
323 
324  if (mmvAddr_)
325  {
326  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), 0);
327  mmv_set_value(mmvAddr_, base, value);
328  }
329  }
330 
337  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
338  {
339  auto nname = normalize_name_(name);
340  if (!registered_metric_types_.count(nname))
341  {
342  TLOG(TLVL_INFO) << "Adding float metric named " << nname;
343  mmv_metric_t newMetric;
344  strcpy(newMetric.name, nname.c_str());
345  newMetric.item = registered_metrics_.size();
346  newMetric.type = MMV_TYPE_FLOAT;
347  newMetric.semantics = MMV_SEM_INSTANT;
348  newMetric.dimension = infer_units_(unit);
349  newMetric.indom = 0;
350  newMetric.helptext = 0;
351  newMetric.shorttext = 0;
352 
353  registered_metrics_.push_back(newMetric);
354  registered_metric_types_[nname] = MMV_TYPE_FLOAT;
355  stop_mmv();
356  }
357 
358  if (registered_metric_types_[nname] != MMV_TYPE_FLOAT)
359  {
360  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
361  << ", got float";
362  return;
363  }
364 
365  if (!mmvAddr_ && check_time_())
366  {
367  init_mmv();
368  }
369 
370  if (mmvAddr_)
371  {
372  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), 0);
373  mmv_set_value(mmvAddr_, base, value);
374  }
375  }
376 
383  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
384  {
385  auto nname = normalize_name_(name);
386  if (!registered_metric_types_.count(nname))
387  {
388  TLOG(TLVL_INFO) << "Adding unsigned metric named " << nname;
389  mmv_metric_t newMetric;
390  strcpy(newMetric.name, nname.c_str());
391  newMetric.item = registered_metrics_.size();
392  newMetric.type = MMV_TYPE_U64;
393  newMetric.semantics = MMV_SEM_INSTANT;
394  newMetric.dimension = infer_units_(unit);
395  newMetric.indom = 0;
396  newMetric.helptext = 0;
397  newMetric.shorttext = 0;
398 
399  registered_metrics_.push_back(newMetric);
400  registered_metric_types_[nname] = MMV_TYPE_U64;
401  stop_mmv();
402  }
403 
404  if (registered_metric_types_[nname] != MMV_TYPE_U64)
405  {
406  TLOG(TLVL_ERROR) << "PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
407  << ", got unsigned int";
408  return;
409  }
410 
411  if (!mmvAddr_ && check_time_())
412  {
413  init_mmv();
414  }
415 
416  if (mmvAddr_)
417  {
418  auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(), 0);
419  mmv_set_value(mmvAddr_, base, value);
420  }
421  }
422 };
423 } // End namespace artdaq
424 
425 DEFINE_ARTDAQ_METRIC(artdaq::PCPMMVMetric)
426 
427 #endif // End ifndef __PCPMMV_METRIC__
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.
void sendMetric_(const std::string &name, const unsigned long int &value, const std::string &unit) override
Send an unsigned long metric to PCPMMV.