diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 2cb52e997313825379a3758515b466f0f08d692d..c5e55511dd9c9d54ddd6148d80c8f31dbc4635f2 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -11,5 +11,6 @@ install(FILES cdc_phy_tx.block.yml cdc_phy_rx.block.yml cdc_insert_burst_c.block.yml - cdc_dsa_pu_scenario_cc.block.yml DESTINATION share/gnuradio/grc/blocks + cdc_dsa_pu_scenario_cc.block.yml + cdc_dsa_stats.block.yml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/cdc_dsa_stats.block.yml b/grc/cdc_dsa_stats.block.yml new file mode 100644 index 0000000000000000000000000000000000000000..766349406ccf727c865003a149e2fa1273def0c7 --- /dev/null +++ b/grc/cdc_dsa_stats.block.yml @@ -0,0 +1,43 @@ +id: cdc_dsa_stats +label: 'CDC DSA Stats' +category: '[CDC]' + +templates: + imports: from gnuradio import cdc + make: cdc.dsa_stats(${period}, ${primary}, ${tput_offered}) + callbacks: + - reset_stats(${reset}) + - set_tput_offered(${tput_offered}) + +parameters: +- id: period + label: Period + default: ' 1' + dtype: int +- id: primary + label: 'Is primary' + default: True + dtype: bool +- id: tput_offered + label: 'Offered PU Throughput' + default: 0.0 + dtype: float +- id: reset + label: 'Reset Stats' + default: False + dtype: bool + +inputs: +- label: pdu + domain: message + optional: True +- label: stats_in + domain: message + optional: True + +outputs: +- label: stats + domain: message + optional: True + +file_format: 1 diff --git a/include/gnuradio/cdc/CMakeLists.txt b/include/gnuradio/cdc/CMakeLists.txt index 91025a06f98fa23e2f0adeabeaa95dcf8916de8b..266b4c50c49828dd0512d214c6d153ee78fd1e6d 100644 --- a/include/gnuradio/cdc/CMakeLists.txt +++ b/include/gnuradio/cdc/CMakeLists.txt @@ -14,5 +14,6 @@ install(FILES tag_tx_burst_cc.h preamble_detect_cc.h insert_burst_c.h - dsa_pu_scenario_cc.h DESTINATION include/gnuradio/cdc + dsa_pu_scenario_cc.h + dsa_stats.h DESTINATION include/gnuradio/cdc ) diff --git a/include/gnuradio/cdc/dsa_stats.h b/include/gnuradio/cdc/dsa_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..8520d3d53de33ba73a99c8753f868fcbb29c9ace --- /dev/null +++ b/include/gnuradio/cdc/dsa_stats.h @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2023 University of Melbourne. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef INCLUDED_CDC_DSA_STATS_H +#define INCLUDED_CDC_DSA_STATS_H + +#include <gnuradio/block.h> +#include <gnuradio/cdc/api.h> + +namespace gr { +namespace cdc { + +/*! + * \brief Track DSA scenario statistics. + * \ingroup cdc + * + */ +class CDC_API dsa_stats : virtual public gr::block { +public: + typedef std::shared_ptr<dsa_stats> sptr; + + static sptr make(int period = 1, + bool primary = true, + double tput_offered = 0.0); + + virtual void reset_stats(bool reset) = 0; + + virtual void set_tput_offered(double tput_offered) = 0; + + virtual double get_tput_offered(void) = 0; +}; + +} // namespace cdc +} // namespace gr + +#endif /* INCLUDED_CDC_DSA_STATS_H */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 0066e1d356f52a930796a404a695362df4d75b76..32e66d09f9708dcea5a6d80a3e5d71fb2e2a931f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -14,7 +14,8 @@ list(APPEND cdc_sources tag_tx_burst_cc_impl.cc preamble_detect_cc_impl.cc insert_burst_c_impl.cc - dsa_pu_scenario_cc_impl.cc ) + dsa_pu_scenario_cc_impl.cc + dsa_stats_impl.cc ) set(cdc_sources "${cdc_sources}" PARENT_SCOPE) if(NOT cdc_sources) diff --git a/lib/dsa_pu_scenario_cc_impl.cc b/lib/dsa_pu_scenario_cc_impl.cc index c8e8ae51555cafc56b53d0cb2bb743c88073b5c1..556f3b525cace5203455ae70fd45d9a7c92413c1 100644 --- a/lib/dsa_pu_scenario_cc_impl.cc +++ b/lib/dsa_pu_scenario_cc_impl.cc @@ -32,9 +32,9 @@ dsa_pu_scenario_cc_impl::dsa_pu_scenario_cc_impl(int samp_rate, gr::io_signature::make(1, -1, sizeof(gr_complex))), d_samp_rate(samp_rate), d_duration_ms(duration_ms), - d_engine(seed), d_random(random), - d_scenario(scenario) + d_scenario(scenario), + d_engine(seed) { message_port_register_out(pmt::mp("mode")); } @@ -83,7 +83,7 @@ dsa_pu_scenario_cc_impl::work(int noutput_items, if (d_active[i_chan]) memcpy(out, in, n_samps * sizeof(gr_complex)); else - memset(out, 0x0, n_samps * sizeof(gr_complex)); + memset((void *)out, 0x0, n_samps * sizeof(gr_complex)); } d_samp_cnt -= n_samps; diff --git a/lib/dsa_pu_scenario_cc_impl.h b/lib/dsa_pu_scenario_cc_impl.h index 8dcd25aad3908e60e8f84c2dc488484eb2ef1605..77afc6e89526e0753af1703c60ada689579ed55d 100644 --- a/lib/dsa_pu_scenario_cc_impl.h +++ b/lib/dsa_pu_scenario_cc_impl.h @@ -44,7 +44,7 @@ public: void set_random(bool random) { d_random = random; }; - bool get_random(void) { return random; }; + bool get_random(void) { return d_random; }; void set_duration_ms(float duration_ms) { d_duration_ms = duration_ms; }; diff --git a/lib/dsa_stats_impl.cc b/lib/dsa_stats_impl.cc new file mode 100644 index 0000000000000000000000000000000000000000..8f07e32942b21a39c34ebe5b042ad08c86b7ef76 --- /dev/null +++ b/lib/dsa_stats_impl.cc @@ -0,0 +1,154 @@ +/* -*- c++ -*- */ +/* + * Copyright 2023 University of Melbourne. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "dsa_stats_impl.h" +#include <gnuradio/io_signature.h> + +using std::chrono::steady_clock; +using std::chrono::duration; + +namespace gr { +namespace cdc { + +dsa_stats::sptr dsa_stats::make(int period, + bool primary, + double tput_offered) +{ + return gnuradio::make_block_sptr<dsa_stats_impl>( + period, primary, tput_offered); +} + +dsa_stats_impl::dsa_stats_impl(int period, + bool primary, + double tput_offered) + : gr::block("dsa_stats", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)), + d_period(period), + d_primary(primary), + d_tput_offered(tput_offered) +{ + message_port_register_in(pmt::mp("pdu")); + set_msg_handler(pmt::mp("pdu"), + [this](const pmt::pmt_t& msg) { this->handle_pdu(msg); }); + message_port_register_in(pmt::mp("stats_in")); + set_msg_handler(pmt::mp("stats_in"), + [this](const pmt::pmt_t& msg) { this->handle_stats_in(msg); }); + message_port_register_out(pmt::mp("stats")); +} + +dsa_stats_impl::~dsa_stats_impl() {} + +bool dsa_stats_impl::start() +{ + d_finished = false; + + d_thread = std::shared_ptr<gr::thread::thread>( + new gr::thread::thread(boost::bind(&dsa_stats_impl::run, this))); + + return block::start(); +} + +bool dsa_stats_impl::stop() +{ + // Shut down the thread + { + gr::thread::scoped_lock lock(d_mtx); + d_finished = true; + } + d_thread->interrupt(); + d_thread->join(); + + return block::stop(); +} + +void dsa_stats_impl::run() +{ + bool finished = false; + reset_stats(); + + while (!finished) { + // elapsed time + auto now = steady_clock::now(); + duration<double> dur_cur = (now - d_last_tp); + duration<double> dur_avg = (now - d_start_tp); + d_last_tp = now; + + // get current stats + double bytes_new = 0; + double tput_remote = 0; + { + gr::thread::scoped_lock lock(d_mtx); + + bytes_new = d_bytes_new; + tput_remote = d_tput_remote; + d_bytes_new = 0; + } + d_bytes += bytes_new; + double tput_cur = 8.0*bytes_new / dur_cur.count(); + double tput_avg = 8.0*d_bytes / dur_avg.count(); + + double tput_pu = d_primary ? tput_avg : tput_remote; + double tput_su = d_primary ? tput_remote : tput_avg; + double score = 0.0; + if (tput_pu > 0) { + score = exp(-10.0*(d_tput_offered - tput_pu)/tput_pu) * tput_su; + } + + // publish stats message + pmt::pmt_t stats = pmt::make_dict(); + stats = pmt::dict_add(stats, + pmt::mp("tput_cur"), + pmt::from_double(tput_cur)); + stats = pmt::dict_add(stats, + pmt::mp("tput_avg"), + pmt::from_double(tput_avg)); + stats = pmt::dict_add(stats, + pmt::mp("score"), + pmt::from_double(score)); + message_port_pub(pmt::mp("stats"), stats); + + // sleep for 'period' second + boost::this_thread::sleep( + boost::posix_time::seconds(static_cast<long>(d_period))); + + { + gr::thread::scoped_lock lock(d_mtx); + finished = d_finished; + } + } +} + +void dsa_stats_impl::handle_pdu(const pmt::pmt_t& msg) +{ + gr::thread::scoped_lock lock(d_mtx); + d_bytes_new += pmt::blob_length(pmt::cdr(msg)); +} + +void dsa_stats_impl::handle_stats_in(const pmt::pmt_t& msg) +{ + gr::thread::scoped_lock lock(d_mtx); + d_tput_remote = pmt::to_double(pmt::dict_ref(msg, + pmt::mp("tput_avg"), + pmt::from_double(0.0))); +} + +void dsa_stats_impl::reset_stats(bool reset) +{ + if (reset) + { + gr::thread::scoped_lock lock(d_mtx); + + d_bytes_new = 0.0; + d_bytes = 0.0; + d_start_tp = steady_clock::now(); + d_last_tp = d_start_tp; + } +} + +} /* namespace cdc */ +} /* namespace gr */ diff --git a/lib/dsa_stats_impl.h b/lib/dsa_stats_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..76412852fa5c6738fa40446c013c62f2bca83a47 --- /dev/null +++ b/lib/dsa_stats_impl.h @@ -0,0 +1,64 @@ +/* -*- c++ -*- */ +/* + * Copyright 2023 University of Melbourne. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef INCLUDED_CDC_DSA_STATS_IMPL_H +#define INCLUDED_CDC_DSA_STATS_IMPL_H + +#include <gnuradio/cdc/dsa_stats.h> +#include <chrono> + +using std::chrono::time_point; +using std::chrono::steady_clock; + +namespace gr { +namespace cdc { + +class dsa_stats_impl : public dsa_stats +{ +private: + std::shared_ptr<gr::thread::thread> d_thread; + bool d_finished; + long d_period; + bool d_primary; + double d_tput_offered; + + // stat variables + gr::thread::mutex d_mtx; + time_point<steady_clock> d_start_tp; + time_point<steady_clock> d_last_tp; + double d_bytes_new = 0.0; + double d_bytes = 0.0; + double d_tput_remote = 0.0; + + void run(); + + void handle_pdu(const pmt::pmt_t& pdu); + + void handle_stats_in(const pmt::pmt_t& pdu); + +public: + dsa_stats_impl(int period, + bool primary, + double tput_offered); + + ~dsa_stats_impl(); + + void reset_stats(bool reset=true); + + double get_tput_offered(void) { return d_tput_offered; } + + void set_tput_offered(double tput_offered) { d_tput_offered = tput_offered; } + + // Overload gr::block start/stop to start internal stats thread + bool start(); + bool stop(); +}; + +} // namespace cdc +} // namespace gr + +#endif /* INCLUDED_CDC_DSA_STATS_IMPL_H */ diff --git a/python/cdc/bindings/CMakeLists.txt b/python/cdc/bindings/CMakeLists.txt index a955da9cde1118b906c2b700ba85fe85df10d797..557fceb8f0134b81ec2170a621e7bbb4dad84622 100644 --- a/python/cdc/bindings/CMakeLists.txt +++ b/python/cdc/bindings/CMakeLists.txt @@ -31,7 +31,8 @@ list(APPEND cdc_python_files tag_tx_burst_cc_python.cc preamble_detect_cc_python.cc insert_burst_c_python.cc - dsa_pu_scenario_cc_python.cc python_bindings.cc) + dsa_pu_scenario_cc_python.cc + dsa_stats_python.cc python_bindings.cc) GR_PYBIND_MAKE_OOT(cdc ../../.. diff --git a/python/cdc/bindings/docstrings/dsa_stats_pydoc_template.h b/python/cdc/bindings/docstrings/dsa_stats_pydoc_template.h new file mode 100644 index 0000000000000000000000000000000000000000..5a8455aa3a94597c4c3d6ca524973946be420d44 --- /dev/null +++ b/python/cdc/bindings/docstrings/dsa_stats_pydoc_template.h @@ -0,0 +1,39 @@ +/* + * Copyright 2023 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr,cdc, __VA_ARGS__ ) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + + + static const char *__doc_gr_cdc_dsa_stats = R"doc()doc"; + + + static const char *__doc_gr_cdc_dsa_stats_dsa_stats_0 = R"doc()doc"; + + + static const char *__doc_gr_cdc_dsa_stats_dsa_stats_1 = R"doc()doc"; + + + static const char *__doc_gr_cdc_dsa_stats_make = R"doc()doc"; + + + static const char *__doc_gr_cdc_dsa_stats_reset_stats = R"doc()doc"; + + + static const char *__doc_gr_cdc_dsa_stats_set_tput_offered = R"doc()doc"; + + + static const char *__doc_gr_cdc_dsa_stats_get_tput_offered = R"doc()doc"; + + diff --git a/python/cdc/bindings/dsa_stats_python.cc b/python/cdc/bindings/dsa_stats_python.cc new file mode 100644 index 0000000000000000000000000000000000000000..3e09297ac0cee89a65fbba6135f876b6542a8ed2 --- /dev/null +++ b/python/cdc/bindings/dsa_stats_python.cc @@ -0,0 +1,82 @@ +/* + * Copyright 2023 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(dsa_stats.h) */ +/* BINDTOOL_HEADER_FILE_HASH(9bbbbaa16987fedac4730cab7eb42ec5) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/cdc/dsa_stats.h> +// pydoc.h is automatically generated in the build directory +#include <dsa_stats_pydoc.h> + +void bind_dsa_stats(py::module& m) +{ + + using dsa_stats = ::gr::cdc::dsa_stats; + + + py::class_<dsa_stats, gr::block, gr::basic_block, + std::shared_ptr<dsa_stats>>(m, "dsa_stats", D(dsa_stats)) + + .def(py::init(&dsa_stats::make), + py::arg("period") = 1, + py::arg("primary") = true, + py::arg("tput_offered") = 0., + D(dsa_stats,make) + ) + + + + + + + .def("reset_stats",&dsa_stats::reset_stats, + py::arg("reset"), + D(dsa_stats,reset_stats) + ) + + + + .def("set_tput_offered",&dsa_stats::set_tput_offered, + py::arg("tput_offered"), + D(dsa_stats,set_tput_offered) + ) + + + + .def("get_tput_offered",&dsa_stats::get_tput_offered, + D(dsa_stats,get_tput_offered) + ) + + ; + + + + +} + + + + + + + + diff --git a/python/cdc/bindings/python_bindings.cc b/python/cdc/bindings/python_bindings.cc index 9f463592a128d75d3cf6e20c6b95d8a144917e29..8e0aa7aba74571e317a2467b93d5b2542140e30e 100644 --- a/python/cdc/bindings/python_bindings.cc +++ b/python/cdc/bindings/python_bindings.cc @@ -25,6 +25,7 @@ namespace py = pybind11; void bind_preamble_detect_cc(py::module& m); void bind_insert_burst_c(py::module& m); void bind_dsa_pu_scenario_cc(py::module& m); + void bind_dsa_stats(py::module& m); // ) END BINDING_FUNCTION_PROTOTYPES @@ -57,5 +58,6 @@ PYBIND11_MODULE(cdc_python, m) bind_preamble_detect_cc(m); bind_insert_burst_c(m); bind_dsa_pu_scenario_cc(m); + bind_dsa_stats(m); // ) END BINDING_FUNCTION_CALLS } \ No newline at end of file