root/examples/timers.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. BOOST_AUTO_TEST_SUITE

   1 /******************************************************************************

   2 ** $Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/examples/timers.cpp 2217 2017-11-04 12:02:29Z jmmcg $

   3 **

   4 ** Copyright (c) 2015 by J.M.McGuiness, coder@hussar.me.uk

   5 **

   6 ** This library is free software; you can redistribute it and/or

   7 ** modify it under the terms of the GNU Lesser General Public

   8 ** License as published by the Free Software Foundation; either

   9 ** version 2.1 of the License, or (at your option) any later version.

  10 **

  11 ** This library is distributed in the hope that it will be useful,

  12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of

  13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU

  14 ** Lesser General Public License for more details.

  15 **

  16 ** You should have received a copy of the GNU Lesser General Public

  17 ** License along with this library; if not, write to the Free Software

  18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

  19 */
  20 
  21 #include "stdafx.h"
  22 
  23 #include "core/stats_output.hpp"
  24 
  25 #define BOOST_TEST_MODULE libjmmcg_tests
  26 #include <boost/test/included/unit_test.hpp>
  27 
  28 #include <boost/test/test_case_template.hpp>
  29 #include <boost/mpl/list.hpp>
  30 
  31 #include "core/ave_deviation_meter.hpp"
  32 #include "core/config.h"
  33 #include "core/hp_timer.hpp"
  34 
  35 #include <boost/chrono.hpp>
  36 
  37 #include <cstdint>
  38 #include <chrono>
  39 #include <iostream>
  40 
  41 #include <sys/time.h>
  42 #include <x86intrin.h>
  43 
  44 using timed_results_t=jmmcg::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 
  69 struct tester_gettimeofday {
  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 
  82 struct tester_clock_gettime_REALTIME {
  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 
  95 struct tester_clock_gettime_REALTIME_COARSE {
  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 
 108 struct tester_clock_gettime_MONOTONIC {
 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 
 121 struct tester_clock_gettime_MONOTONIC_COARSE {
 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 
 134 struct tester_clock_gettime_MONOTONIC_RAW {
 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 
 147 struct tester_clock_gettime_PROCESS_CPUTIME_ID {
 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 
 160 struct tester_clock_gettime_THREAD_CPUTIME_ID {
 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 
 173 struct tester_std_chrono_high_resolution_clock {
 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 
 184 struct tester_std_chrono_steady_clock {
 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 
 195 struct tester_std_chrono_system_clock {
 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 
 206 struct tester_boost_chrono_high_resolution_clock {
 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 
 217 struct tester_boost_chrono_steady_clock {
 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 
 228 struct tester_boost_chrono_system_clock {
 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,
 241         tester_rdtscp,
 242         tester_gettimeofday,
 243         tester_clock_gettime_REALTIME,
 244         tester_clock_gettime_REALTIME_COARSE,
 245         tester_clock_gettime_MONOTONIC,
 246         tester_clock_gettime_MONOTONIC_COARSE,
 247         tester_clock_gettime_MONOTONIC_RAW,
 248         tester_clock_gettime_PROCESS_CPUTIME_ID,
 249         tester_clock_gettime_THREAD_CPUTIME_ID,
 250         tester_std_chrono_high_resolution_clock,
 251         tester_std_chrono_steady_clock,
 252         tester_std_chrono_system_clock,
 253         tester_boost_chrono_high_resolution_clock,
 254         tester_boost_chrono_steady_clock,
 255         tester_boost_chrono_system_clock
 256 > timer_types;
 257 
 258 BOOST_AUTO_TEST_SUITE(timers)
 259 
 260 BOOST_AUTO_TEST_SUITE(performance, *boost::unit_test::fixture<jmmcg::stats_to_csv::wrapper>(std::string("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                 JMMCG_SYSTEM<<", "
 272                 JMMCG_SYSTEM_PROCESSOR<<", "
 273                 JMMCG_CXX_COMPILER_ID<<", "
 274                 JMMCG_CXX_COMPILER_VERSION<<", ";
 275 #ifdef DEBUG
 276         std::cout<<"DEBUG"<<std::endl;
 277 #endif
 278 #ifdef NDEBUG
 279         std::cout<<"RELEASE"<<std::endl;
 280 #endif
 281 
 282 #ifdef JMMCG_PERFORMANCE_TESTS
 283         const std::size_t num_loops=500000;
 284         const unsigned short loops_for_conv=500;
 285 #else
 286         const std::size_t num_loops=10;
 287         const unsigned short loops_for_conv=5;
 288 #endif
 289         const double perc_conv_estimate=5.0;
 290 
 291         const std::pair<timed_results_t, bool> timed_results(jmmcg::compute_average_deviation<timed_results_t::value_type>(
 292                 perc_conv_estimate,
 293                 loops_for_conv,
 294                 []() {
 295                         typename test::result_type time=typename test::result_type();
 296                         jmmcg::cpu_timer::element_type time_to_measure;
 297                         {
 298                                 jmmcg::cpu_timer::out_of_order timer(time_to_measure);
 299                                 for (unsigned i=0; i<num_loops; ++i) {
 300                                         time+=test::result();
 301                                 }
 302                         }
 303                         BOOST_CHECK_GT(time_to_measure, 0U);
 304                         return static_cast<timed_results_t::value_type>(time_to_measure)/num_loops;
 305                 }
 306         ));
 307         std::cout<<test::name<<" time in CPU ticks="<<timed_results.first<<std::endl;
 308 #ifdef JMMCG_PERFORMANCE_TESTS
 309         jmmcg::stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
 310         BOOST_CHECK(!timed_results.second);
 311 #endif
 312 }
 313 
 314 BOOST_AUTO_TEST_SUITE_END()
 315 
 316 BOOST_AUTO_TEST_SUITE_END()

/* [<][>][^][v][top][bottom][index][help] */