libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
CPUTicker.hpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2002 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 // TITLE:
19 // High-Resolution Counter Class.
20 //
21 // DESCRIPTION:
22 // This file declares a class the wraps the Pentium-specific time stamp counter.
23 // This counter has a resolution in terms of PCLKS (processor clocks) so it can
24 // be used for direct instruction timings.
25 //
26 // 1. The constructor can be time-expensive. It will throw an exception if the
27 // RDTSC instruction is not present.
28 // 2. The GetAndCalcCPUFrequency() function is also time-expensive, as this
29 // function dynamically re-calculates the CPU's core frequency.
30 // 3. Conversion from unsigned __int64 to double is not implemented in
31 // the MSVC++ v5.0 compiler, hence the GetTickCountUS() and GetTickCountS()
32 // operators. Also this is the reason for the operator-() function.
33 //
34 // This class has been tested to work on Pentium processors (at least P60's to
35 // P233 MMX's), Pentium Pro's and Pentium II's. It also works on AMD K6-233's.
36 //
37 // VERSION HISTORY:
38 // 26/3/96 1.0 Created.
39 // 16/7/97 2.0 Modified by P.J.Naughter, please see the source file for comments.
40 // Modified then by J.M.McGuiness.
41 // 22/10/97 3.0 Modified by J.M.McGuiness, made calling conventions explicitly to __fastcall.
42 // Please see the source file for more comments.
43 // 1/12/97 3.1 Modified to compile with MSVC++ v4.x and to ensure certain functions and structures are defined.
44 // 2/2/98 3.2 Updated the contact e-mail addresses.
45 // 12/5/99 3.21 Minor improvements to the interface functions.
46 // 25/2/2004 Removed MFC-isms, exception specifications and pointless comments.
47 
48 // The MSVC++ v4.x compiler doesn't support the ANSI C++ data type "bool".
49 // Versions 5.0 and greater do.
50 #if _MSC_VER < 1100
51  typedef BOOL bool;
52 #endif
53 
54 #include "../OnNT.hpp"
55 
56 namespace jmmcg { namespace NTUtils {
57 
58  class win_exception;
59 
60  class AFX_EXT_CLASS CPUTicker {
61  public:
63 
64  class CPUCountFn {
65  public:
66  __stdcall CPUCountFn(void) noexcept(true)
67  : GetCPUCount(OnNT() ? new GetCPUCountFnNT() : new GetCPUCountFn9X()) {
68  }
69  __stdcall ~CPUCountFn(void) noexcept(true) {
70  }
71 
72  unsigned __int64 __fastcall GetCount(void) const noexcept(true) {
73  return (*GetCPUCount)();
74  }
75 
76  private:
77  struct GetCPUCountFnNT {
78  virtual unsigned __int64 __fastcall operator()(void) const noexcept(true);
79  };
80  struct GetCPUCountFn9X : public GetCPUCountFnNT {
81  unsigned __int64 __fastcall operator()(void) const noexcept(true);
82  };
83 
85 
86  __stdcall CPUCountFn(const CPUCountFn &) noexcept(true);
87  CPUCountFn &operator=(const CPUCountFn &) noexcept(true);
88  };
89 
90  __stdcall CPUTicker(void);
91  __stdcall CPUTicker(const CPUTicker &) noexcept(true);
92  __stdcall ~CPUTicker(void);
93 
94  CPUTicker& __fastcall operator=(const CPUTicker &) noexcept(true);
95 
96  // Perform the actual measurement.
97  void __fastcall GetCPUCount(void) noexcept(true);
98 
99  // Accessors to the actual measured value.
100  double __fastcall GetTickCountAsSeconds(void) const {
101  return static_cast<double>(GetTickCountS())/freq;
102  }
103  unsigned __int64 __fastcall GetTickCountUS(void) const noexcept(true) {
104  return TickCount;
105  }
106  signed __int64 __fastcall GetTickCountS(void) const;
107 
108  /**
109  The following function will work out the processor clock frequency to a
110  specified accuracy determined by the target average deviation required.
111  Note that the worst average deviation of the result is less than 5MHz for
112  a mean frequency of 90MHz. So basically the target average deviation is
113  supplied only if you want a more accurate result, it won't let you get a
114  worse one. (Units are Hz.)
115 
116  (The average deviation is a better and more robust measure than it's cousin
117  the standard deviation of a quantity. The item determined by each is
118  essentially similar. See "Numerical Recipies", W.Press et al for more
119  details.)
120 
121  This function will run for a maximum of 20 seconds before giving up on
122  trying to improve the average deviation, with the average deviation
123  actually achieved replacing the supplied target value. Use "max_loops" to
124  change this. To improve the value the function converges to increase
125  "interval" (which is in units of ms, default value=1000ms).
126  */
127  const bool __fastcall GetAndCalcCPUFrequency(double &frequency,double &target_ave_dev,const unsigned long interval = 1000,const unsigned int max_loops =20);
128  void __fastcall GetCPUFrequency(double &frequency,double &target_ave_dev) const noexcept(true) {
129  frequency=freq;
131  }
132 
133  CPUTicker __fastcall operator-(const CPUTicker &) const;
134 
135  private:
136  const CPUCountFn counter;
137  unsigned __int64 TickCount;
138 
139  // Note: deviation and frequency are undefined until calculated,
140  // as we have no idea what they should be.
141  double deviation;
142  double freq;
143 
144  static bool __fastcall HasRDTSC(void) noexcept(true);
145  static bool __fastcall InterruptsOK(void) noexcept(true);
146  };
147 
148 } }