summaryrefslogtreecommitdiffstats
path: root/src/common/DecayCounter.h
blob: b9545b1516194d118d10023f24605fbb11a9cf0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software 
 * Foundation.  See file COPYING.
 * 
 */

#ifndef CEPH_DECAYCOUNTER_H
#define CEPH_DECAYCOUNTER_H

#include "include/buffer.h"
#include "common/Formatter.h"
#include "common/ceph_time.h"

#include <cmath>
#include <list>
#include <sstream>

/**
 *
 * TODO: normalize value based on some function of half_life, 
 *  so that it can be interpreted as an approximation of a
 *  moving average of N seconds.  currently, changing half-life
 *  skews the scale of the value, even at steady state.  
 *
 */

class DecayRate {
public:
  friend class DecayCounter;

  DecayRate() {}
  // cppcheck-suppress noExplicitConstructor
  DecayRate(double hl) { set_halflife(hl); }
  DecayRate(const DecayRate &dr) : k(dr.k) {}

  void set_halflife(double hl) {
    k = log(.5) / hl;
  }
  double get_halflife() const {
    return log(.5) / k;
  }

private:
  double k = 0;             // k = ln(.5)/half_life
};

class DecayCounter {
public:
  using time = ceph::coarse_mono_time;
  using clock = ceph::coarse_mono_clock;

  DecayCounter() : DecayCounter(DecayRate()) {}
  explicit DecayCounter(const DecayRate &rate) : last_decay(clock::now()), rate(rate) {}

  void encode(bufferlist& bl) const;
  void decode(bufferlist::const_iterator& p);
  void dump(Formatter *f) const;
  static void generate_test_instances(std::list<DecayCounter*>& ls);

  /**
   * reading
   */

  double get() const {
    decay();
    return val;
  }

  double get_last() const {
    return val;
  }
  
  time get_last_decay() const {
    return last_decay; 
  }

  /**
   * adjusting
   */

  double hit(double v = 1.0) {
    decay(v);
    return val;
  }
  void adjust(double v = 1.0) {
    decay(v);
  }

  void scale(double f) {
    val *= f;
  }

  /**
   * decay etc.
   */

  void reset() {
    last_decay = clock::now();
    val = 0;
  }

protected:
  void decay(double delta) const;
  void decay() const {decay(0.0);}

private:
  mutable double val = 0.0;           // value
  mutable time last_decay = clock::zero();   // time of last decay
  DecayRate rate;
};

inline void encode(const DecayCounter &c, bufferlist &bl) {
  c.encode(bl);
}
inline void decode(DecayCounter &c, bufferlist::const_iterator &p) {
  c.decode(p);
}

inline std::ostream& operator<<(std::ostream& out, const DecayCounter& d) {
  std::ostringstream oss;
  oss.precision(2);
  double val = d.get();
  oss << "[C " << std::scientific << val << "]";
  return out << oss.str();
}

#endif