Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v31r0 (aeb156f0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
CPUCrunchSvc.cpp
Go to the documentation of this file.
1 #include "CPUCrunchSvc.h"
2 
5 
6 #include <sys/times.h>
7 #include <tbb/tick_count.h>
8 
10 
11 #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
12 #define DEBUG_MSG ON_DEBUG debug()
13 
14 #define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
15 #define VERBOSE_MSG ON_VERBOSE verbose()
16 
17 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
18 
20 
21 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22 
24  debug() << "initialize" << endmsg;
25 
26  if ( base_class::initialize().isFailure() ) {
27  error() << "Error initializing base class" << endmsg;
28  return StatusCode::FAILURE;
29  }
30 
31  calibrate();
32 
33  return StatusCode::SUCCESS;
34 }
35 
36 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
37 
38 /*
39 Calibrate the crunching finding the right relation between max number to be searched and time spent.
40 The relation is a sqrt for times greater than 10^-4 seconds.
41 */
43  if ( m_niters_vect.value().size() == 0 ) {
44  m_niters_vect = {0, 500, 600, 700, 800, 1000, 1300, 1600, 2000, 2300,
45  2600, 3000, 3300, 3500, 3900, 4200, 5000, 6000, 8000, 10000,
46  12000, 15000, 17000, 20000, 25000, 30000, 35000, 40000, 50000, 60000};
47  if ( !m_shortCalib ) {
48  m_niters_vect.value().push_back( 80000 );
49  m_niters_vect.value().push_back( 100000 );
50  m_niters_vect.value().push_back( 150000 );
51  m_niters_vect.value().push_back( 200000 );
52  }
53  }
54 
55  if ( m_niters_vect.value().at( 0 ) != 0 ) {
56  warning() << "NIterationsVect[0]= " << m_niters_vect.value().at( 0 ) << " but needs to be zero. resetting it."
57  << endmsg;
58  m_niters_vect.value().at( 0 ) = 0;
59  }
60 
61  m_times_vect.resize( m_niters_vect.value().size() );
62  m_times_vect.at( 0 ) = 0;
63 
64  const unsigned int minCalibTime_us = m_minCalibTime * 1000;
65 
66  // warm it up by doing 20k iterations
67  findPrimes( 20000 );
68 
69  for ( int irun = 0; irun < m_numCalibRuns; ++irun ) {
70 
71  debug() << "Starting calibration run " << irun + 1 << " ..." << endmsg;
72  for ( unsigned int i = 1; i < m_niters_vect.value().size(); ++i ) {
73  unsigned int niters = m_niters_vect.value().at( i );
74  unsigned int trials = 30;
75  do {
76  auto start_cali = tbb::tick_count::now();
77  findPrimes( niters );
78  auto stop_cali = tbb::tick_count::now();
79  auto deltat = ( stop_cali - start_cali ).seconds();
80  m_times_vect.at( i ) = deltat * 1000000; // in microseconds
81  debug() << " Calibration: # iters = " << niters << " => " << m_times_vect.at( i ) << " us" << endmsg;
82  trials--;
83  } while ( trials > 0 && m_times_vect.at( i ) < m_times_vect.at( i - 1 ) ); // make sure that they are monotonic
84 
85  if ( i == m_niters_vect.value().size() - 1 && minCalibTime_us != 0 ) {
86  if ( m_times_vect.at( i ) < minCalibTime_us ) {
87  debug() << " increasing calib vect with " << int( m_niters_vect.value().back() * 1.2 )
88  << " iterations to reach min calib time of " << m_minCalibTime.value() << " ms " << endmsg;
89  m_niters_vect.value().push_back( int( m_niters_vect.value().back() * 1.2 ) );
90  m_times_vect.push_back( 0. );
91  }
92  }
93  }
94  }
95  if ( m_corrFact != 1. ) {
96  debug() << "Adjusting times with correction factor " << m_corrFact.value() << endmsg;
97  for ( auto& t : m_times_vect ) { t = t * m_corrFact; }
98  }
99  debug() << "Calibration finished!" << endmsg;
100 }
101 
102 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
103 
105 
106  unsigned int smaller_i = 0;
107  double time = 0.;
108  bool found = false;
109  double corrRuntime = runtime.count(); // * m_corrFact;
110  // We know that the first entry is 0, so we start to iterate from 1
111  for ( unsigned int i = 1; i < m_times_vect.size(); i++ ) {
112  time = m_times_vect.at( i );
113  if ( time > corrRuntime ) {
114  smaller_i = i - 1;
115  found = true;
116  break;
117  }
118  }
119 
120  // Case 1: we are outside the interpolation range, we take the last 2 points
121  if ( not found ) smaller_i = m_times_vect.size() - 2;
122 
123  // Case 2: we maeke a linear interpolation
124  // y=mx+q
125  const auto x0 = m_times_vect.at( smaller_i );
126  const auto x1 = m_times_vect.at( smaller_i + 1 );
127  const auto y0 = m_niters_vect.value().at( smaller_i );
128  const auto y1 = m_niters_vect.value().at( smaller_i + 1 );
129  const double m = (double)( y1 - y0 ) / (double)( x1 - x0 );
130  const double q = y0 - m * x0;
131 
132  const unsigned int nCaliIters = m * corrRuntime + q;
133 
134  VERBOSE_MSG << "x0: " << x0 << " x1: " << x1 << " y0: " << y0 << " y1: " << y1 << " m: " << m << " q: " << q
135  << " itr: " << nCaliIters << endmsg;
136 
137  return nCaliIters;
138 }
139 
140 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
141 
142 void CPUCrunchSvc::findPrimes( const unsigned int n_iterations ) const {
143  // Flag to trigger the allocation
144  bool is_prime;
145 
146  // Let's prepare the material for the allocations
147  unsigned int primes_size = 1;
148  unsigned long* primes = new unsigned long[primes_size];
149  primes[0] = 2;
150 
151  unsigned long i = 2;
152 
153  // Loop on numbers
154  for ( unsigned long int iiter = 0; iiter < n_iterations; iiter++ ) {
155  // Once at max, it returns to 0
156  i += 1;
157 
158  // Check if it can be divided by the smaller ones
159  is_prime = true;
160  for ( unsigned long j = 2; j < i && is_prime; ++j ) {
161  if ( i % j == 0 ) is_prime = false;
162  } // end loop on numbers < than tested one
163 
164  if ( is_prime ) {
165  // copy the array of primes (INEFFICIENT ON PURPOSE!)
166  unsigned int new_primes_size = 1 + primes_size;
167  unsigned long* new_primes = new unsigned long[new_primes_size];
168 
169  for ( unsigned int prime_index = 0; prime_index < primes_size; prime_index++ ) {
170  new_primes[prime_index] = primes[prime_index];
171  }
172  // attach the last prime
173  new_primes[primes_size] = i;
174 
175  // Update primes array
176  delete[] primes;
177  primes = new_primes;
178  primes_size = new_primes_size;
179  } // end is prime
180 
181  } // end of while loop
182 
183  // Fool Compiler optimisations:
184  for ( unsigned int prime_index = 0; prime_index < primes_size; prime_index++ )
185  if ( primes[prime_index] == 4 )
186  debug() << "This does never happen, but it's necessary too fool aggressive compiler optimisations!" << endmsg;
187 
188  delete[] primes;
189 }
190 
191 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
192 
193 // Translate the required crunch time into interations, and do it
195 
196  const unsigned int niters = getNCaliIters( crunchtime );
197 
198  auto start_cali = tbb::tick_count::now();
199  findPrimes( niters );
200  auto stop_cali = tbb::tick_count::now();
201 
202  std::chrono::milliseconds actual( int( 1000 * ( stop_cali - start_cali ).seconds() ) );
203 
204  DEBUG_MSG << "crunch for " << crunchtime.count() << " ms == " << niters << " iter. actual time: " << actual.count()
205  << " ms. ratio: " << float( actual.count() ) / crunchtime.count() << endmsg;
206 
207  return actual;
208 }
unsigned int getNCaliIters(std::chrono::microseconds runtime) const
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
Gaudi::Property< unsigned int > m_minCalibTime
Definition: CPUCrunchSvc.h:35
void findPrimes(unsigned int) const
constexpr static const auto SUCCESS
Definition: StatusCode.h:85
T resize(T...args)
STL class.
#define DECLARE_COMPONENT(type)
T at(T...args)
T push_back(T...args)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
#define VERBOSE_MSG
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:50
constexpr double m
Definition: SystemOfUnits.h:92
Gaudi::Property< bool > m_shortCalib
Definition: CPUCrunchSvc.h:34
Gaudi::Property< float > m_corrFact
Definition: CPUCrunchSvc.h:38
void calibrate()
Gaudi::Property< int > m_numCalibRuns
Definition: CPUCrunchSvc.h:37
T size(T...args)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
constexpr static const auto FAILURE
Definition: StatusCode.h:86
virtual StatusCode initialize() override
std::vector< unsigned int > m_times_vect
Definition: CPUCrunchSvc.h:30
CPUCrunchSvc(const std::string &name, ISvcLocator *svc)
std::chrono::milliseconds crunch_for(const std::chrono::milliseconds &crunchtime) const override
#define DEBUG_MSG
Gaudi::Property< std::vector< unsigned int > > m_niters_vect
Definition: CPUCrunchSvc.h:32
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:192