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

MikkelSchubert / adapterremoval / #45

20 Sep 2024 06:49PM UTC coverage: 26.244% (-49.2%) from 75.443%
#45

push

travis-ci

web-flow
attempt to fix coveralls run

2458 of 9366 relevant lines covered (26.24%)

4362.23 hits per line

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

0.0
/src/progress.cpp
1
/*************************************************************************\
2
 * AdapterRemoval - cleaning next-generation sequencing reads            *
3
 *                                                                       *
4
 * Copyright (C) 2011 by Stinus Lindgreen - stinus@binf.ku.dk            *
5
 * Copyright (C) 2014 by Mikkel Schubert - mikkelsch@gmail.com           *
6
 *                                                                       *
7
 * This program is free software: you can redistribute it and/or modify  *
8
 * it under the terms of the GNU General Public License as published by  *
9
 * the Free Software Foundation, either version 3 of the License, or     *
10
 * (at your option) any later version.                                   *
11
 *                                                                       *
12
 * This program is distributed in the hope that it will be useful,       *
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15
 * GNU General Public License for more details.                          *
16
 *                                                                       *
17
 * You should have received a copy of the GNU General Public License     *
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. *
19
\*************************************************************************/
20
#include "progress.hpp"
21
#include "debug.hpp"    // for AR_FAIL
22
#include "logging.hpp"  // for info, log_stream, cerr
23
#include "strutils.hpp" // for format_rough_number, format_thousand_sep
24
#include <chrono>       // for microseconds
25
#include <iomanip>      // for operator<<, setfill, setw
26
#include <sstream>      // for operator<<, basic_ostream, ostringstream
27
#include <string>       // for string, operator<<, basic_string, char_traits
28
#include <vector>       // for vector
29

30
namespace adapterremoval {
31

32
namespace {
33
//! Print progress report every N read
34
const size_t REPORT_EVERY_NTH_READ = 1e6;
35
//! Print an updated progress report every S seconds
36
const size_t REPORT_EVERY_NTH_LOOP = 10;
37
//! Increment the spinner every time-unit
38
const auto SPIN_EVERY = std::chrono::microseconds(100000);
39

40
std::string
41
format_time(double seconds)
×
42
{
43
  std::ostringstream stream;
×
44
  stream.precision(1);
×
45
  stream << std::setfill('0');
×
46

47
  if (seconds > 60 * 60) {
×
48
    stream << static_cast<size_t>(seconds) / (60LU * 60) << ":";
×
49
    stream << std::setw(2);
×
50
  }
51

52
  if (seconds > 60) {
×
53
    stream << (static_cast<size_t>(seconds) % (60LU * 60)) / 60 << ":";
×
54
    stream << std::setw(4) << std::setfill('0');
×
55
  }
56

57
  stream << std::fixed << (static_cast<size_t>(seconds * 100) % 6000) / 100.0
×
58
         << "s";
×
59

60
  return stream.str();
×
61
}
62

63
std::string
64
format_progress(size_t reads,
×
65
                double seconds,
66
                double rate,
67
                bool finalize = false)
68
{
69
  std::ostringstream ss;
×
70

71
  if (finalize) {
×
72
    ss << "Processed " << format_thousand_sep(reads) << " reads in "
×
73
       << format_time(seconds) << "; " << format_rough_number(rate)
×
74
       << " reads/s on average";
×
75
  } else {
76
    ss << "Processed " << format_rough_number(reads) << " reads in "
×
77
       << format_time(seconds) << "; " << format_rough_number(rate)
×
78
       << " reads/s";
×
79
  }
80

81
  return ss.str();
×
82
}
83

84
} // namespace
85

86
progress_timer::progress_timer(progress_type type)
×
87
  : m_type(type)
×
88
{
89
  start();
×
90
}
91

92
progress_timer::~progress_timer()
×
93
{
94
  stop();
×
95
}
96

97
void
98
progress_timer::increment(size_t inc)
×
99
{
100
  switch (m_type) {
×
101
    case progress_type::none: {
×
102
      m_total += inc;
×
103
      break;
×
104
    }
105

106
    case progress_type::simple: {
×
107
      m_total += inc;
×
108
      m_current += inc;
×
109

110
      if (m_current >= REPORT_EVERY_NTH_READ) {
×
111
        const double current_time = m_timer.duration();
×
112
        const double rate = m_current / (current_time - m_last_time);
×
113
        log::info() << format_progress(m_total, m_timer.duration(), rate);
×
114

115
        m_current = 0;
×
116
        m_last_time = current_time;
×
117
      }
118

119
      break;
120
    }
121

122
    case progress_type::spinner: {
×
123
      std::unique_lock<std::mutex> lock(m_lock);
×
124

125
      m_total += inc;
×
126
      break;
×
127
    }
128

129
    default:
×
130
      AR_FAIL("invalid progress report type");
×
131
  }
132
}
133

134
void
135
progress_timer::finalize()
×
136
{
137
  stop();
×
138

139
  const double rate = m_total / m_timer.duration();
×
140
  log::info() << format_progress(m_total, m_timer.duration(), rate, true);
×
141
}
142

143
void
144
progress_timer::start()
×
145
{
146
  // TODO: Hide/show cursor with "\033[?25l" / "\033[?25h"?
147
  if (m_type == progress_type::spinner && !m_spinner.joinable()) {
×
148
    m_spinning = true;
×
149
    m_spinner = std::thread(&progress_timer::loop, this);
×
150
  }
151
}
152

153
void
154
progress_timer::loop()
×
155
{
156
  double last_time = 0;
×
157
  size_t last_reads = 0;
×
158

159
  const std::vector<std::string> symbols = { "⠙", "⠸", "⢰", "⣠",
×
160
                                             "⣄", "⡆", "⠇", "⠋" };
×
161
  auto symbol_it = symbols.begin();
×
162
  std::string last_message;
×
163

164
  for (size_t loop = 0;; loop++) {
×
165
    std::this_thread::sleep_for(SPIN_EVERY);
×
166

167
    double current_time = 0;
×
168
    size_t current_reads = 0;
×
169

170
    {
×
171
      std::unique_lock<std::mutex> lock(m_lock);
×
172
      if (m_spinning) {
×
173
        current_time = m_timer.duration();
×
174
        current_reads = m_total;
×
175
      } else {
176
        break;
177
      }
178
    }
179

180
    if (loop % REPORT_EVERY_NTH_LOOP == 0) {
×
181
      const double rate =
×
182
        (current_reads - last_reads) / (current_time - last_time);
×
183

184
      last_message = format_progress(current_reads, current_time, rate);
×
185
      last_reads = current_reads;
×
186
      last_time = current_time;
×
187
    }
188

189
    log::cerr().transient() << *symbol_it++ << " " << last_message;
×
190

191
    if (symbol_it == symbols.end()) {
×
192
      symbol_it = symbols.begin();
×
193
    }
194
  }
195
}
196

197
void
198
progress_timer::stop()
×
199
{
200
  if (m_spinner.joinable()) {
×
201
    {
×
202
      std::unique_lock<std::mutex> lock(m_lock);
×
203
      m_spinning = false;
×
204
    }
205

206
    m_spinner.join();
×
207
  }
208
}
209

210
} // 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