demos/spectrum/3rdparty/fftreal/stopwatch/ClockCycleCounter.cpp
changeset 25 e24348a560a6
equal deleted inserted replaced
23:89e065397ea6 25:e24348a560a6
       
     1 /*****************************************************************************
       
     2 
       
     3         ClockCycleCounter.cpp
       
     4         Copyright (c) 2003 Laurent de Soras
       
     5 
       
     6 --- Legal stuff ---
       
     7 
       
     8 This library is free software; you can redistribute it and/or
       
     9 modify it under the terms of the GNU Lesser General Public
       
    10 License as published by the Free Software Foundation; either
       
    11 version 2.1 of the License, or (at your option) any later version.
       
    12 
       
    13 This library is distributed in the hope that it will be useful,
       
    14 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16 Lesser General Public License for more details.
       
    17 
       
    18 You should have received a copy of the GNU Lesser General Public
       
    19 License along with this library; if not, write to the Free Software
       
    20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    21 
       
    22 *Tab=3***********************************************************************/
       
    23 
       
    24 
       
    25 
       
    26 #if defined (_MSC_VER)
       
    27 	#pragma warning (1 : 4130) // "'operator' : logical operation on address of string constant"
       
    28 	#pragma warning (1 : 4223) // "nonstandard extension used : non-lvalue array converted to pointer"
       
    29 	#pragma warning (1 : 4705) // "statement has no effect"
       
    30 	#pragma warning (1 : 4706) // "assignment within conditional expression"
       
    31 	#pragma warning (4 : 4786) // "identifier was truncated to '255' characters in the debug information"
       
    32 	#pragma warning (4 : 4800) // "forcing value to bool 'true' or 'false' (performance warning)"
       
    33 	#pragma warning (4 : 4355) // "'this' : used in base member initializer list"
       
    34 #endif
       
    35 
       
    36 
       
    37 
       
    38 /*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
       
    39 
       
    40 #include	"ClockCycleCounter.h"
       
    41 
       
    42 #include	<cassert>
       
    43 
       
    44 
       
    45 
       
    46 namespace stopwatch
       
    47 {
       
    48 
       
    49 
       
    50 
       
    51 /*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
       
    52 
       
    53 
       
    54 
       
    55 /*
       
    56 ==============================================================================
       
    57 Name: ctor
       
    58 Description:
       
    59 	The first object constructed initialise global data. This first
       
    60 	construction may be a bit slow.
       
    61 Throws: Nothing
       
    62 ==============================================================================
       
    63 */
       
    64 
       
    65 ClockCycleCounter::ClockCycleCounter ()
       
    66 :	_start_time (0)
       
    67 ,	_state (0)
       
    68 ,	_best_score (-1)
       
    69 {
       
    70 	if (! _init_flag)
       
    71 	{
       
    72 		// Should be executed in this order
       
    73 		compute_clk_mul ();
       
    74 		compute_measure_time_total ();
       
    75 		compute_measure_time_lap ();
       
    76 
       
    77 		// Restores object state
       
    78 		_start_time = 0;
       
    79 		_state      = 0;
       
    80 		_best_score = -1;
       
    81 
       
    82 		_init_flag = true;
       
    83 	}
       
    84 }
       
    85 
       
    86 
       
    87 
       
    88 /*
       
    89 ==============================================================================
       
    90 Name: get_time_total
       
    91 Description:
       
    92 	Gives the time elapsed between the latest stop_lap() and start() calls.
       
    93 Returns:
       
    94 	The duration, in clock cycles.
       
    95 Throws: Nothing
       
    96 ==============================================================================
       
    97 */
       
    98 
       
    99 Int64	ClockCycleCounter::get_time_total () const
       
   100 {
       
   101 	const Int64		duration = _state - _start_time;
       
   102 	assert (duration >= 0);
       
   103 
       
   104 	const Int64		t = max (
       
   105 		duration - _measure_time_total,
       
   106 		static_cast <Int64> (0)
       
   107 	);
       
   108 
       
   109 	return (t * _clk_mul);
       
   110 }
       
   111 
       
   112 
       
   113 
       
   114 /*
       
   115 ==============================================================================
       
   116 Name: get_time_best_lap
       
   117 Description:
       
   118 	Gives the smallest time between two consecutive stop_lap() or between
       
   119 	the stop_lap() and start(). The value is reset by a call to start().
       
   120 	Call this function only after a stop_lap().
       
   121 	The time is amputed from the duration of the stop_lap() call itself.
       
   122 Returns:
       
   123 	The smallest duration, in clock cycles.
       
   124 Throws: Nothing
       
   125 ==============================================================================
       
   126 */
       
   127 
       
   128 Int64	ClockCycleCounter::get_time_best_lap () const
       
   129 {
       
   130 	assert (_best_score >= 0);
       
   131 
       
   132 	const Int64		t1 = max (
       
   133 		_best_score - _measure_time_lap,
       
   134 		static_cast <Int64> (0)
       
   135 	);
       
   136 	const Int64		t = min (t1, get_time_total ());
       
   137 
       
   138 	return (t * _clk_mul);
       
   139 }
       
   140 
       
   141 
       
   142 
       
   143 /*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
       
   144 
       
   145 
       
   146 
       
   147 /*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
       
   148 
       
   149 
       
   150 
       
   151 #if defined (__MACOS__)
       
   152 
       
   153 static inline double	stopwatch_ClockCycleCounter_get_time_s ()
       
   154 {
       
   155 	const Nanoseconds	ns = AbsoluteToNanoseconds (UpTime ());
       
   156 
       
   157 	return (ns.hi * 4294967296e-9 + ns.lo * 1e-9);
       
   158 }
       
   159 
       
   160 #endif	// __MACOS__
       
   161 
       
   162 
       
   163 
       
   164 /*
       
   165 ==============================================================================
       
   166 Name: compute_clk_mul
       
   167 Description:
       
   168 	This function, only for PowerPC/MacOS computers, computes the multiplier
       
   169 	required to deduce clock cycles from the internal counter.
       
   170 Throws: Nothing
       
   171 ==============================================================================
       
   172 */
       
   173 
       
   174 void	ClockCycleCounter::compute_clk_mul ()
       
   175 {
       
   176 	assert (! _init_flag);
       
   177 
       
   178 #if defined (__MACOS__)
       
   179 
       
   180 	long				clk_speed_mhz = CurrentProcessorSpeed ();
       
   181 	const Int64		clk_speed =
       
   182 		static_cast <Int64> (clk_speed_mhz) * (1000L*1000L);
       
   183 
       
   184 	const double	start_time_s = stopwatch_ClockCycleCounter_get_time_s ();
       
   185 	start ();
       
   186 
       
   187 	const double	duration = 0.01;	// Seconds
       
   188 	while (stopwatch_ClockCycleCounter_get_time_s () - start_time_s < duration)
       
   189 	{
       
   190 		continue;
       
   191 	}
       
   192 
       
   193 	const double	stop_time_s = stopwatch_ClockCycleCounter_get_time_s ();
       
   194 	stop ();
       
   195 
       
   196 	const double	diff_time_s = stop_time_s - start_time_s;
       
   197 	const double	nbr_cycles = diff_time_s * static_cast <double> (clk_speed);
       
   198 
       
   199 	const Int64		diff_time_c = _state - _start_time;
       
   200 	const double	clk_mul = nbr_cycles / static_cast <double> (diff_time_c);
       
   201 
       
   202 	_clk_mul = round_int (clk_mul);
       
   203 
       
   204 #endif	// __MACOS__
       
   205 }
       
   206 
       
   207 
       
   208 
       
   209 void	ClockCycleCounter::compute_measure_time_total ()
       
   210 {
       
   211 	start ();
       
   212 	spend_time ();
       
   213 
       
   214 	Int64				best_result = 0x7FFFFFFFL;	// Should be enough
       
   215 	long				nbr_tests = 100;
       
   216 	for (long cnt = 0; cnt < nbr_tests; ++cnt)
       
   217 	{
       
   218 		start ();
       
   219 		stop_lap ();
       
   220 		const Int64		duration = _state - _start_time;
       
   221 		best_result = min (best_result, duration);
       
   222 	}
       
   223 
       
   224 	_measure_time_total = best_result;
       
   225 }
       
   226 
       
   227 
       
   228 
       
   229 /*
       
   230 ==============================================================================
       
   231 Name: compute_measure_time_lap
       
   232 Description:
       
   233 	Computes the duration of one stop_lap() call and store it. It will be used
       
   234 	later to get the real duration of the measured operation (by substracting
       
   235 	the measurement duration).
       
   236 Throws: Nothing
       
   237 ==============================================================================
       
   238 */
       
   239 
       
   240 void	ClockCycleCounter::compute_measure_time_lap ()
       
   241 {
       
   242 	start ();
       
   243 	spend_time ();
       
   244 
       
   245 	long				nbr_tests = 10;
       
   246 	for (long cnt = 0; cnt < nbr_tests; ++cnt)
       
   247 	{
       
   248 		stop_lap ();
       
   249 		stop_lap ();
       
   250 		stop_lap ();
       
   251 		stop_lap ();
       
   252 	}
       
   253 
       
   254 	_measure_time_lap = _best_score;
       
   255 }
       
   256 
       
   257 
       
   258 
       
   259 void	ClockCycleCounter::spend_time ()
       
   260 {
       
   261 	const Int64		nbr_clocks = 500;	// Number of clock cycles to spend
       
   262 
       
   263 	const Int64		start = read_clock_counter ();
       
   264 	Int64				current;
       
   265 
       
   266 	do
       
   267 	{
       
   268 		current = read_clock_counter ();
       
   269 	}
       
   270 	while ((current - start) * _clk_mul < nbr_clocks);
       
   271 }
       
   272 
       
   273 
       
   274 
       
   275 Int64	ClockCycleCounter::_measure_time_total = 0;
       
   276 Int64	ClockCycleCounter::_measure_time_lap = 0;
       
   277 int	ClockCycleCounter::_clk_mul = 1;
       
   278 bool	ClockCycleCounter::_init_flag = false;
       
   279 
       
   280 
       
   281 }	// namespace stopwatch
       
   282 
       
   283 
       
   284 
       
   285 /*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/