libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
timers.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2015 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 
19 #include "stdafx.h"
20 
21 #define BOOST_TEST_MODULE libjmmcg_tests
22 #include <boost/test/included/unit_test.hpp>
23 
24 #include <boost/mpl/list.hpp>
25 
26 #include "core/ave_deviation_meter.hpp"
27 #include "core/config.h"
28 #include "core/hp_timer.hpp"
29 #include "core/stats_output.hpp"
30 
31 #include <boost/chrono.hpp>
32 
33 #include <cstdint>
34 #include <chrono>
35 #include <iostream>
36 
37 #include <sys/time.h>
38 #if defined(i386) || defined(__i386__) || defined(__x86_64__)
39 # include <x86intrin.h>
40 #endif
41 
42 using namespace libjmmcg;
43 
44 using timed_results_t=ave_deviation_meter<double>;
45 
46 struct tester_rdtsc {
47  using result_type=unsigned long long;
48 
49  static constexpr char const name[]="__rdtsc";
50 
51  static result_type result() {
52  return __rdtsc();
53  }
54 };
55 constexpr char const tester_rdtsc::name[];
56 
57 struct tester_rdtscp {
58  using result_type=unsigned long long;
59 
60  static constexpr char const name[]="__rdtscp";
61 
62  static result_type result() {
63  unsigned int cpuid;
64  return __rdtscp(&cpuid);
65  }
66 };
67 constexpr char const tester_rdtscp::name[];
68 
70  using result_type=unsigned long long;
71 
72  static constexpr char const name[]="gettimeofday";
73 
74  static result_type result() {
75  timeval tv;
76  gettimeofday(&tv, nullptr);
77  return tv.tv_usec;
78  }
79 };
80 constexpr char const tester_gettimeofday::name[];
81 
83  using result_type=unsigned long long;
84 
85  static constexpr char const name[]="clock_gettime(REALTIME)";
86 
87  static result_type result() {
88  timespec tv;
89  clock_gettime(CLOCK_REALTIME, &tv);
90  return tv.tv_nsec;
91  }
92 };
93 constexpr char const tester_clock_gettime_REALTIME::name[];
94 
96  using result_type=unsigned long long;
97 
98  static constexpr char const name[]="clock_gettime(REALTIME_COARSE)";
99 
100  static result_type result() {
101  timespec tv;
102  clock_gettime(CLOCK_REALTIME_COARSE, &tv);
103  return tv.tv_nsec;
104  }
105 };
106 constexpr char const tester_clock_gettime_REALTIME_COARSE::name[];
107 
109  using result_type=unsigned long long;
110 
111  static constexpr char const name[]="clock_gettime(MONOTONIC)";
112 
113  static result_type result() {
114  timespec tv;
115  clock_gettime(CLOCK_MONOTONIC, &tv);
116  return tv.tv_nsec;
117  }
118 };
119 constexpr char const tester_clock_gettime_MONOTONIC::name[];
120 
122  using result_type=unsigned long long;
123 
124  static constexpr char const name[]="clock_gettime(MONOTONIC_COARSE)";
125 
126  static result_type result() {
127  timespec tv;
128  clock_gettime(CLOCK_MONOTONIC_COARSE, &tv);
129  return tv.tv_nsec;
130  }
131 };
132 constexpr char const tester_clock_gettime_MONOTONIC_COARSE::name[];
133 
135  using result_type=unsigned long long;
136 
137  static constexpr char const name[]="clock_gettime(MONOTONIC_RAW)";
138 
139  static result_type result() {
140  timespec tv;
141  clock_gettime(CLOCK_MONOTONIC_RAW, &tv);
142  return tv.tv_nsec;
143  }
144 };
145 constexpr char const tester_clock_gettime_MONOTONIC_RAW::name[];
146 
148  using result_type=unsigned long long;
149 
150  static constexpr char const name[]="clock_gettime(PROCESS_CPUTIME_ID)";
151 
152  static result_type result() {
153  timespec tv;
154  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tv);
155  return tv.tv_nsec;
156  }
157 };
158 constexpr char const tester_clock_gettime_PROCESS_CPUTIME_ID::name[];
159 
161  using result_type=unsigned long long;
162 
163  static constexpr char const name[]="clock_gettime(THREAD_CPUTIME_ID)";
164 
165  static result_type result() {
166  timespec tv;
167  clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tv);
168  return tv.tv_nsec;
169  }
170 };
171 constexpr char const tester_clock_gettime_THREAD_CPUTIME_ID::name[];
172 
174  using result_type=unsigned long long;
175 
176  static constexpr char const name[]="std::chrono::high_resolution_clock";
177 
178  static result_type result() {
179  return std::chrono::high_resolution_clock::now().time_since_epoch().count();
180  }
181 };
182 constexpr char const tester_std_chrono_high_resolution_clock::name[];
183 
185  using result_type=unsigned long long;
186 
187  static constexpr char const name[]="std::chrono::steady_clock";
188 
189  static result_type result() {
190  return std::chrono::steady_clock::now().time_since_epoch().count();
191  }
192 };
193 constexpr char const tester_std_chrono_steady_clock::name[];
194 
196  using result_type=unsigned long long;
197 
198  static constexpr char const name[]="std::chrono::system_clock";
199 
200  static result_type result() {
201  return std::chrono::system_clock::now().time_since_epoch().count();
202  }
203 };
204 constexpr char const tester_std_chrono_system_clock::name[];
205 
207  using result_type=unsigned long long;
208 
209  static constexpr char const name[]="boost::chrono::high_resolution_clock";
210 
211  static result_type result() {
212  return boost::chrono::high_resolution_clock::now().time_since_epoch().count();
213  }
214 };
215 constexpr char const tester_boost_chrono_high_resolution_clock::name[];
216 
218  using result_type=unsigned long long;
219 
220  static constexpr char const name[]="boost::chrono::steady_clock";
221 
222  static result_type result() {
223  return boost::chrono::steady_clock::now().time_since_epoch().count();
224  }
225 };
226 constexpr char const tester_boost_chrono_steady_clock::name[];
227 
229  using result_type=unsigned long long;
230 
231  static constexpr char const name[]="boost::chrono::system_clock";
232 
233  static result_type result() {
234  return boost::chrono::system_clock::now().time_since_epoch().count();
235  }
236 };
237 constexpr char const tester_boost_chrono_system_clock::name[];
238 
239 typedef boost::mpl::list<
240  tester_rdtsc,
257 
258 BOOST_AUTO_TEST_SUITE(timers)
259 
260 BOOST_AUTO_TEST_SUITE(performance, *stats_to_csv::make_fixture("timers.csv"))
261 
262 /**
263  \test <a href="./examples/timers.svg">Graph</a> of performance results for the various timer functions.
264  ==========================================================================================
265  Results for 500000 repetitions.
266  Note that accurate timings should follow the recommendations in <a href="https://www-ssl.intel.com/content/www/us/en/embedded/training/ia-32-ia-64-benchmark-code-execution-paper.html">How to Benchmark Code Execution Times on Intel (c) IA-32 and IA-64 Instruction Set Architectures</a> and note that RDTSC is stable across processors, see section 17.14.1 of the <a href="https://www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3b-part-2-manual.pdf">Intel (c) 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide, Part 2</a>, as long as "tsc" is listed in "/sys/devices/system/clocksource/clocksource0/available_clocksource".
267 */
268 BOOST_AUTO_TEST_CASE_TEMPLATE(time, test, timer_types)
269 {
270  std::cout<<
271  LIBJMMCG_SYSTEM ", "
276 
277 #ifdef JMMCG_PERFORMANCE_TESTS
278  const std::size_t num_loops=500000;
279  const unsigned short loops_for_conv=500;
280 #else
281  const std::size_t num_loops=10;
282  const unsigned short loops_for_conv=5;
283 #endif
284  const double perc_conv_estimate=5.0;
285 
286  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
287  perc_conv_estimate,
288  loops_for_conv,
289  []() {
290  typename test::result_type time=typename test::result_type();
291  cpu_timer::element_type time_to_measure;
292  {
293  cpu_timer::out_of_order timer(time_to_measure);
294  for (unsigned i=0; i<num_loops; ++i) {
295  time+=test::result();
296  }
297  }
298  BOOST_CHECK_GT(time_to_measure, 0U);
299  return static_cast<timed_results_t::value_type>(time_to_measure)/num_loops;
300  }
301  ));
302  std::cout<<test::name<<" time in CPU ticks="<<timed_results.first<<std::endl;
303 #ifdef JMMCG_PERFORMANCE_TESTS
304  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
305  BOOST_CHECK(!timed_results.second);
306 #endif
307 }
308 
309 BOOST_AUTO_TEST_SUITE_END()
310 
311 BOOST_AUTO_TEST_SUITE_END()