Skip to content

Commit 576c605

Browse files
committed
Extract Runner class
1 parent 8280d34 commit 576c605

File tree

6 files changed

+318
-184
lines changed

6 files changed

+318
-184
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ add_library(base_objects OBJECT
9393
src/base/processing/StepsLatencyEstimator.cpp
9494
src/base/reports/JsonReporter.cpp
9595
src/base/reports/TextReporter.cpp
96+
src/base/run/Runner.cpp
9697
)
9798

9899
add_dependencies(base_objects

src/base/core/Config.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,23 @@
66
#include "core/Time.hpp"
77

88
#include <cstdlib>
9+
#include <string>
910

1011
namespace signal_estimator {
1112

1213
struct Config {
14+
// operation mode
15+
std::string mode { "latency_corr" };
16+
17+
// report format
18+
std::string report_format { "text" };
19+
20+
// device names
21+
std::string output_dev, input_dev;
22+
23+
// dump files
24+
std::string output_dump, input_dump;
25+
1326
// number of pre-allocated frames in frame pool
1427
size_t frame_pool_size { 128 };
1528

src/base/io/AlsaUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ void alsa_close(snd_pcm_t* pcm) {
224224
int err = 0;
225225

226226
if ((err = snd_pcm_close(pcm)) < 0) {
227-
se_log_error("can't close alsa device: snd_pcm_close(): {}", snd_strerror(err));
227+
se_log_warn("can't close alsa device: snd_pcm_close(): {}", snd_strerror(err));
228228
}
229229
}
230230

src/base/run/Runner.cpp

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Copyright (c) Signal Estimator authors
2+
// Licensed under MIT
3+
4+
#include "run/Runner.hpp"
5+
#include "core/Log.hpp"
6+
#include "core/Realtime.hpp"
7+
#include "dumps/AsyncDumper.hpp"
8+
#include "dumps/CsvDumper.hpp"
9+
#include "io/AlsaReader.hpp"
10+
#include "io/AlsaWriter.hpp"
11+
#include "processing/ContinuousGenerator.hpp"
12+
#include "processing/CorrelationLatencyEstimator.hpp"
13+
#include "processing/Impulse.hpp"
14+
#include "processing/ImpulseGenerator.hpp"
15+
#include "processing/LossEstimator.hpp"
16+
#include "processing/StepsGenerator.hpp"
17+
#include "processing/StepsLatencyEstimator.hpp"
18+
#include "reports/JsonReporter.hpp"
19+
#include "reports/TextReporter.hpp"
20+
21+
namespace signal_estimator {
22+
23+
Runner::Runner(const Config& config)
24+
: config_(config) {
25+
}
26+
27+
Runner::~Runner() {
28+
stop();
29+
wait();
30+
}
31+
32+
bool Runner::failed() const {
33+
return fail_;
34+
}
35+
36+
bool Runner::start() {
37+
{
38+
auto alsa_writer = std::make_unique<AlsaWriter>();
39+
// may update config
40+
if (!alsa_writer->open(config_, config_.output_dev.c_str())) {
41+
fail_ = true;
42+
return false;
43+
}
44+
output_writer_ = std::move(alsa_writer);
45+
}
46+
47+
{
48+
auto alsa_reader = std::make_unique<AlsaReader>();
49+
// may update config
50+
if (!alsa_reader->open(config_, config_.input_dev.c_str())) {
51+
fail_ = true;
52+
return false;
53+
}
54+
input_reader_ = std::move(alsa_reader);
55+
}
56+
57+
if (!config_.output_dump.empty()) {
58+
auto csv_dumper = std::make_unique<CsvDumper>(config_);
59+
if (!csv_dumper->open(config_.output_dump.c_str())) {
60+
fail_ = true;
61+
return false;
62+
}
63+
output_dumper_ = std::move(csv_dumper);
64+
}
65+
66+
if (!config_.input_dump.empty()) {
67+
auto csv_dumper = std::make_unique<CsvDumper>(config_);
68+
if (!csv_dumper->open(config_.input_dump.c_str())) {
69+
fail_ = true;
70+
return false;
71+
}
72+
input_dumper_ = std::move(csv_dumper);
73+
}
74+
75+
if (output_dumper_) {
76+
output_dumper_ = std::make_unique<AsyncDumper>(std::move(output_dumper_));
77+
}
78+
79+
if (input_dumper_) {
80+
input_dumper_ = std::make_unique<AsyncDumper>(std::move(input_dumper_));
81+
}
82+
83+
se_log_info("starting measurement");
84+
85+
frame_pool_ = std::make_unique<FramePool>(config_);
86+
87+
if (config_.report_format == "text") {
88+
reporter_ = std::make_unique<TextReporter>();
89+
} else if (config_.report_format == "json") {
90+
reporter_ = std::make_unique<JsonReporter>();
91+
}
92+
93+
if (config_.mode == "latency_step") {
94+
generator_ = std::make_unique<StepsGenerator>(config_);
95+
} else if (config_.mode == "latency_corr") {
96+
generator_ = std::make_unique<ImpulseGenerator>(config_, impulse);
97+
} else if (config_.mode == "losses") {
98+
generator_ = std::make_unique<ContinuousGenerator>(config_);
99+
}
100+
101+
if (config_.mode == "latency_step") {
102+
estimator_ = std::make_unique<StepsLatencyEstimator>(config_, *reporter_);
103+
} else if (config_.mode == "latency_corr") {
104+
estimator_ = std::make_unique<CorrelationLatencyEstimator>(config_, *reporter_);
105+
} else if (config_.mode == "losses") {
106+
estimator_ = std::make_unique<LossEstimator>(config_, *reporter_);
107+
}
108+
109+
output_thread_ = std::thread(&Runner::output_loop_, this);
110+
input_thread_ = std::thread(&Runner::input_loop_, this);
111+
112+
return true;
113+
}
114+
115+
void Runner::stop() {
116+
stop_ = true;
117+
}
118+
119+
void Runner::wait() {
120+
if (output_thread_.joinable()) {
121+
output_thread_.join();
122+
}
123+
124+
if (input_thread_.joinable()) {
125+
input_thread_.join();
126+
}
127+
}
128+
129+
void Runner::output_loop_() {
130+
make_realtime();
131+
132+
size_t n = 0;
133+
134+
for (; config_.io_num_periods > n; n++) {
135+
if (stop_ || fail_) {
136+
break;
137+
}
138+
139+
auto frame = frame_pool_->allocate();
140+
141+
if (!output_writer_->write(*frame)) {
142+
se_log_error("got error from output device, exiting");
143+
fail_ = true;
144+
break;
145+
}
146+
}
147+
148+
for (; n < config_.total_periods(); n++) {
149+
if (stop_ || fail_) {
150+
break;
151+
}
152+
153+
auto frame = frame_pool_->allocate();
154+
155+
generator_->generate(*frame);
156+
157+
if (!output_writer_->write(*frame)) {
158+
se_log_error("got error from output device, exiting");
159+
fail_ = true;
160+
break;
161+
}
162+
163+
if (n < config_.warmup_periods()) {
164+
continue;
165+
}
166+
167+
if (estimator_) {
168+
estimator_->add_output(frame);
169+
}
170+
171+
if (output_dumper_) {
172+
output_dumper_->write(frame);
173+
}
174+
}
175+
176+
if (estimator_) {
177+
estimator_->add_output(nullptr);
178+
}
179+
}
180+
181+
void Runner::input_loop_() {
182+
make_realtime();
183+
184+
for (size_t n = 0; n < config_.total_periods(); n++) {
185+
if (stop_ || fail_) {
186+
break;
187+
}
188+
189+
auto frame = frame_pool_->allocate();
190+
191+
if (!input_reader_->read(*frame)) {
192+
se_log_error("got error from input device, exiting");
193+
fail_ = true;
194+
break;
195+
}
196+
197+
if (n < config_.warmup_periods()) {
198+
continue;
199+
}
200+
201+
if (estimator_) {
202+
estimator_->add_input(frame);
203+
}
204+
205+
if (input_dumper_) {
206+
input_dumper_->write(frame);
207+
}
208+
}
209+
210+
if (estimator_) {
211+
estimator_->add_input(nullptr);
212+
}
213+
}
214+
215+
} // namespace signal_estimator

src/base/run/Runner.hpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) Signal Estimator authors
2+
// Licensed under MIT
3+
4+
#pragma once
5+
6+
#include "core/Config.hpp"
7+
#include "core/FramePool.hpp"
8+
#include "dumps/IDumper.hpp"
9+
#include "io/IDeviceReader.hpp"
10+
#include "io/IDeviceWriter.hpp"
11+
#include "processing/IEstimator.hpp"
12+
#include "processing/IGenerator.hpp"
13+
#include "reports/IReporter.hpp"
14+
15+
#include <atomic>
16+
#include <memory>
17+
#include <thread>
18+
19+
namespace signal_estimator {
20+
21+
class Runner {
22+
public:
23+
Runner(const Config& config);
24+
~Runner();
25+
26+
Runner(const Runner&) = delete;
27+
Runner& operator=(const Runner&) = delete;
28+
29+
bool failed() const;
30+
31+
bool start();
32+
void stop();
33+
void wait();
34+
35+
private:
36+
void output_loop_();
37+
void input_loop_();
38+
39+
Config config_;
40+
41+
std::unique_ptr<IDeviceWriter> output_writer_;
42+
std::unique_ptr<IDeviceReader> input_reader_;
43+
44+
std::unique_ptr<FramePool> frame_pool_;
45+
46+
std::unique_ptr<IReporter> reporter_;
47+
48+
std::unique_ptr<IGenerator> generator_;
49+
std::unique_ptr<IEstimator> estimator_;
50+
51+
std::unique_ptr<IDumper> output_dumper_;
52+
std::unique_ptr<IDumper> input_dumper_;
53+
54+
std::thread output_thread_;
55+
std::thread input_thread_;
56+
57+
std::atomic_bool stop_ { false };
58+
std::atomic_bool fail_ { false };
59+
};
60+
61+
} // namespace signal_estimator

0 commit comments

Comments
 (0)