11#ifndef RTCTK_STANDALONETOOLS_SHMPUB_HPP
12#define RTCTK_STANDALONETOOLS_SHMPUB_HPP
15#include <boost/program_options.hpp>
18#include <cfitsio/fitsio.h>
21#include <numapp/mempolicy.hpp>
22#include <numapp/numapolicies.hpp>
23#include <numapp/thread.hpp>
26#include <ipcq/writer.hpp>
36static bool g_stop =
false;
44 std::cout <<
"\nSignal to exit received\n";
74template <
class TopicType,
class WriterType = ipcq::Writer<TopicType>>
78 using namespace boost::program_options;
81 options_description desc(
"Allowed options");
84 (
"help,h",
"produce help message")
86 value<std::string>(&m_filename)->default_value(
""),
87 "fits input file: if not provided the app will generate data")
89 value<std::string>(&m_queue_name)->default_value(
"default_shm_queue"),
92 value<size_t>(&m_queue_size)->default_value(1000),
95 value<int>(&m_sample_delay)->default_value(10),
96 "inter-sample delay in ms")
97 (
"numa-node,n", value<int>(&m_numa),
"numa node for shm queue")
99 value<int>(&m_print_every)->default_value(0),
100 "when to print to screen the number of sample written")
102 value<int>(&m_gen_frames)->default_value(100),
103 "Number of frames to generate")
104 (
"sample-id-increment,i",
105 value<unsigned>(&m_sample_id_increment)->default_value(1),
106 "sample_id increment")
108 bool_switch(&m_repeat_mode),
109 "Repeat output when all samples are written");
113 store(command_line_parser(argc, argv).options(desc).run(), vm);
116 if (vm.count(
"help")) {
118 std::cout << desc <<
"\n";
121 std::cout <<
"fits-file: " << m_filename <<
"\n";
122 std::cout <<
"queue-name: " << m_queue_name <<
"\n";
123 std::cout <<
"queue-size: " << m_queue_size <<
"\n";
124 std::cout <<
"sample-delay: " << m_sample_delay <<
"\n";
125 if (vm.count(
"numa-node")) {
126 std::cout <<
"numa-node: " << m_numa <<
"\n";
128 std::cout <<
"print-every: " << m_print_every <<
"\n";
129 std::cout <<
"gen-frames: " << m_gen_frames <<
"\n";
130 std::cout <<
"sample-id-increment: " << m_sample_id_increment <<
"\n";
131 std::cout <<
"repeat-mode: " << m_repeat_mode <<
"\n";
133 if (vm.count(
"numa-node")) {
135 std::make_unique<WriterType>(m_queue_name.c_str(),
137 numapp::MemPolicy::MakeBindNode(m_numa));
139 m_writer = std::make_unique<WriterType>(m_queue_name.c_str(), m_queue_size);
142 }
catch (
const std::exception& e) {
143 std::cerr <<
"Exception:" << e.what() <<
"\n";
169 std::vector<TopicType> data;
174 if (not m_filename.empty()) {
175 std::cout <<
"Reading data from FITS file: " << m_filename <<
"\n";
178 std::cout <<
"Generating data\n";
184 throw std::runtime_error(
"Data vector is not populated so will exit");
188 std::cout <<
"Writing data to shared memory queue\n";
191 }
catch (
const std::exception& e) {
192 std::cout << e.what() <<
"\n";
199 std::this_thread::sleep_for(std::chrono::seconds(2));
219 virtual std::vector<TopicType>
ReadFits(std::string filename) = 0;
235 virtual std::vector<TopicType>
GenData(
int num_frames) = 0;
265 return m_sample_delay;
275 return m_repeat_mode;
290 void WriteToShm(std::vector<TopicType>& data) {
291 using namespace std::chrono;
293 size_t n_written = 0;
294 auto t_sent = steady_clock::now();
295 auto t_last = t_sent;
297 for (
auto& sample : data) {
303 sample.sample_id = n_written * m_sample_id_increment;
305 t_sent = steady_clock::now();
306 std::error_code err = m_writer->Write(sample, ipcq::Notify::All);
308 throw std::runtime_error(
"Error writing to shm: " + err.message());
312 if (n_written && m_print_every && (n_written % m_print_every == 0)) {
313 auto dur = duration_cast<milliseconds>(t_sent - t_last).count();
314 std::cout <<
"Samples written: " << n_written <<
"\n";
315 std::cout <<
"Total time to write " << m_print_every <<
" : " << dur <<
" ms\n";
316 std::cout <<
"Average frame time: " <<
static_cast<float>(dur) / m_print_every
320 while (duration_cast<milliseconds>(steady_clock::now() - t_sent).count() <
325 }
while (m_repeat_mode);
328 std::string m_queue_name;
329 size_t m_queue_size{0};
330 std::string m_filename;
331 int m_sample_delay{0};
334 int m_print_every{0};
336 unsigned m_sample_id_increment{1};
337 bool m_repeat_mode{
false};
338 bool m_help_only{
false};
340 std::unique_ptr<WriterType> m_writer;
361 int col, typecode, anynul;
367 fits_get_colnum(fptr, CASESEN,
const_cast<char*
>(name.c_str()), &col, &status);
369 fits_report_error(stderr, status);
370 throw std::runtime_error(
"Error getting column: " + name);
373 fits_get_coltype(fptr, col, &typecode, &repeat, &width, &status);
375 fits_report_error(stderr, status);
376 throw std::runtime_error(
"Error getting coltype of:" + name);
380 std::cout <<
"name: " << name <<
"\n";
381 std::cout <<
"col: " << col <<
"\n";
382 std::cout <<
"typecode: " << typecode <<
"\n";
383 std::cout <<
"repeat: " << repeat <<
"\n";
384 std::cout <<
"width: " << width <<
"\n";
389 data.resize(repeat * nrows);
391 fits_read_col(fptr, typecode, col, 1, 1, repeat * nrows, &nulval, d, &anynul, &status);
393 fits_report_error(stderr, status);
394 throw std::runtime_error(
"Error reading column: " + name);