12#ifndef RTCTK_STANDALONETOOLS_SHMPUB_HPP
13#define RTCTK_STANDALONETOOLS_SHMPUB_HPP
16#include <boost/program_options.hpp>
19#include <cfitsio/fitsio.h>
22#include <numapp/mempolicy.hpp>
23#include <numapp/numapolicies.hpp>
24#include <numapp/thread.hpp>
27#include <ipcq/writer.hpp>
37static bool g_stop =
false;
45 std::cout <<
"\nSignal to exit received\n";
75template <
class TopicType,
class WriterType = ipcq::Writer<TopicType>>
79 using namespace boost::program_options;
82 options_description desc(
"Allowed options");
85 (
"help,h",
"produce help message")
87 value<std::string>(&m_filename)->default_value(
""),
88 "fits input file: if not provided the app will generate data")
90 value<std::string>(&m_queue_name)->default_value(
"default_shm_queue"),
93 value<size_t>(&m_queue_size)->default_value(1000),
96 value<int>(&m_sample_delay)->default_value(10),
97 "inter-sample delay in ms")
98 (
"numa-node,n", value<int>(&m_numa),
"numa node for shm queue")
100 value<int>(&m_print_every)->default_value(0),
101 "when to print to screen the number of sample written")
103 value<int>(&m_gen_frames)->default_value(100),
104 "Number of frames to generate")
105 (
"sample-id-increment,i",
106 value<unsigned>(&m_sample_id_increment)->default_value(1),
107 "sample_id increment")
109 bool_switch(&m_repeat_mode),
110 "Repeat output when all samples are written");
114 store(command_line_parser(argc, argv).options(desc).run(), vm);
117 if (vm.count(
"help")) {
119 std::cout << desc <<
"\n";
122 std::cout <<
"fits-file: " << m_filename <<
"\n";
123 std::cout <<
"queue-name: " << m_queue_name <<
"\n";
124 std::cout <<
"queue-size: " << m_queue_size <<
"\n";
125 std::cout <<
"sample-delay: " << m_sample_delay <<
"\n";
126 if (vm.count(
"numa-node")) {
127 std::cout <<
"numa-node: " << m_numa <<
"\n";
129 std::cout <<
"print-every: " << m_print_every <<
"\n";
130 std::cout <<
"gen-frames: " << m_gen_frames <<
"\n";
131 std::cout <<
"sample-id-increment: " << m_sample_id_increment <<
"\n";
132 std::cout <<
"repeat-mode: " << m_repeat_mode <<
"\n";
134 if (vm.count(
"numa-node")) {
136 std::make_unique<WriterType>(m_queue_name.c_str(),
138 numapp::MemPolicy::MakeBindNode(m_numa));
140 m_writer = std::make_unique<WriterType>(m_queue_name.c_str(), m_queue_size);
143 }
catch (
const std::exception& e) {
144 std::cerr <<
"Exception:" << e.what() <<
"\n";
170 std::vector<TopicType> data;
175 if (not m_filename.empty()) {
176 std::cout <<
"Reading data from FITS file: " << m_filename <<
"\n";
179 std::cout <<
"Generating data\n";
185 throw std::runtime_error(
"Data vector is not populated so will exit");
189 std::cout <<
"Writing data to shared memory queue\n";
192 }
catch (
const std::exception& e) {
193 std::cout << e.what() <<
"\n";
200 std::this_thread::sleep_for(std::chrono::seconds(2));
220 virtual std::vector<TopicType>
ReadFits(std::string filename) = 0;
236 virtual std::vector<TopicType>
GenData(
int num_frames) = 0;
266 return m_sample_delay;
276 return m_repeat_mode;
291 void WriteToShm(std::vector<TopicType>& data) {
292 using namespace std::chrono;
294 size_t n_written = 0;
295 auto t_sent = steady_clock::now();
296 auto t_last = t_sent;
298 for (
auto& sample : data) {
304 sample.sample_id = n_written * m_sample_id_increment;
306 t_sent = steady_clock::now();
307 std::error_code err = m_writer->Write(sample, ipcq::Notify::All);
309 throw std::runtime_error(
"Error writing to shm: " + err.message());
313 if (n_written && m_print_every && (n_written % m_print_every == 0)) {
314 auto dur = duration_cast<milliseconds>(t_sent - t_last).count();
315 std::cout <<
"Samples written: " << n_written <<
"\n";
316 std::cout <<
"Total time to write " << m_print_every <<
" : " << dur <<
" ms\n";
317 std::cout <<
"Average frame time: " <<
static_cast<float>(dur) / m_print_every
321 while (duration_cast<milliseconds>(steady_clock::now() - t_sent).count() <
326 }
while (m_repeat_mode);
329 std::string m_queue_name;
330 size_t m_queue_size{0};
331 std::string m_filename;
332 int m_sample_delay{0};
335 int m_print_every{0};
337 unsigned m_sample_id_increment{1};
338 bool m_repeat_mode{
false};
339 bool m_help_only{
false};
341 std::unique_ptr<WriterType> m_writer;
362 int col, typecode, anynul;
368 fits_get_colnum(fptr, CASESEN,
const_cast<char*
>(name.c_str()), &col, &status);
370 fits_report_error(stderr, status);
371 throw std::runtime_error(
"Error getting column: " + name);
374 fits_get_coltype(fptr, col, &typecode, &repeat, &width, &status);
376 fits_report_error(stderr, status);
377 throw std::runtime_error(
"Error getting coltype of:" + name);
381 std::cout <<
"name: " << name <<
"\n";
382 std::cout <<
"col: " << col <<
"\n";
383 std::cout <<
"typecode: " << typecode <<
"\n";
384 std::cout <<
"repeat: " << repeat <<
"\n";
385 std::cout <<
"width: " << width <<
"\n";
390 data.resize(repeat * nrows);
392 fits_read_col(fptr, typecode, col, 1, 1, repeat * nrows, &nulval, d, &anynul, &status);
394 fits_report_error(stderr, status);
395 throw std::runtime_error(
"Error reading column: " + name);