PVData C++  8.0.5
reftrack.h
1 /*
2  * Copyright information and license terms for this software can be
3  * found in the file LICENSE that is included with the distribution
4  */
5 #ifndef REFTRACK_H
6 #define REFTRACK_H
7 
8 /** @page pvd_reftrack RefTrack
9  *
10  * reftrack.h is a utility for listing, finding, and reading global atomic counters.
11  * By convention used to expose object instance counters as a way of detecting (slow)
12  * reference/resource leaks before they cause problems.
13  *
14  * cf. the IOC shell commands "refshow", "refsave", and "refdiff".
15  *
16  * Example usage:
17  *
18  * @code
19  * // my header.h
20  * struct MyClass {
21  * MyClass();
22  * ~MyClass();
23  * static size_t num_instances;
24  * ...
25  * };
26  * ...
27  * // my src.cpp
28  * size_t MyClass::num_instances;
29  * MyClass::MyClass() {
30  * REFTRACE_INCREMENT(num_instances);
31  * }
32  * MyClass::~MyClass() {
33  * REFTRACE_DECREMENT(num_instances);
34  * }
35  * // in some IOC registrar or global ctor
36  * registerRefCounter("MyClass", &MyClass::num_instances);
37  * @endcode
38  */
39 
40 #ifdef __cplusplus
41 
42 #include <map>
43 #include <string>
44 #include <ostream>
45 
46 #include <stdlib.h>
47 
48 #include <epicsVersion.h>
49 #include <epicsAtomic.h>
50 
51 #define REFTRACE_INCREMENT(counter) ::epics::atomic::increment(counter)
52 #define REFTRACE_DECREMENT(counter) ::epics::atomic::decrement(counter)
53 
54 #include <shareLib.h>
55 
56 namespace epics {
57 
58 //! Register new global reference counter
59 epicsShareFunc
60 void registerRefCounter(const char *name, const size_t* counter);
61 
62 //! Remove registration of global reference counter (if dynamically allocated)
63 epicsShareFunc
64 void unregisterRefCounter(const char *name, const size_t* counter);
65 
66 //! Fetch current value of single reference counter
67 epicsShareFunc
68 size_t readRefCounter(const char *name);
69 
70 //! Represent a snapshot of many reference counters
71 class epicsShareClass RefSnapshot
72 {
73 public:
74  //! A single count
75  struct Count {
76  size_t current;
77  long delta; //!< current - previous
78  Count() :current(0u), delta(0) {}
79  explicit Count(size_t c, long d) :current(c), delta(d) {}
80  bool operator==(const Count& o) const
81  { return current==o.current && delta==o.delta; }
82  };
83 
84 private:
85  typedef std::map<std::string, Count> cnt_map_t;
86  cnt_map_t counts;
87 public:
88  typedef cnt_map_t::const_iterator iterator;
89  typedef cnt_map_t::const_iterator const_iterator;
90 
91  /** Fetch values of all reference counters.
92  *
93  * This involves many atomic reads, not a single operation.
94  */
95  void update();
96 
97  const Count& operator[](const std::string& name) const;
98 
99  iterator begin() const { return counts.begin(); }
100  iterator end() const { return counts.end(); }
101  size_t size() const { return counts.size(); }
102 
103  inline void swap(RefSnapshot& o)
104  {
105  counts.swap(o.counts);
106  }
107 
108  /** Compute the difference lhs - rhs
109  *
110  * Returned RefSnapshot has Count::current=lhs.current
111  * and Count::delta= lhs.current - rhs.current
112  */
113  RefSnapshot operator-(const RefSnapshot& rhs) const;
114 };
115 
116 //! Print all counters with a non-zero delta
117 epicsShareFunc
118 std::ostream& operator<<(std::ostream& strm, const RefSnapshot& snap);
119 
120 //! Helper to run a thread which periodically prints (via show() )
121 //! global reference counter deltas.
122 class epicsShareClass RefMonitor
123 {
124  struct Impl;
125  Impl *impl;
126 public:
127  RefMonitor();
128  virtual ~RefMonitor();
129 
130  void start(double period=10.0);
131  void stop();
132  bool running() const;
133 
134  //! call show() with current snapshot
135  void current();
136 protected:
137  //! Default prints to stderr
138  //! @param complete when false show only non-zero delta, when true show non-zero count or delta
139  virtual void show(const RefSnapshot& snap, bool complete=false);
140 };
141 
142 } // namespace epics
143 
144 extern "C" {
145 #endif /* __cplusplus */
146 
147 /** Fetch and print current snapshot
148  * @return NULL or a char* which must be free()'d
149  */
150 char* epicsRefSnapshotCurrent();
151 
152 #ifdef __cplusplus
153 }
154 #endif /* __cplusplus */
155 
156 #endif // REFTRACK_H