NdmcMetric.h
Go to the documentation of this file.
1 /**
2  * NdmcMetric header file
3  * $Id: NdmcMetric.h,v 1.25.10.1 2019/09/27 00:07:18 slin Exp $
4  */
5 #ifndef __NDMC_METRIC_H_
6 #define __NDMC_METRIC_H_
7 
8 #include <typeinfo>
9 #include <sstream>
10 #include <sys/times.h>
11 #include <boost/algorithm/string.hpp> // to_lower
13 #include "NovaDAQMonitorClient/Ndmc.h"
14 #include "NovaDAQMonitorClient/NdmcMetricABC.h"
15 #include "NovaDAQMonitorClient/NdmcClientService.h"
16 
17 //extern "C" {
18 #include "ganglia.h"
19 //}
20 
21 class NdmcMetricTest;
22 class NdmcClientTest;
23 
25 
26 /**
27  * NdmcMetric
28  *
29  * This class implements a single custom metric to be sent by a client
30  * to the DAQ Monitor Server.
31  *
32  * @author Susan Kasahara
33  * @author <a href="mailto:schubert@physics.umn.edu">schubert@physics.umn.edu</a>
34  * @date May 05 2010 (creation)
35  */
36 template <class T>
37 class NdmcMetric : public NdmcMetricABC {
38 
39  friend class ::NdmcMetricTest;
40  friend class ::NdmcClientTest;
41 
42  public:
43 
44  // Constructors/Destructors
46  int32_t maxdeltatime=30, int32_t lifetime=60, ganglia_slope_t slope=GANGLIA_SLOPE_BOTH,
47  int32_t partition = -1, std::string appName="", std::string groupName="",
48  std::string title = "", std::string desc = "");
49  virtual ~NdmcMetric();
50 
51  // State changing methods
52  bool setValue(T value, double weight=1., int npar = 0, double* par = 0);
53  bool send();
54 
55  // Accessor methods
56  std::string getName() const { return _name; }
57  std::string getUnit() const { return _unit; }
58  int32_t getPartition() const { return _partition; }
60  std::string getGroupName() const { return _groupName; }
61  std::string getTitle() const { return _title; }
64  int32_t getMaxDeltaTime() const { return _maxDeltaTime; }
65  int32_t getLifeTime() const { return _lifeTime; }
66  ganglia_slope_t getSlope() const { return _slope; }
67  std::string getType() const { return _type; }
68  T getValue() const { return _value; }
69  bool getLastValueSent(T& lastValueSent) const;
70  double getSumWX() const { return _sumwx; }
71  double getSumW() const { return _sumw; }
72  double getNW() const { return _nw; }
73  double getSumWXSq() const { return _sumwxsq; }
74  bool isValueSet() const { return _isValueSet; }
76 
77  // State changing methods
78  void resetValue() { if ( _metricType == HEARTBEAT ) return;
79  _value = 0; _sumw = 0; _nw = 0; _sumwx = 0; _sumwxsq = 0;
80  _isValueSet = false; }
81  void setApplicationName(std::string appName);
82  void setGroupName(std::string groupName);
83  void setPartition(int32_t partition);
86 
87  private:
88 
89  std::string _name; /**< Name of this metric */
90  std::string _unit; /**< Unit of metric ("bytes","kB/s",...) */
91  MetricType_t _metricType; /**< Metric type */
92  int32_t _maxDeltaTime; /**< Maximum time in seconds between gmetric calls */
93  int32_t _lifeTime; /**< Lifetime in seconds of this metric, default 0 => unlimited */
94  ganglia_slope_t _slope; /**< Slope of metric (zero (fixed), positive (counter),negative, both) */
95  std::string _type; /**< Type of metric as string ("uint32","int32",...) */
96  T _value; /**< Value of metric */
97  double _sumwx; /**< summed weight*value, used for AVERAGE & STDEV */
98  double _sumw; /**< summed weight, used for MetricType::AVERAGE & STDEV */
99  double _nw; /**< summed number of non-zero weight entries, used for STDEV */
100  double _sumwxsq; /**< summed weight*value*value, used for STDEV */
101  bool _isValueSet; /**< If value is currently set, then true */
102  clock_t _lastSendTime; /**< Last metric send time */
103  T _lastValueSent; /**< Last metric value sent */
104  bool _valueHasBeenSent; /**< At least one value has been sent */
105  int32_t _partition; /**< Partition */
106  std::string _applicationName; /**< Application name */
107  std::string _groupName; /**< Group name */
108  std::string _title; /**< Title to be displayed over metric */
109  std::string _description; /**< Description of metric displayed when mousing-over graph */
110  std::string _metricName; /**< <name of metric>_A<appname>_P<partition> */
111  Ganglia_metric_t _gMetric; /**< Ganglia metric structure */
112 
113  // private methods
114  std::string _getType() const;
115  double _timeSinceLastSend(clock_t& currentwalltime);
116  bool _calculateSendValue(T& sendValue, double timeSinceLastSend=0);
117  void _updateMetricName();
118 
119 };
120 
121 /**
122  * Constructor
123  */
124 template <class T>
126  int32_t maxDeltaTime, int32_t lifeTime, ganglia_slope_t slope,
127  int32_t partition, std::string appName, std::string groupName,
129  _name(name), _unit(unit), _metricType(metricType),
130  _maxDeltaTime(maxDeltaTime),_lifeTime(lifeTime), _slope(slope), _value(0),
131  _sumwx(0),_sumw(0),_nw(0),_sumwxsq(0),_isValueSet(false),_lastSendTime(0),
132  _lastValueSent(0), _valueHasBeenSent(false), _partition(partition),
133  _applicationName(appName), _groupName(groupName), _title(title),
134  _description(description), _metricName("") {
135 
136  LOG_DEBUG("NdmcMetric") << "NdmcMetric::ctor @" << this << "." << std::endl;
137 
138  _type = _getType();
139 
140  Ganglia_pool_t globalContext = NdmcClientService::instance().getGlobalContext();
141  // Create the message container
142  _gMetric = Ganglia_metric_create(globalContext);
143  std::ostringstream oss;
144  if ( !_gMetric ) {
145  ::mf::LogError("NdmcMetric")
146  << "NdmcMetric::ctor - Unable to allocate gmetric structure for metric "
147  << name.c_str() << "." << std::endl;
148  return;
149  }
150  else {
151  oss << "NdmcMetric::ctor - Constructed metric " << name.c_str();
152  }
153 
154  struct tms ctime;
155  clock_t wall = times(&ctime);
156  _lastSendTime = wall;
157 
158  if ( _metricType == HEARTBEAT ) setValue(1);
159 
160  setPartition(partition);
161  setApplicationName(appName);
162  setGroupName(groupName);
163 
164  if ( !title.empty() ) setTitle(title);
165  if ( !description.empty() ) setDescription(description);
166 
167  oss << ", Partition " << getPartition() << ", AppName \"" << getApplicationName()
168  << "\", GroupName \"" << getGroupName() << "\".";
169 
170 
171  ::mf::LogInfo("NdmcMetric") << oss.str() << std::endl;
172 
173 }
174 
175 /**
176  * Destructor
177  */
178 template <class T>
180 
181  LOG_DEBUG("NdmcMetric") << "NdmcMetric::dtor @" << this << "." << std::endl;
182 
183  Ganglia_metric_destroy(_gMetric);
184 
185  ::mf::LogInfo("NdmcMetric") << "NdmcMetric::dtor - Destroyed metric " << getName()
186  << ", Partition " << getPartition() << ", AppName \"" << getApplicationName()
187  << "\", GroupName \"" << getGroupName() << "\"." << std::endl;
188 
189 }
190 
191 /**
192  * Get last value sent for this metric.
193  * @param lastValueSent reference to return value.
194  * @return true if successful, else false if no metric yet sent.
195  */
196 template <class T>
197 bool NdmcMetric<T>::getLastValueSent(T& lastValueSent) const {
198 
199  if ( !_valueHasBeenSent ) return false;
200 
201  lastValueSent = _lastValueSent;
202  return true;
203 
204 }
205 
206 /**
207  * Set new partition.
208  * @param partition - partition number (0,1,2,3). -1 => no partition.
209  * This is the partition number assigned to the application
210  * on startup. If partition number is not -1 (default),
211  * the partition number will be tacked on the metric
212  * name as <metricname>_A<appname>_P<partition>.
213  */
214 template <class T>
216 
219 
220 }
221 
222 /**
223  * Set new application name (optional). Application name will be set to
224  * lower case.
225  * Application name is used to distinguish between different
226  * applications running on the same node in the same partition.
227  * For example, two event displays (Far & Near) may have application names
228  * evdfar and evdnear to distinguish the results in the DAQ Monitor web
229  * display and database. It should not be used to distinguish between
230  * application running for the same purpose on different nodes, or on different
231  * partitions.
232  *
233  * @param appName - application name (optional). Defaults to "". If specified
234  * the application name will be tacked onto the metric name
235  * as <metricname>_A<appname>_P<partition>.
236  */
237 template <class T>
239 
240  _applicationName = appName;
241  boost::algorithm::to_lower(_applicationName);
243 
244 }
245 
246 /**
247  * Set new group name.
248  * The group name is used to specify which group the metric will be displayed
249  * as part of in the DAQ Monitor web display.
250  * @param groupName - group name (optional). Defaults to "". If specified
251  * the metric will be will be displayed as part of groupName
252  * in the web display, else it will be displayed as part of
253  * the "no group" group. The group name is meta data and is
254  * not stored directly in the database file. A metric can
255  * be reassigned to a new group at any time without losing the
256  * continuity of the data stored in the database.
257  */
258 template <class T>
260 
261  _groupName = groupName;
262  // Use _set instead of _add so that new group name will override previous
263  // GSD -- Temp switch to _add -- there is no Ganglia_metadata_set in 3_6_0
264  Ganglia_metadata_add(_gMetric, (char*)"GROUP", (char*)_groupName.c_str());
265 
266 }
267 
268 /**
269  * Set new title.
270  * The title is used to specify the title which will be displayed on the graph
271  * of the metric in the web display.
272  * If not specified, the title will default to "<metricname> P<partition>" if
273  * the partition has been set, else just "<metricname>".
274  * @param title - metric graph title
275  */
276 template <class T>
278 
279  _title = title;
280  // Use _set instead of _add so that new title will override previous
281  // GSD -- Temp switch to _add -- there is no Ganglia_metadata_set in 3_6_0
282  Ganglia_metadata_add(_gMetric, (char*)"TITLE", (char*)_title.c_str());
283 
284 }
285 
286 /**
287  * Set new description.
288  * The description is used to specify the description which will be displayed on
289  * the graph when mousing over the graph in the web display.
290  * @param description - metric graph description
291  */
292 template <class T>
294 
295  _description = desc;
296  // Use _set instead of _add so that new description will override previous
297  // GSD -- Temp switch to _add -- there is no Ganglia_metadata_set in 3_6_0
298  Ganglia_metadata_add(_gMetric, (char*)"DESC", (char*)_description.c_str());
299 
300 }
301 
302 /**
303  * Update metric name if either partition number or application name is changed.
304  * Metric name has the form:
305  * <metric>_A<appname>_P<partition> if both appname and partition are defined, else
306  * <metric>_A<appname> if no partition
307  * <metric>_P<partition> if no appname
308  * <metric> if no partition or appname
309  * For example, "MicroSlice Rate_Adcmapp_P0".
310  */
311 template <class T>
313 
314  std::ostringstream oss;
315  oss << getName();
316  if ( !(getApplicationName().empty()) ) oss << "_A" << getApplicationName();
317  if ( getPartition() >= 0 ) oss << "_P" << getPartition();
318  _metricName = oss.str();
319 
320 }
321 
322 /**
323  * setValue
324  */
325 template <class T>
326 bool NdmcMetric<T>::setValue(T value, double weight, int npar, double* par) {
327 
328  switch ( _metricType ) {
329 
330  case VALUE:
331  case HEARTBEAT:
332  _value = value;
333  break;
334 
335  case COUNTER:
336  case RATE:
337  _value += value;
338  break;
339 
340  case STDEV:
341  if ( npar == 0 ) {
342  _sumwxsq += weight*value*value;
343  _sumwx += weight*value;
344  _sumw += weight;
345  if ( weight > 0.) _nw += 1;
346  }
347  else {
348  // user has provided partial sums, assume weight is just count in partial sums
349  _sumwxsq += par[0];
350  _sumwx += value;
351  _sumw += weight;
352  _nw += weight;
353  }
354  break;
355 
356  case AVERAGE:
357  _sumwx += weight*value;
358  _sumw += weight;
359  break;
360 
361  case MINIMUM:
362  if ( !_isValueSet || value < _value ) _value = value;
363  break;
364 
365  case MAXIMUM:
366  if ( !_isValueSet || value > _value ) _value = value;
367  break;
368 
369  default:
370  ::mf::LogError("NdmcMetric") << "NdmcMetric::setValue - has unknown metric type " <<
371  _metricType << " for metric " << getMetricName() << "." << std::endl;
372  return false;
373  }
374 
375  _isValueSet = true;
376 
377  return true;
378 
379 }
380 
381 /**
382  * send gmetric value already set
383  */
384 template <class T>
386 
387  if (!_isValueSet ) return false; // no value set since last call to send
388 
389  clock_t lastSendTime = 0;
390  double timeSinceLastSend = _timeSinceLastSend(lastSendTime);
391 
392  T sendValue;
393  if ( !_calculateSendValue(sendValue,timeSinceLastSend) ) return false;
394 
395  std::stringstream ssval;
396  ssval << sendValue;
397 
398  int rval = Ganglia_metric_set(_gMetric,(char*)getMetricName().c_str(),
399  (char*)ssval.str().c_str(),(char*)getType().c_str(),
400  (char*)getUnit().c_str(),getSlope(), getMaxDeltaTime(),getLifeTime());
401 
402  switch (rval) {
403  case 1:
404  ::mf::LogError("NdmcMetric") << "NdmcMetric::send - gmetric parameters invalid for metric: "
405  << getMetricName() << "." << std::endl;
406  return false;
407  case 2:
408  ::mf::LogError("NdmcMetric")
409  << "NdmcMetric::send - one of the gmetric parameters has an invalid character for metric: "
410  << getMetricName() << "." << std::endl;
411  return false;
412  case 3:
413  ::mf::LogError("NdmcMetric") << "NdmcMetric::send - "
414  << "gmetric type parameter is not a valid type for metric: "
415  << getMetricName() << std::endl;
416  return false;
417  case 4:
418  ::mf::LogError("NdmcMetric")
419  << "NdmcMetric::send - gmetric value parameter does not represent a number for metric: "
420  << getMetricName() << "." << std::endl;
421  return false;
422  default:
423  break;
424  }
425 
426  Ganglia_udp_send_channels_t sendChannels = NdmcClientService::instance().getSendChannels();
427 
428  LOG_DEBUG("NdmcMetric") << "NdmcMetric::send() - send value " << sendValue << " for metric "
429  << getMetricName() << "." << std::endl;
430  rval = Ganglia_metric_send(_gMetric,sendChannels);
431  if ( rval ) {
432  ::mf::LogError("NdmcMetric") << "NdmcMetric::send - Error sending to " << rval
433  << " channels " << "for metric: " << getMetricName() << "."
434  << std::endl;
435  return false;
436  }
437 
438  _lastValueSent = sendValue;
439  _valueHasBeenSent = true;
440  _lastSendTime = lastSendTime;
441  resetValue();
442  return true;
443 
444 }
445 
446 /**
447  * Calculate value to send based on metric type.
448  * @param sendValue reference to be filled by method
449  * @param timeSinceLastSend is required if metrictype is RATE, otherwise ignored.
450  * @return true or false if not successful.
451  */
452 template <class T>
453 bool NdmcMetric<T>::_calculateSendValue(T& sendValue, double timeSinceLastSend) {
454 
455  switch ( _metricType ) {
456 
457  case VALUE:
458  case COUNTER:
459  case MAXIMUM:
460  case MINIMUM:
461  case HEARTBEAT:
462  sendValue = _value;
463  break;
464 
465  case RATE:
466  if ( timeSinceLastSend != 0 ) sendValue = T(double(_value)/timeSinceLastSend);
467  else return false;
468  break;
469 
470  case AVERAGE:
471  if ( _sumw != 0 ) sendValue = T(_sumwx/_sumw);
472  else return false;
473  break;
474 
475  case STDEV: {
476  double denom = _sumw*_sumw*(_nw-1);
477  if ( denom != 0 ) sendValue = T( sqrt((_sumwxsq*_sumw - _sumwx*_sumwx)*_nw/denom) );
478  else return false;
479  }
480  break;
481 
482  default:
483  ::mf::LogError("NdmcMetric") << "NdmcMetric::_calculateSendValue - unknown metric type " <<
484  _metricType << "." << std::endl;
485  return false;
486  }
487 
488  return true;
489 
490 }
491 
492 
493 
494 /**
495  * Access the data type
496  * Return "unknown" if unknown.
497  */
498 template <class T>
500 
501  if ( typeid(T) == typeid(int8_t) ) return "int8";
502  else if ( typeid(T) == typeid(uint8_t) ) return "uint8";
503  else if ( typeid(T) == typeid(int16_t) ) return "int16";
504  else if ( typeid(T) == typeid(uint16_t) ) return "uint16";
505  else if ( typeid(T) == typeid(int32_t) ) return "int32";
506  else if ( typeid(T) == typeid(uint32_t) ) return "uint32";
507  else if ( typeid(T) == typeid(float) ) return "float";
508  else if ( typeid(T) == typeid(double) ) return "double";
509 
510  ::mf::LogError("NdmcMetric") << "NdmcMetric::getType - Templated type not supported." << std::endl;
511  return "Unknown";
512 
513 }
514 
515 /**
516  * Time since last send (or since construction on first call) in seconds
517  * @param reference in which current time will be stored on output
518  * @return deltaw since _lastSendTime
519  */
520 template <class T>
521 double NdmcMetric<T>::_timeSinceLastSend(clock_t& currenttime) {
522 
523  struct tms ctime;
524  currenttime = times(&ctime);
525  double deltaw = ((double)(currenttime - _lastSendTime))*10000./CLOCKS_PER_SEC;
526  return deltaw;
527 
528 }
529 
531 
532 #endif
533 
void setPartition(int32_t partition)
Definition: NdmcMetric.h:215
#define LOG_DEBUG(stream)
Definition: Messenger.h:149
NdmcMetric(std::string name, std::string unit="", MetricType_t metricType=VALUE, int32_t maxdeltatime=30, int32_t lifetime=60, ganglia_slope_t slope=GANGLIA_SLOPE_BOTH, int32_t partition=-1, std::string appName="", std::string groupName="", std::string title="", std::string desc="")
Definition: NdmcMetric.h:125
const XML_Char * name
Definition: expat.h:151
std::string getName() const
Definition: NdmcMetric.h:56
Ganglia_pool_t getGlobalContext() const
Ganglia_udp_send_channels_t getSendChannels() const
#define NDMC_NAMESPACE_BEGIN
Definition: Ndmc.h:23
const Var weight
clock_t _lastSendTime
Definition: NdmcMetric.h:102
ganglia_slope_t _slope
Definition: NdmcMetric.h:94
Definition: Ndmc.h:39
T sqrt(T number)
Definition: d0nt_math.hpp:156
std::string _applicationName
Definition: NdmcMetric.h:106
std::string getDescription() const
Definition: NdmcMetric.h:62
Int_t par
Definition: SimpleIterate.C:24
double _sumw
Definition: NdmcMetric.h:98
int32_t getMaxDeltaTime() const
Definition: NdmcMetric.h:64
ganglia_slope_t getSlope() const
Definition: NdmcMetric.h:66
Definition: Ndmc.h:37
int32_t _maxDeltaTime
Definition: NdmcMetric.h:92
T getValue() const
Definition: NdmcMetric.h:68
bool isValueSet() const
Definition: NdmcMetric.h:74
MetricType_t _metricType
Definition: NdmcMetric.h:91
std::string _getType() const
Definition: NdmcMetric.h:499
bool _isValueSet
Definition: NdmcMetric.h:101
double getSumWX() const
Definition: NdmcMetric.h:70
enum MetricType MetricType_t
void setTitle(std::string title)
Definition: NdmcMetric.h:277
MetricType_t getMetricType() const
Definition: NdmcMetric.h:63
double _timeSinceLastSend(clock_t &currentwalltime)
Definition: NdmcMetric.h:521
std::string _metricName
Definition: NdmcMetric.h:110
int32_t _lifeTime
Definition: NdmcMetric.h:93
std::string getTitle() const
Definition: NdmcMetric.h:61
bool send()
Definition: NdmcMetric.h:385
std::string _description
Definition: NdmcMetric.h:109
#define NDMC_NAMESPACE_END
Definition: Ndmc.h:26
Definition: Ndmc.h:38
const XML_Char int const XML_Char * value
Definition: expat.h:331
T _lastValueSent
Definition: NdmcMetric.h:103
Definition: Ndmc.h:36
virtual ~NdmcMetric()
Definition: NdmcMetric.h:179
std::string _name
Definition: NdmcMetric.h:89
std::string getGroupName() const
Definition: NdmcMetric.h:60
bool setValue(T value, double weight=1., int npar=0, double *par=0)
Definition: NdmcMetric.h:326
double _sumwxsq
Definition: NdmcMetric.h:100
std::string getType() const
Definition: NdmcMetric.h:67
bool _valueHasBeenSent
Definition: NdmcMetric.h:104
std::string _unit
Definition: NdmcMetric.h:90
std::string _title
Definition: NdmcMetric.h:108
Definition: Ndmc.h:40
double getSumW() const
Definition: NdmcMetric.h:71
static NdmcClientService & instance()
std::string getUnit() const
Definition: NdmcMetric.h:57
::xsd::cxx::tree::string< char, simple_type > string
Definition: Database.h:154
void setDescription(std::string description)
Definition: NdmcMetric.h:293
Definition: Ndmc.h:41
Ganglia_metric_t _gMetric
Definition: NdmcMetric.h:111
bool _calculateSendValue(T &sendValue, double timeSinceLastSend=0)
Definition: NdmcMetric.h:453
void setApplicationName(std::string appName)
Definition: NdmcMetric.h:238
int32_t getPartition() const
Definition: NdmcMetric.h:58
std::string _groupName
Definition: NdmcMetric.h:107
std::string getApplicationName() const
Definition: NdmcMetric.h:59
Definition: Ndmc.h:42
std::string getMetricName() const
Definition: NdmcMetric.h:75
void resetValue()
Definition: NdmcMetric.h:78
double T
Definition: Xdiff_gwt.C:5
int32_t _partition
Definition: NdmcMetric.h:105
void _updateMetricName()
Definition: NdmcMetric.h:312
double _sumwx
Definition: NdmcMetric.h:97
int32_t getLifeTime() const
Definition: NdmcMetric.h:65
double _nw
Definition: NdmcMetric.h:99
void setGroupName(std::string groupName)
Definition: NdmcMetric.h:259
Definition: Ndmc.h:35
std::string _type
Definition: NdmcMetric.h:95
bool getLastValueSent(T &lastValueSent) const
Definition: NdmcMetric.h:197
double getSumWXSq() const
Definition: NdmcMetric.h:73
double getNW() const
Definition: NdmcMetric.h:72