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";
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")
99 value<int>(&m_initial_delay)->default_value(0),
100 "initial delay in ms")
101 (
"numa-node,n", value<int>(&m_numa),
"numa node for shm queue")
103 value<int>(&m_print_every)->default_value(0),
104 "when to print to screen the number of sample written")
106 value<int>(&m_gen_frames)->default_value(100),
107 "Number of frames to generate")
108 (
"sample-id-increment,i",
109 value<unsigned>(&m_sample_id_increment)->default_value(1),
110 "sample_id increment")
112 bool_switch(&m_repeat_mode),
113 "Repeat output when all samples are written");
117 store(command_line_parser(argc, argv).options(desc).run(), vm);
120 if (vm.count(
"help")) {
122 std::cout << desc <<
"\n";
125 std::cout <<
"fits-file: " << m_filename <<
"\n";
126 std::cout <<
"queue-name: " << m_queue_name <<
"\n";
127 std::cout <<
"queue-size: " << m_queue_size <<
"\n";
128 std::cout <<
"sample-delay: " << m_sample_delay <<
"\n";
129 std::cout <<
"initital-delay: " << m_initial_delay <<
"\n";
130 if (vm.count(
"numa-node")) {
131 std::cout <<
"numa-node: " << m_numa <<
"\n";
133 std::cout <<
"print-every: " << m_print_every <<
"\n";
134 std::cout <<
"gen-frames: " << m_gen_frames <<
"\n";
135 std::cout <<
"sample-id-increment: " << m_sample_id_increment <<
"\n";
136 std::cout <<
"repeat-mode: " << m_repeat_mode <<
"\n";
138 if (vm.count(
"numa-node")) {
140 std::make_unique<WriterType>(m_queue_name.c_str(),
142 numapp::MemPolicy::MakeBindNode(m_numa));
144 m_writer = std::make_unique<WriterType>(m_queue_name.c_str(), m_queue_size);
147 }
catch (
const std::exception& e) {
148 std::cerr <<
"Exception:" << e.what() <<
"\n";
174 std::vector<TopicType> data;
179 if (not m_filename.empty()) {
180 std::cout <<
"Reading data from FITS file: " << m_filename <<
"\n";
183 std::cout <<
"Generating data\n";
189 throw std::runtime_error(
"Data vector is not populated so will exit");
192 WaitFor(std::chrono::milliseconds{m_initial_delay});
195 std::cout <<
"Writing data to shared memory queue\n";
198 }
catch (
const std::exception& e) {
199 std::cout << e.what() <<
"\n";
206 std::this_thread::sleep_for(std::chrono::seconds(2));
226 virtual std::vector<TopicType>
ReadFits(std::string filename) = 0;
242 virtual std::vector<TopicType>
GenData(
int num_frames) = 0;
272 return m_sample_delay;
282 return m_repeat_mode;
292 void WaitFor(std::chrono::milliseconds delay) {
293 using namespace std::chrono;
295 if(g_stop or delay == 0ms) {
299 auto t_start = steady_clock::now();
300 while(!g_stop and ((steady_clock::now() - t_start) < delay)) {
301 std::this_thread::sleep_for(1ms);
316 void WriteToShm(std::vector<TopicType>& data) {
317 using namespace std::chrono;
319 size_t n_written = 0;
320 auto t_sent = steady_clock::now();
321 auto t_last = t_sent;
323 for (
auto& sample : data) {
329 sample.sample_id = n_written * m_sample_id_increment;
331 t_sent = steady_clock::now();
332 std::error_code err = m_writer->Write(sample, ipcq::Notify::All);
334 throw std::runtime_error(
"Error writing to shm: " + err.message());
338 if (n_written && m_print_every && (n_written % m_print_every == 0)) {
339 auto dur = duration_cast<milliseconds>(t_sent - t_last).count();
340 std::cout <<
"Samples written: " << n_written <<
"\n";
341 std::cout <<
"Total time to write " << m_print_every <<
" : " << dur <<
" ms\n";
342 std::cout <<
"Average frame time: " <<
static_cast<float>(dur) / m_print_every
346 while (duration_cast<milliseconds>(steady_clock::now() - t_sent).count() <
351 }
while (m_repeat_mode);
354 std::string m_queue_name;
355 size_t m_queue_size{0};
356 std::string m_filename;
357 int m_sample_delay{0};
358 int m_initial_delay{0};
361 int m_print_every{0};
363 unsigned m_sample_id_increment{1};
364 bool m_repeat_mode{
false};
365 bool m_help_only{
false};
367 std::unique_ptr<WriterType> m_writer;
388 int col, typecode, anynul;
394 fits_get_colnum(fptr, CASESEN,
const_cast<char*
>(name.c_str()), &col, &status);
396 fits_report_error(stderr, status);
397 throw std::runtime_error(
"Error getting column: " + name);
400 fits_get_coltype(fptr, col, &typecode, &repeat, &width, &status);
402 fits_report_error(stderr, status);
403 throw std::runtime_error(
"Error getting coltype of:" + name);
407 std::cout <<
"name: " << name <<
"\n";
408 std::cout <<
"col: " << col <<
"\n";
409 std::cout <<
"typecode: " << typecode <<
"\n";
410 std::cout <<
"repeat: " << repeat <<
"\n";
411 std::cout <<
"width: " << width <<
"\n";
416 data.resize(repeat * nrows);
418 fits_read_col(fptr, typecode, col, 1, 1, repeat * nrows, &nulval, d, &anynul, &status);
420 fits_report_error(stderr, status);
421 throw std::runtime_error(
"Error reading column: " + name);