libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
hp_timer.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 20017 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 "hp_timer.hpp"
20 
21 #include <iomanip>
22 #include <iostream>
23 
24 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
25 
27 public:
28  using api_threading_traits=ppd::api_threading_traits<ppd::platform_api, ppd::heavyweight_threading>;
29 
30  scoped_thread_settings() noexcept(true) try
31  : old_priority(api_threading_traits::get_kernel_priority(api_threading_traits::get_current_thread())) {
32  api_threading_traits::set_kernel_priority(api_threading_traits::get_current_thread(), api_threading_traits::api_params_type::priority_type::time_critical);
33  } catch (...) {
34  // Ignore any errors...
35  }
36  ~scoped_thread_settings() noexcept(true) try {
37  api_threading_traits::set_kernel_priority(api_threading_traits::get_current_thread(), old_priority);
38  } catch (...) {
39  // Ignore any errors...
40  }
41 
42 private:
43  api_threading_traits::api_params_type::priority_type const old_priority;
44 };
45 
46 std::ostream &
47 cpu_timer::private_::operator<<(std::ostream &s, cpu_timer::private_::ticks_per_microsec_details const &tpm) {
48  s<<"min="<<std::setprecision(5)<<tpm.min<<"MHz, mean="<<tpm.mean<<"MHz, mean-ave. dev.="<<std::setprecision(2)<<100*tpm.mean_average_dev/tpm.mean<<"%, max="<<std::setprecision(5)<<tpm.max<<"Mhz";
49  return s;
50 }
51 
54  const constexpr unsigned num_reps=10u;
55  using samples_t=std ::array<double, num_reps>;
56  [[maybe_unused]] const scoped_thread_settings settings;
57  const auto ticks_per_microsec=[]() {
58  element_type e{};
59  const auto start_microsec=std::chrono::high_resolution_clock::now();
60  {
61  const out_of_order time(e);
62  std::this_thread::sleep_for(std::chrono::milliseconds(1));
63  }
64  const auto end_microsec=std::chrono::high_resolution_clock::now();
65  assert(end_microsec>start_microsec);
66  const std::chrono::duration<double, std::micro> microsec_dur=end_microsec-start_microsec;
67  return e/microsec_dur.count();
68  };
69  samples_t samples;
70  double min{std::numeric_limits<double>::max()};
71  double mean{};
72  double max{std::numeric_limits<double>::min()};
73  for (unsigned i=0; i<num_reps; ++i) {
74  samples[i]=ticks_per_microsec();
75  min=std::min(min, samples[i]);
76  if (i==0) {
77  mean=samples[i];
78  } else {
79  mean+=samples[i];
80  }
81  max=std::max(max, samples[i]);
82  }
83  mean/=num_reps;
84  const double mean_average_dev=std::accumulate(
85  samples.begin(),
86  samples.end(),
87  double{},
88  [&mean](auto const acc, auto const sample) {
89  return acc+std::abs(sample-mean);
90  }
91  )/num_reps;
92  return ticks_per_microsec_details{min, mean, max, mean_average_dev};
93 }
94 
95 } }