Mitsuba Renderer  0.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
statistics.h
Go to the documentation of this file.
1 /*
2  This file is part of Mitsuba, a physically based rendering system.
3 
4  Copyright (c) 2007-2014 by Wenzel Jakob and others.
5 
6  Mitsuba is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Mitsuba is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #if !defined(__MITSUBA_CORE_STATISTICS_H_)
21 #define __MITSUBA_CORE_STATISTICS_H_
22 
23 #include <mitsuba/core/timer.h>
24 #include <mitsuba/core/atomic.h>
25 
26 //#define MTS_NO_STATISTICS 1
27 
28 #if defined(_MSC_VER)
29 # include <intrin.h>
30 #endif
31 
33 
34 // -----------------------------------------------------------------------
35 // Statistics collection
36 // -----------------------------------------------------------------------
37 
38 /// Size (in characters) of the console-based progress message
39 #define PROGRESS_MSG_SIZE 56
40 
41 /**
42  * Specifies the number of internal counters associated with each
43  * \ref StatsCounter instance.
44  *
45  * This is needed for SMP/ccNUMA systems where different processors might
46  * be contending for a cache line containing a counter. The solution used
47  * here tries to ensure that every processor has its own local counter.
48  */
49 #define NUM_COUNTERS 128 // Must be a power of 2
50 
51 /// Bitmask for \ref NUM_COUNTERS
52 #define NUM_COUNTERS_MASK (NUM_COUNTERS-1)
53 
54 /// Determines the multiples (e.g. 1000, 1024) and units of a \ref StatsCounter
55 enum EStatsType {
56  ENumberValue = 0, ///< Simple unitless number, e.g. # of rays
57  EByteCount, ///< Number of read/written/transferred bytes
58  EPercentage, ///< Percentage with respect to a base counter
59  EMinimumValue, ///< Minimum observed value of some quantity
60  EMaximumValue, ///< Maximum observed value of some quantity
61  EAverage ///< Average value with respect to a base counter
62 };
63 
64 #if (defined(_WIN32) && !defined(_WIN64)) || (defined(__POWERPC__) && !defined(_LP64))
65 #define MTS_32BIT_COUNTERS 1
66 #endif
67 
68 /**
69  * \brief Counter data structure, which is suitable for ccNUMA/SMP machines
70  *
71  * This counter takes up at least one cache line to reduce false sharing.
72  */
74 #if MTS_32BIT_COUNTERS == 1
75  // WIN32 & Darwin (PPC/32) don't support atomic 64 bit increment operations
76  // -> restrict counters to 32bit :(
77  uint32_t value;
78  uint32_t unused2;
79 #else
80  uint64_t value;
81 #endif
82  char unused[120];
83 };
84 
85 /** \brief General-purpose statistics counter
86  *
87  * This class implements a simple counter, which can be used to track various
88  * quantities within Mitsuba. At various points during the execution, it is
89  * possible to then call \ref Statistics::printStats() to get a human-readable
90  * report of their values.
91  *
92  * \ingroup libcore
93  */
95 public:
96  /**
97  * \brief Create a new statistics counter
98  *
99  * \param category Category of the counter when shown in the statistics summary
100  * \param name Name of the counter when shown in the statistics summary
101  * \param type Characterization of the quantity that will be measured
102  * \param initial Initial value of the counter
103  * \param base Initial value of the base counter (only for <tt>type == EPercentage</tt> and <tt>EAverage</tt>)
104  */
105  StatsCounter(const std::string &category, const std::string &name,
106  EStatsType type = ENumberValue, uint64_t initial = 0L, uint64_t base = 0L);
107 
108  /// Free all storage used by the counter
109  ~StatsCounter();
110 
111  /// Increment the counter value by one
112  inline uint64_t operator++() {
113 #if defined(MTS_NO_STATISTICS)
114  // do nothing
115  return 0;
116 #elif defined(_MSC_VER) && defined(_WIN64)
117  const int offset = Thread::getID() & NUM_COUNTERS_MASK;
118  _InterlockedExchangeAdd64(reinterpret_cast<__int64 volatile *>(&m_value[offset].value), 1);
119  return m_value[offset].value;
120 #elif defined(_MSC_VER) && defined(_WIN32)
121  const int offset = Thread::getID() & NUM_COUNTERS_MASK;
122  _InterlockedExchangeAdd(reinterpret_cast<long volatile *>(&m_value[offset].value), 1);
123  return m_value[offset].value;
124 #elif defined(__POWERPC__) && !defined(_LP64)
125  return (uint64_t) __sync_fetch_and_add(&m_value[Thread::getID() & NUM_COUNTERS_MASK].value, 1);
126 #else
127  return __sync_fetch_and_add(&m_value[Thread::getID() & NUM_COUNTERS_MASK].value, 1);
128 #endif
129  }
130 
131  /// Increment the counter by the specified amount
132  inline void operator+=(size_t amount) {
133 #ifdef MTS_NO_STATISTICS
134  /// do nothing
135 #elif defined(_MSC_VER) && defined(_WIN64)
136  _InterlockedExchangeAdd64(reinterpret_cast<__int64 volatile *>(&m_value[Thread::getID() & NUM_COUNTERS_MASK].value), amount);
137 #elif defined(_MSC_VER) && defined(_WIN32)
138  _InterlockedExchangeAdd(reinterpret_cast<long volatile *>(&m_value[Thread::getID() & NUM_COUNTERS_MASK].value), amount);
139 #else
140  __sync_fetch_and_add(&m_value[Thread::getID() & NUM_COUNTERS_MASK].value, amount);
141 #endif
142  }
143 
144  /// Increment the base counter by the specified amount (only for use with EPercentage/EAverage)
145  inline void incrementBase(size_t amount = 1) {
146 #ifdef MTS_NO_STATISTICS
147  /// do nothing
148 #elif defined(_MSC_VER) && defined(_WIN64)
149  _InterlockedExchangeAdd64(reinterpret_cast<__int64 volatile *>(&m_base[Thread::getID() & NUM_COUNTERS_MASK].value), amount);
150 #elif defined(_WIN32)
151  _InterlockedExchangeAdd(reinterpret_cast<long volatile *>(&m_base[Thread::getID() & NUM_COUNTERS_MASK].value), amount);
152 #else
153  __sync_fetch_and_add(&m_base[Thread::getID() & NUM_COUNTERS_MASK].value, amount);
154 #endif
155  }
156 
157  /**
158  * \brief When this is a minimum "counter", this function records
159  * an observation of the quantity whose minimum is to be determined
160  */
161  inline void recordMinimum(size_t value) {
162  int id = Thread::getID() & NUM_COUNTERS_MASK;
163  #if MTS_32BIT_COUNTERS == 1
164  volatile int32_t *ptr =
165  (volatile int32_t *) &m_value[id].value;
166  int32_t curMinimum;
167  int32_t newMinimum = (int32_t) value;
168  #else
169  volatile int64_t *ptr =
170  (volatile int64_t *) &m_value[id].value;
171  int64_t curMinimum;
172  int64_t newMinimum = (int64_t) value;
173  #endif
174 
175  do {
176  curMinimum = *ptr;
177  if (newMinimum >= curMinimum)
178  return;
179  #if (defined(__i386__) || defined(__amd64__))
180  __asm__ __volatile__ ("pause\n");
181  #endif
182  } while (!atomicCompareAndExchange(ptr, newMinimum, curMinimum));
183  }
184 
185  /**
186  * \brief When this is a maximum "counter", this function records
187  * an observation of the quantity whose maximum is to be determined
188  */
189  inline void recordMaximum(size_t value) {
190  int id = Thread::getID() & NUM_COUNTERS_MASK;
191  #if MTS_32BIT_COUNTERS == 1
192  volatile int32_t *ptr =
193  (volatile int32_t *) &m_value[id].value;
194  int32_t curMaximum;
195  int32_t newMaximum = (int32_t) value;
196  #else
197  volatile int64_t *ptr =
198  (volatile int64_t *) &m_value[id].value;
199  int64_t curMaximum;
200  int64_t newMaximum = (int64_t) value;
201  #endif
202 
203  do {
204  curMaximum = *ptr;
205  if (newMaximum <= curMaximum)
206  return;
207  #if (defined(__i386__) || defined(__amd64__))
208  __asm__ __volatile__ ("pause\n");
209  #endif
210  } while (!atomicCompareAndExchange(ptr, newMaximum, curMaximum));
211  }
212 
213  /// Return the name of this counter
214  inline const std::string &getName() const { return m_name; }
215 
216  /// Return the category of this counter
217  inline const std::string &getCategory() const { return m_category; }
218 
219  /// Return the type of this counter
220  inline EStatsType getType() const { return m_type; }
221 
222  /// Return the value of this counter as 64-bit unsigned integer
223 #ifdef MTS_NO_STATISTICS
224  inline uint64_t getValue() const { return 0L; }
225  inline uint64_t getMaximum() const { return 0L; }
226  inline uint64_t getMinimum() const { return 0L; }
227 #else
228  inline uint64_t getValue() const {
229  uint64_t result = 0;
230  for (int i=0; i<NUM_COUNTERS; ++i)
231  result += m_value[i].value;
232  return result;
233  }
234 
235  inline uint64_t getMinimum() const {
236  uint64_t result = 0;
237  for (int i=0; i<NUM_COUNTERS; ++i)
238  result = std::min(static_cast<uint64_t>(m_value[i].value), result);
239  return result;
240  }
241 
242  inline uint64_t getMaximum() const {
243  uint64_t result = 0;
244  for (int i=0; i<NUM_COUNTERS; ++i)
245  result = std::max(static_cast<uint64_t>(m_value[i].value), result);
246  return result;
247  }
248 #endif
249 
250  /// Get the reference number (only used with the EPercentage/EAverage counter type)
251 #ifdef MTS_NO_STATISTICS
252  inline uint64_t getBase() const { return 0L; }
253 #else
254  inline uint64_t getBase() const {
255  uint64_t result = 0;
256  for (int i=0; i<NUM_COUNTERS; ++i)
257  result += m_base[i].value;
258  return result;
259  }
260 #endif
261 
262  /// Reset the stored counter values
263  inline void reset() {
264  for (int i=0; i<NUM_COUNTERS; ++i) {
265  m_value[i].value = m_base[i].value = 0;
266  }
267  }
268 
269  /// Sorting by name (for the statistics)
270  bool operator<(const StatsCounter &v) const;
271 private:
272  std::string m_category;
273  std::string m_name;
274  EStatsType m_type;
275  CacheLineCounter *m_value;
276  CacheLineCounter *m_base;
277 };
278 
279 /** \brief General-purpose progress reporter
280  *
281  * This class is used to track the progress of various operations that might
282  * take longer than, say, a second. It provides interactive feedback on both
283  * the console binaries and within Mitsuba's Qt-based GUI.
284  *
285  * \ingroup libcore
286  */
288 public:
289  /**
290  * Construct a new progress reporter.
291  * 'ptr' is a custom pointer payload to be submitted with progress messages
292  */
293  ProgressReporter(const std::string &title, long long total, const void *ptr);
294 
295  /// Reset the progress reporter to its initial state
296  void reset();
297 
298  /// Update the progress display
299  void update(long long value);
300 
301  /// Return the current value
302  inline long long getValue() const { return m_value; }
303 
304  /// Finish
305  inline void finish() {
306  if (m_value < m_total)
307  update(m_total);
308  }
309 
310  /// Enable/disable progress bars
311  static void setEnabled(bool enabled);
312 
313  /// Check whether progress bars are enabled
314  static inline bool isEnabled() { return m_enabled; }
315 private:
316  /// Convert a time value to a human-readable format
317  void printTime(Float time, std::ostream &os) const;
318 private:
319  static bool m_enabled;
320  std::string m_title;
321  long long m_total, m_value;
322  unsigned int m_lastMs;
323  int m_percentage;
324  int m_fillSize, m_fillPos;
325  char m_string[PROGRESS_MSG_SIZE];
326  ref<Timer> m_timer;
327  const void *m_ptr;
328 };
329 
330 /** \brief Collects various rendering statistics and presents them
331  * in a human-readable form.
332  *
333  * \remark Only the \ref getInstance(), \ref getStats(), and
334  * \ref printStats() functions are implemented in the Python bindings.
335  *
336  * \ingroup libcore
337  * \ingroup libpython
338  */
340 public:
341  /// Return the global stats collector instance
342  inline static Statistics *getInstance() { return m_instance; }
343 
344  /// Register a counter with the statistics collector
345  void registerCounter(const StatsCounter *ctr);
346 
347  /// Record that a plugin has been loaded
348  void logPlugin(const std::string &pname, const std::string &descr);
349 
350  /// Print a summary of gathered statistics
351  void printStats();
352 
353  /// Return a string containing gathered statistics
354  std::string getStats();
355 
356  /// Reset all statistics counters
357  void resetAll();
358 
359  /// Initialize the global statistics collector
360  static void staticInitialization();
361 
362  /// Free the memory taken by staticInitialization()
363  static void staticShutdown();
364 
366 protected:
367  /// Create a statistics instance
368  Statistics();
369  /// Virtual destructor
370  virtual ~Statistics() { }
371 private:
372  struct compareCategory {
373  bool operator()(const StatsCounter *c1, const StatsCounter *c2) {
374  if (c1->getCategory() == c2->getCategory())
375  return c1->getName() <= c2->getName();
376  return c1->getCategory() < c2->getCategory();
377  }
378  };
379 
380  static ref<Statistics> m_instance;
381  std::vector<const StatsCounter *> m_counters;
382  std::vector<std::pair<std::string, std::string> > m_plugins;
383  ref<Mutex> m_mutex;
384 };
385 
387 
388 #endif /* __MITSUBA_CORE_STATISTICS_H_ */
Collects various rendering statistics and presents them in a human-readable form. ...
Definition: statistics.h:339
void incrementBase(size_t amount=1)
Increment the base counter by the specified amount (only for use with EPercentage/EAverage) ...
Definition: statistics.h:145
Simple unitless number, e.g. # of rays.
Definition: statistics.h:56
bool atomicCompareAndExchange(volatile int32_t *v, int32_t newValue, int32_t oldValue)
Atomically attempt to exchange a 32-bit integer with another value.
Definition: atomic.h:89
static void staticInitialization()
Initializes the built-in reference count debugger (if enabled)
void recordMinimum(size_t value)
When this is a minimum &quot;counter&quot;, this function records an observation of the quantity whose minimum ...
Definition: statistics.h:161
static bool isEnabled()
Check whether progress bars are enabled.
Definition: statistics.h:314
uint64_t getMinimum() const
Definition: statistics.h:235
#define MTS_EXPORT_CORE
Definition: getopt.h:29
EStatsType
Determines the multiples (e.g. 1000, 1024) and units of a StatsCounter.
Definition: statistics.h:55
void recordMaximum(size_t value)
When this is a maximum &quot;counter&quot;, this function records an observation of the quantity whose maximum ...
Definition: statistics.h:189
Minimum observed value of some quantity.
Definition: statistics.h:59
void reset()
Reset the stored counter values.
Definition: statistics.h:263
uint64_t getValue() const
Return the value of this counter as 64-bit unsigned integer.
Definition: statistics.h:228
const std::string & getName() const
Return the name of this counter.
Definition: statistics.h:214
#define MTS_NAMESPACE_BEGIN
Definition: platform.h:137
uint64_t getBase() const
Get the reference number (only used with the EPercentage/EAverage counter type)
Definition: statistics.h:254
uint64_t getMaximum() const
Definition: statistics.h:242
uint64_t value
Definition: statistics.h:80
void operator+=(size_t amount)
Increment the counter by the specified amount.
Definition: statistics.h:132
Counter data structure, which is suitable for ccNUMA/SMP machines.
Definition: statistics.h:73
Maximum observed value of some quantity.
Definition: statistics.h:60
static Statistics * getInstance()
Return the global stats collector instance.
Definition: statistics.h:342
#define NUM_COUNTERS_MASK
Bitmask for NUM_COUNTERS.
Definition: statistics.h:52
#define MTS_DECLARE_CLASS()
This macro must be used in the initial definition in classes that derive from Object.
Definition: class.h:158
Reference counting helper.
Definition: ref.h:40
Number of read/written/transferred bytes.
Definition: statistics.h:57
General-purpose progress reporter.
Definition: statistics.h:287
General-purpose statistics counter.
Definition: statistics.h:94
uint64_t operator++()
Increment the counter value by one.
Definition: statistics.h:112
Average value with respect to a base counter.
Definition: statistics.h:61
const std::string & getCategory() const
Return the category of this counter.
Definition: statistics.h:217
#define NUM_COUNTERS
Definition: statistics.h:49
long long getValue() const
Return the current value.
Definition: statistics.h:302
Parent of all Mitsuba classes.
Definition: object.h:38
#define PROGRESS_MSG_SIZE
Size (in characters) of the console-based progress message.
Definition: statistics.h:39
void finish()
Finish.
Definition: statistics.h:305
EStatsType getType() const
Return the type of this counter.
Definition: statistics.h:220
static void staticShutdown()
Free the memory taken by staticInitialization()
#define MTS_NAMESPACE_END
Definition: platform.h:138
Percentage with respect to a base counter.
Definition: statistics.h:58