• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MikkelSchubert / adapterremoval / #46

27 Nov 2024 03:10PM UTC coverage: 27.245% (+1.0%) from 26.244%
#46

push

travis-ci

MikkelSchubert
fix convenience executable make target

2609 of 9576 relevant lines covered (27.25%)

4268.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/benchmarking.cpp
1
/*************************************************************************\
2
 * AdapterRemoval - cleaning next-generation sequencing reads            *
3
 *                                                                       *
4
 * Copyright (C) 2024 by Mikkel Schubert - mikkelsch@gmail.com           *
5
 *                                                                       *
6
 * This program is free software: you can redistribute it and/or modify  *
7
 * it under the terms of the GNU General Public License as published by  *
8
 * the Free Software Foundation, either version 3 of the License, or     *
9
 * (at your option) any later version.                                   *
10
 *                                                                       *
11
 * This program 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         *
14
 * GNU General Public License for more details.                          *
15
 *                                                                       *
16
 * You should have received a copy of the GNU General Public License     *
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. *
18
\*************************************************************************/
19
#include "benchmarking.hpp" // for benchmark_toggles, benchmarker
20
#include "debug.hpp"        // for AR_REQUIRE
21
#include "logging.hpp"      // for log
22
#include "mathutils.hpp"    // for arithmetic_mean, standard_deviation
23
#include "simd.hpp"         // for supported
24
#include "strutils.hpp"     // for to_lower
25
#include <algorithm>        // for find, accumulate
26
#include <array>            // for array
27
#include <cmath>            // for round
28
#include <iomanip>          // for fixed, setsetprecision
29
#include <iostream>         // for cout
30
#include <numeric>          // for accumulate
31

