From 2f8643fb9757c3f12bb69f60d42e32a7d7a895fa Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 12 Mar 2020 11:33:58 +0100 Subject: [PATCH] add tx/rx pkt ok/nok to enb metrics, also add enb metrics test This is what it'll look like if running the new test: ------DL--------------------------------UL------------------------------------- rnti cqi ri mcs brate ok nok (%) snr phr mcs brate ok nok (%) bsr 46 16 1.5 28 15.2G 1000 1000 100% 14.2 12.0 20 15.2M 50 10 20% 100.0 ffff 1.2 1.5 6.2 1.00M 100 54 54% 22.2 99.1 28 1.00k 50 10 20% 100.0 --- srsenb/hdr/metrics_stdout.h | 3 +- srsenb/src/metrics_stdout.cc | 53 +++++++---- srsenb/test/CMakeLists.txt | 4 + srsenb/test/enb_metrics_test.cc | 162 ++++++++++++++++++++++++++++++++ 4 files changed, 202 insertions(+), 20 deletions(-) create mode 100644 srsenb/test/enb_metrics_test.cc diff --git a/srsenb/hdr/metrics_stdout.h b/srsenb/hdr/metrics_stdout.h index 55bd2055d..439f45b6d 100644 --- a/srsenb/hdr/metrics_stdout.h +++ b/srsenb/hdr/metrics_stdout.h @@ -46,7 +46,8 @@ public: void stop(){}; private: - std::string float_to_string(float f, int digits); + std::string float_to_string(float f, int digits, int field_width = 6); + std::string int_to_hex_string(int value, int field_width); std::string float_to_eng_string(float f, int digits); bool do_print; diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index e8bdb682f..743857c42 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -92,8 +92,8 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe if (++n_reports > 10) { n_reports = 0; cout << endl; - cout << "------DL------------------------------UL----------------------------------" << endl; - cout << "rnti cqi ri mcs brate bler snr phr mcs brate bler bsr" << endl; + cout << "------DL--------------------------------UL-------------------------------------" << endl; + cout << "rnti cqi ri mcs brate ok nok (%) snr phr mcs brate ok nok (%) bsr" << endl; } for (int i = 0; i < metrics.stack.rrc.n_ues; i++) { @@ -104,48 +104,56 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe printf("rx caution errors %d > %d\n", metrics.stack.mac[i].rx_errors, metrics.stack.mac[i].rx_pkts); } - cout << std::hex << metrics.stack.mac[i].rnti << " "; - cout << float_to_string(SRSLTE_MAX(0.1, metrics.stack.mac[i].dl_cqi), 2); - cout << float_to_string(metrics.stack.mac[i].dl_ri, 1); + cout << int_to_hex_string(metrics.stack.mac[i].rnti, 4) << " "; + cout << float_to_string(SRSLTE_MAX(0.1, metrics.stack.mac[i].dl_cqi), 1, 3); + cout << float_to_string(metrics.stack.mac[i].dl_ri, 1, 4); if (not isnan(metrics.phy[i].dl.mcs)) { - cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].dl.mcs), 2); + cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].dl.mcs), 1, 4); } else { - cout << float_to_string(0, 2); + cout << float_to_string(0, 2, 4); } if (metrics.stack.mac[i].tx_brate > 0) { cout << float_to_eng_string(SRSLTE_MAX(0.1, (float)metrics.stack.mac[i].tx_brate / period_usec * 1e6), 2); } else { - cout << float_to_string(0, 2) << ""; + cout << float_to_string(0, 2, 5) << ""; } + cout << std::setw(5) << metrics.stack.mac[i].tx_pkts; + cout << std::setw(5) << metrics.stack.mac[i].tx_errors; if (metrics.stack.mac[i].tx_pkts > 0 && metrics.stack.mac[i].tx_errors) { cout << float_to_string( - SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac[i].tx_errors / metrics.stack.mac[i].tx_pkts), 1) + SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac[i].tx_errors / metrics.stack.mac[i].tx_pkts), 1, 4) << "%"; } else { cout << float_to_string(0, 1) << "%"; } + cout << " "; + if (not isnan(metrics.phy[i].ul.sinr)) { - cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.sinr), 2); + cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.sinr), 2, 4); } else { - cout << float_to_string(0, 2); + cout << float_to_string(0, 1, 4); } - cout << float_to_string(metrics.stack.mac[i].phr, 2); + + cout << float_to_string(metrics.stack.mac[i].phr, 2, 5); if (not isnan(metrics.phy[i].ul.mcs)) { - cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.mcs), 2); + cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.mcs), 1, 4); } else { - cout << float_to_string(0, 2); + cout << float_to_string(0, 1, 4); } if (metrics.stack.mac[i].rx_brate > 0) { cout << float_to_eng_string(SRSLTE_MAX(0.1, (float)metrics.stack.mac[i].rx_brate / period_usec * 1e6), 2); } else { cout << float_to_string(0, 2) << ""; } + cout << std::setw(5) << metrics.stack.mac[i].rx_pkts; + cout << std::setw(5) << metrics.stack.mac[i].rx_errors; + if (metrics.stack.mac[i].rx_pkts > 0 && metrics.stack.mac[i].rx_errors > 0) { cout << float_to_string( - SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac[i].rx_errors / metrics.stack.mac[i].rx_pkts), 1) + SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac[i].rx_errors / metrics.stack.mac[i].rx_pkts), 1, 4) << "%"; } else { - cout << float_to_string(0, 1) << "%"; + cout << float_to_string(0, 1, 4) << "%"; } cout << float_to_eng_string(metrics.stack.mac[i].ul_buffer, 2); cout << endl; @@ -154,7 +162,7 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe cout.flags(f); // For avoiding Coverity defect: Not restoring ostream format } -std::string metrics_stdout::float_to_string(float f, int digits) +std::string metrics_stdout::float_to_string(float f, int digits, int field_width) { std::ostringstream os; int precision; @@ -164,7 +172,14 @@ std::string metrics_stdout::float_to_string(float f, int digits) } else { precision = digits - (int)(log10f(fabs(f)) - 2 * DBL_EPSILON); } - os << std::setw(6) << std::fixed << std::setprecision(precision) << f; + os << std::setw(field_width) << std::fixed << std::setprecision(precision) << f; + return os.str(); +} + +std::string metrics_stdout::int_to_hex_string(int value, int field_width) +{ + std::ostringstream os; + os << std::hex << std::setw(field_width) << value; return os.str(); } @@ -185,7 +200,7 @@ std::string metrics_stdout::float_to_eng_string(float f, int digits) const double scaled = f * pow(1000.0, -degree); if (degree != 0) { - return float_to_string(scaled, digits) + factor; + return float_to_string(scaled, digits, 5) + factor; } else { return " " + float_to_string(scaled, digits) + factor; } diff --git a/srsenb/test/CMakeLists.txt b/srsenb/test/CMakeLists.txt index 1caf0301d..999f3afb4 100644 --- a/srsenb/test/CMakeLists.txt +++ b/srsenb/test/CMakeLists.txt @@ -21,3 +21,7 @@ add_subdirectory(mac) add_subdirectory(phy) add_subdirectory(upper) + +add_executable(enb_metrics_test enb_metrics_test.cc ../src/metrics_stdout.cc ../src/metrics_csv.cc) +target_link_libraries(enb_metrics_test srslte_phy srslte_common) +add_test(enb_metrics_test enb_metrics_test -o ${CMAKE_CURRENT_BINARY_DIR}/enb_metrics.csv) diff --git a/srsenb/test/enb_metrics_test.cc b/srsenb/test/enb_metrics_test.cc new file mode 100644 index 000000000..14367e492 --- /dev/null +++ b/srsenb/test/enb_metrics_test.cc @@ -0,0 +1,162 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srsenb/hdr/metrics_csv.h" +#include "srsenb/hdr/metrics_stdout.h" +#include "srslte/common/metrics_hub.h" +#include "srslte/interfaces/enb_metrics_interface.h" +#include "srslte/srslte.h" +#include +#include +#include +#include +#include + +using namespace srsenb; + +namespace srsenb { + +char* csv_file_name = NULL; + +#define NUM_METRICS 2 + +// fake classes +class enb_dummy : public enb_metrics_interface +{ +public: + enb_dummy() + { + // first entry + metrics[0].rf.rf_o = 10; + metrics[0].stack.rrc.n_ues = 1; + metrics[0].stack.mac[0].rnti = 0x46; + metrics[0].stack.mac[0].tx_pkts = 1000; + metrics[0].stack.mac[0].tx_errors = 1000; + metrics[0].stack.mac[0].tx_brate = 1e6; + metrics[0].stack.mac[0].rx_pkts = 50; + metrics[0].stack.mac[0].rx_errors = 10; + metrics[0].stack.mac[0].rx_brate = 1e3; + metrics[0].stack.mac[0].ul_buffer = 100; + metrics[0].stack.mac[0].dl_buffer = 200; + metrics[0].stack.mac[0].dl_cqi = 15.9; + metrics[0].stack.mac[0].dl_ri = 1.5; + metrics[0].stack.mac[0].dl_pmi = 1.0; + metrics[0].stack.mac[0].phr = 12.0; + metrics[0].phy->dl.mcs = 28.0; + metrics[0].phy->ul.mcs = 20.2; + metrics[0].phy->ul.sinr = 14.2; + + // second + metrics[1].rf.rf_o = 10; + metrics[1].stack.rrc.n_ues = 1; + metrics[1].stack.mac[0].rnti = 0xffff; + metrics[1].stack.mac[0].tx_pkts = 100; + metrics[1].stack.mac[0].tx_errors = 54; + metrics[1].stack.mac[0].tx_brate = 1e6; + metrics[1].stack.mac[0].rx_pkts = 50; + metrics[1].stack.mac[0].rx_errors = 10; + metrics[1].stack.mac[0].rx_brate = 1e3; + metrics[1].stack.mac[0].ul_buffer = 100; + metrics[1].stack.mac[0].dl_buffer = 200; + metrics[1].stack.mac[0].dl_cqi = 1.2; + metrics[1].stack.mac[0].dl_ri = 1.5; + metrics[1].stack.mac[0].dl_pmi = 1.0; + metrics[1].stack.mac[0].phr = 99.1; + metrics[1].phy->dl.mcs = 6.2; + metrics[1].phy->ul.mcs = 28.0; + metrics[1].phy->ul.sinr = 22.2; + } + + bool get_metrics(enb_metrics_t* m) + { + // fill dummy values + memcpy(m, &metrics[counter % NUM_METRICS], sizeof(enb_metrics_t)); + counter++; + return true; + } + +private: + int counter = 0; + enb_metrics_t metrics[2] = {}; +}; + +} // namespace srsenb + +void usage(char* prog) +{ + printf("Usage: %s -o csv_output_file\n", prog); +} + +void parse_args(int argc, char** argv) +{ + int opt; + + while ((opt = getopt(argc, argv, "o")) != -1) { + switch (opt) { + case 'o': + csv_file_name = argv[optind]; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!csv_file_name) { + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char** argv) +{ + float period = 1.0; + enb_dummy enb; + + if (argc < 3) { + usage(argv[0]); + exit(-1); + } + + parse_args(argc, argv); + + // the default metrics type for stdout output + metrics_stdout metrics_screen; + metrics_screen.set_handle(&enb); + + // the CSV file writer + metrics_csv metrics_file(csv_file_name); + metrics_file.set_handle(&enb); + + // create metrics hub and register metrics for stdout + srslte::metrics_hub metricshub; + metricshub.init(&enb, period); + metricshub.add_listener(&metrics_screen); + metricshub.add_listener(&metrics_file); + + // enable printing + metrics_screen.toggle_print(true); + + std::cout << "Running for 2 seconds .." << std::endl; + usleep(2e6); + + metricshub.stop(); + return 0; +}