32
namespace adapterremoval {
33

34
namespace {
35

36
//! Number of loops to perform prior to benchmarking as burn-in
37
const size_t BENCHMARK_BURN_IN = 1;
38
//! Benchmarks must be repeated at least this number of times
39
const size_t BENCHMARK_MIN_LOOPS = 10;
40
//! Benchmarks must be repeated at most this number of times
41
const size_t BENCHMARK_MAX_LOOPS = 1000;
42
//! Benchmarks must run for at this this number of nano-seconds
43
const double BENCHMARK_MIN_TIME_NS = 5'000'000'000;
44
//! Benchmark loops shorter than this number of nano-seconds cannot be measured
45
const double BENCHMARK_CUTOFF_TIME_NS = 10'000;
46
//! Number of NS between terminal updates
47
const size_t BENCHMARK_UPDATE_INTERVAL = 50'000'000;
48

49
} // namespace
50

51
benchmark_toggles::benchmark_toggles(string_vec keys)
×
52
  : m_toggles(std::move(keys))
×
53
  , m_enabled(m_toggles.size(), false)
×
54
  , m_defaults()
×
55
{
56
}
57

58
bool
59
benchmark_toggles::update_toggles(const string_vec& keys)
×
60
{
61
  bool any_errors = false;
×
62
  m_defaults = keys.empty();
×
63
  for (const auto& key : keys) {
×
64
    const auto it =
×
65
      std::find(m_toggles.begin(), m_toggles.end(), to_lower(key));
×
66

67
    if (it == m_toggles.end()) {
×
68
      log::error() << "Unknown benchmarking toggle '" << key << "'";
×
69
      any_errors = true;
×
70
    } else {
71
      m_enabled.at(it - m_toggles.begin()) = true;
×
72
    }
73
  }
74

75
  if (any_errors) {
×
76
    auto msg = log::error();
×
77
    msg << "Valid toggles are ";
×
78
    for (size_t i = 0; i < m_toggles.size() - 1; ++i) {
×
79
      msg << m_toggles.at(i) << ", ";
×
80
    }
81
    msg << " and " << m_toggles.back();
×
82
  }
83

84
  return !any_errors;
×
85
}
86

87
bool
88
benchmark_toggles::is_set(const std::string& key) const
×
89
{
90
  const auto it = std::find(m_toggles.begin(), m_toggles.end(), to_lower(key));
×
91

92
  AR_REQUIRE(it != m_toggles.end());
×
93
  return m_enabled.at(it - m_toggles.begin());
×
94
}
95

96
benchmarker::benchmarker(std::string desc, string_vec toggles)
×
97
  : m_description(std::move(desc))
×
98
  , m_toggles(std::move(toggles))
×
99
{
100
}
101

102
void
103
benchmarker::run_if_toggled(const benchmark_toggles& toggles)
×
104
{
105
  const auto s = enabled(toggles);
×
106
  if (s != strategy::skip) {
×
107
    run(s);
×
108
  }
109
}
110

111
/** Called before `setup` to perform any per batch setup */
112
void
113
benchmarker::setup() {};
×
114

115
strategy
116
benchmarker::enabled(const benchmark_toggles& toggles) const
×
117
{
118
  if (toggles.defaults()) {
×
119
    return strategy::benchmark;
120
  }
121

122
  for (const auto& toggle : m_toggles) {
×
123
    if (toggles.is_set(toggle)) {
×
124
      return strategy::benchmark;
×
125
    }
126
  }
127

128
  return m_required ? strategy::passthrough : strategy::skip;
×
129
}
130

131
void
132
benchmarker::run(const strategy s)
×
133
{
134
  static bool header = false;
135
  if (!header) {
×
136
    std::cout << "             Benchmark |       Min |      Mean |       Max | "
×
137
                 "SD (%) | Loops | Outliers"
×
138
              << std::endl;
×
139
    header = true;
×
140
  }
141

142
  if (s != strategy::passthrough) {
×
143
    log::cerr() << "\r\033[K" << std::setw(22) << m_description << " burn-in";
×
144

145
    for (size_t i = 1; i <= BENCHMARK_BURN_IN; ++i) {
×
146
      setup();
×
147
      execute();
×
148

149
      log::cerr() << ".";
×
150
    }
151
  } else {
152
    log::cerr() << "\r\033[K" << std::setw(22) << m_description << " (setup)";
×
153
  }
154

155
  size_t loops = 0;
156
  uint64_t next_update = 0;
157
  do {
×
158
    uint64_t elapsed =
×
159
      std::accumulate(m_durations.begin(), m_durations.end(), uint64_t());
×
160

161
    do {
×
162
      setup();
×
163
      const auto start = clock::now();
×
164
      execute();
×
165
      const auto duration = (clock::now() - start).count();
×
166

167
      loops++;
×
168
      elapsed += duration;
×
169
      m_durations.push_back(duration);
×
170

171
      if (elapsed >= next_update) {
×
172
        log::cerr() << "\r\033[K" << summarize(loops);
×
173
        next_update += BENCHMARK_UPDATE_INTERVAL;
×
174
      }
175
    } while (s == strategy::benchmark &&
×
176
             m_durations.size() < BENCHMARK_MAX_LOOPS &&
×
177
             (m_durations.size() < BENCHMARK_MIN_LOOPS ||
×
178
              (elapsed < BENCHMARK_MIN_TIME_NS &&
×
179
               elapsed / m_durations.size() >= BENCHMARK_CUTOFF_TIME_NS)));
×
180
  } while (s == strategy::benchmark && (loops < 2 * m_durations.size()) &&
×
181
           grubbs_test_prune(m_durations));
×
182

183
  log::cerr() << "\r\033[K";
×
184

185
  if (s != strategy::passthrough) {
×
186
    std::cout << summarize(loops) << std::endl;
×
187
  }
188
}
189

190
std::string
191
benchmarker::summarize(size_t loops) const
×
192
{
193
  const std::array<size_t, 7> COLUMN_WIDTHS{ 22, 9, 9, 9, 6, 5, 8 };
×
194
  std::array<std::string, COLUMN_WIDTHS.size()> values{
×
195
    m_description,
×
196
    "",
197
    "",
198
    "",
199
    "",
200
    std::to_string(m_durations.size()),
×
201
    std::to_string(loops - m_durations.size()),
×
202
  };
203

204
  if (!m_durations.empty()) {
×
205
    const auto min_max =
×
206
      std::minmax_element(m_durations.begin(), m_durations.end());
×
207
    const auto mean = arithmetic_mean(m_durations);
×
208

209
    values.at(1) = format_thousand_sep(*min_max.first / 1e3);
×
210
    values.at(2) = format_thousand_sep(std::round(mean / 1e3));
×
211
    values.at(3) = format_thousand_sep(*min_max.second / 1e3);
×
212

213
    if (m_durations.size() > 1) {
×
214
      const auto sd = standard_deviation(m_durations);
×
215
      values.at(4) = format_fraction(1e9 * sd, 1e7 * mean);
×
216
    }
217
  }
218

219
  std::ostringstream ss;
×
220
  for (size_t i = 0; i < values.size(); ++i) {
×
221
    if (i) {
×
222
      ss << " | ";
×
223
    }
224

225
    ss << std::setw(COLUMN_WIDTHS.at(i)) << values.at(i);
×
226
  }
227

228
  return ss.str();
×
229
}
230

231
} // namespace adapterremoval
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc