Merge pull request #24 from softwareradiosystems/ue_metrics

UE metrics
This commit is contained in:
Ismael Gomez 2017-09-24 19:15:46 +02:00 committed by GitHub
commit a5bba6e248
13 changed files with 356 additions and 71 deletions

View File

@ -24,7 +24,7 @@ template<typename metrics_t>
class metrics_listener
{
public:
virtual void set_metrics(metrics_t &m) = 0;
virtual void set_metrics(metrics_t &m, float report_period_secs=1.0) = 0;
};
template<typename metrics_t>
@ -38,6 +38,7 @@ public:
}
void stop() {
thread_cancel();
wait_thread_finish();
}
void add_listener(metrics_listener<metrics_t> *listener) {

64
srsue/hdr/metrics_csv.h Normal file
View File

@ -0,0 +1,64 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE 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.
*
* srsUE 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/.
*
*/
/******************************************************************************
* File: metrics_csv.h
* Description: Metrics class writing to CSV file.
*****************************************************************************/
#ifndef METRICS_CSV_H
#define METRICS_CSV_H
#include <pthread.h>
#include <stdint.h>
#include <string>
#include <iostream>
#include <fstream>
#include "srslte/common/metrics_hub.h"
#include "ue_metrics_interface.h"
namespace srsue {
class metrics_csv : public srslte::metrics_listener<ue_metrics_t>
{
public:
metrics_csv(std::string filename);
void set_metrics(ue_metrics_t &m, float report_period_secs);
void set_ue_handle(ue_metrics_interface *ue_);
private:
std::string float_to_string(float f, int digits, bool add_semicolon = true);
std::ofstream file;
ue_metrics_interface* ue;
uint32_t n_reports;
};
} // namespace srsue
#endif // METRICS_CSV_H

View File

@ -36,36 +36,28 @@
#include <stdint.h>
#include <string>
#include "srslte/common/metrics_hub.h"
#include "ue_metrics_interface.h"
namespace srsue {
class metrics_stdout
class metrics_stdout : public srslte::metrics_listener<ue_metrics_t>
{
public:
metrics_stdout();
bool init(ue_metrics_interface *u, float report_period_secs=1.0);
void stop();
void toggle_print(bool b);
static void* metrics_thread_start(void *m);
void metrics_thread_run();
void set_metrics(ue_metrics_t &m, float report_period_secs);
void set_ue_handle(ue_metrics_interface *ue_);
private:
void print_metrics();
void print_disconnect();
std::string float_to_string(float f, int digits);
std::string float_to_eng_string(float f, int digits);
std::string int_to_eng_string(int f, int digits);
ue_metrics_interface *ue_;
bool started;
bool do_print;
pthread_t metrics_thread;
ue_metrics_t metrics;
float metrics_report_period; // seconds
uint8_t n_reports;
bool do_print;
uint8_t n_reports;
ue_metrics_interface* ue;
};
} // namespace srsue

View File

@ -107,6 +107,8 @@ typedef struct {
float metrics_period_secs;
bool pregenerate_signals;
std::string ue_cateogry;
bool metrics_csv_enable;
std::string metrics_csv_filename;
}expert_args_t;
typedef struct {

View File

@ -29,6 +29,7 @@
#include <stdint.h>
#include "srslte/common/metrics_hub.h"
#include "upper/gw_metrics.h"
#include "srslte/upper/rlc_metrics.h"
#include "mac/mac_metrics.h"
@ -52,10 +53,11 @@ typedef struct {
}ue_metrics_t;
// UE interface
class ue_metrics_interface
class ue_metrics_interface : public srslte::metrics_interface<ue_metrics_t>
{
public:
virtual bool get_metrics(ue_metrics_t &m) = 0;
virtual bool is_attached() = 0;
};
} // namespace srsue

View File

@ -31,7 +31,7 @@ if (RPATH)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
endif (RPATH)
add_executable(srsue main.cc ue_base.cc ue.cc metrics_stdout.cc)
add_executable(srsue main.cc ue_base.cc ue.cc metrics_stdout.cc metrics_csv.cc)
target_link_libraries(srsue srsue_mac
srsue_phy
srsue_upper

View File

@ -38,6 +38,8 @@
#include "ue.h"
#include "metrics_stdout.h"
#include "metrics_csv.h"
#include "srslte/common/metrics_hub.h"
#include "srslte/version.h"
using namespace std;
@ -134,6 +136,14 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<float>(&args->expert.metrics_period_secs)->default_value(1.0),
"Periodicity for metrics in seconds")
("expert.metrics_csv_enable",
bpo::value<bool>(&args->expert.metrics_csv_enable)->default_value(false),
"Write UE metrics to CSV file")
("expert.metrics_csv_filename",
bpo::value<string>(&args->expert.metrics_csv_filename)->default_value("/tmp/ue_metrics.csv"),
"Metrics CSV filename")
("expert.pregenerate_signals",
bpo::value<bool>(&args->expert.pregenerate_signals)->default_value(false),
"Pregenerate uplink signals after attach. Improves CPU performance.")
@ -320,13 +330,13 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
static bool running = true;
static bool do_metrics = false;
metrics_stdout metrics_screen;
void sig_int_handler(int signo) {
running = false;
}
void *input_loop(void *m) {
metrics_stdout *metrics = (metrics_stdout *) m;
char key;
while (running) {
cin >> key;
@ -337,7 +347,7 @@ void *input_loop(void *m) {
} else {
cout << "Enter t to restart trace." << endl;
}
metrics->toggle_print(do_metrics);
metrics_screen.toggle_print(do_metrics);
}
}
return NULL;
@ -345,6 +355,7 @@ void *input_loop(void *m) {
int main(int argc, char *argv[])
{
srslte::metrics_hub<ue_metrics_t> metricshub;
signal(SIGINT, sig_int_handler);
all_args_t args;
parse_args(&args, argc, argv);
@ -361,11 +372,18 @@ int main(int argc, char *argv[])
exit(1);
}
metrics_stdout metrics;
metrics.init(ue, args.expert.metrics_period_secs);
metricshub.init(ue, args.expert.metrics_period_secs);
metricshub.add_listener(&metrics_screen);
metrics_screen.set_ue_handle(ue);
metrics_csv metrics_file(args.expert.metrics_csv_filename);
if (args.expert.metrics_csv_enable) {
metricshub.add_listener(&metrics_file);
metrics_file.set_ue_handle(ue);
}
pthread_t input;
pthread_create(&input, NULL, &input_loop, &metrics);
pthread_create(&input, NULL, &input_loop, &args);
bool plot_started = false;
bool signals_pregenerated = false;
@ -383,7 +401,7 @@ int main(int argc, char *argv[])
sleep(1);
}
pthread_cancel(input);
metrics.stop();
metricshub.stop();
ue->stop();
ue->cleanup();
cout << "--- exiting ---" << endl;

109
srsue/src/metrics_csv.cc Normal file
View File

@ -0,0 +1,109 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2015 The srsUE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE 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.
*
* srsUE 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 "metrics_csv.h"
#include <unistd.h>
#include <sstream>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <iomanip>
#include <iostream>
#include <stdio.h>
using namespace std;
namespace srsue{
metrics_csv::metrics_csv(std::string filename)
:n_reports(0)
,ue(NULL)
{
file.open(filename.c_str());
}
void metrics_csv::set_ue_handle(ue_metrics_interface *ue_)
{
ue = ue_;
}
void metrics_csv::set_metrics(ue_metrics_t &metrics, float metrics_report_period)
{
if (file.is_open()) {
if (!ue->is_attached()) {
file << "# disconnected" << endl;
return;
}
if(n_reports == 0) {
file << "time;rsrp;pl;cfo;dl_mcs;dl_snr;dl_turbo;dl_brate;dl_bler;ul_mcs;ul_buff;ul_brate;ul_bler;rf_o;rf_u;rf_l" << endl;
}
file << (metrics_report_period*n_reports) << ";";
file << float_to_string(metrics.phy.dl.rsrp, 2);
file << float_to_string(metrics.phy.dl.pathloss, 2);
file << float_to_string(metrics.phy.sync.cfo, 2);
file << float_to_string(metrics.phy.dl.mcs, 2);
file << float_to_string(metrics.phy.dl.sinr, 2);
file << float_to_string(metrics.phy.dl.turbo_iters, 2);
file << float_to_string((float) metrics.mac.rx_brate/metrics_report_period, 2);
if (metrics.mac.rx_pkts > 0) {
file << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1);
} else {
file << float_to_string(0, 2);
}
file << float_to_string(metrics.phy.ul.mcs, 2);
file << float_to_string((float) metrics.mac.ul_buffer, 2);
file << float_to_string((float) metrics.mac.tx_brate/metrics_report_period, 2);
if (metrics.mac.tx_pkts > 0) {
file << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1);
} else {
file << float_to_string(0, 2);
}
file << float_to_string(metrics.rf.rf_o, 2);
file << float_to_string(metrics.rf.rf_u, 2);
file << float_to_string(metrics.rf.rf_l, 2, false);
file << endl;
n_reports++;
} else {
std::cout << "Error, couldn't write CSV file." << std::endl;
}
}
std::string metrics_csv::float_to_string(float f, int digits, bool add_semicolon)
{
std::ostringstream os;
const int precision = (f == 0.0) ? digits-1 : digits - log10(fabs(f))-2*DBL_EPSILON;
os << std::fixed << std::setprecision(precision) << f;
if (add_semicolon)
os << ';';
return os.str();
}
} // namespace srsue

View File

@ -48,29 +48,15 @@ char const * const prefixes[2][9] =
};
metrics_stdout::metrics_stdout()
:started(false)
,do_print(false)
:do_print(false)
,n_reports(10)
,ue(NULL)
{
}
bool metrics_stdout::init(ue_metrics_interface *u, float report_period_secs)
void metrics_stdout::set_ue_handle(ue_metrics_interface *ue_)
{
ue_ = u;
metrics_report_period = report_period_secs;
started = true;
pthread_create(&metrics_thread, NULL, &metrics_thread_start, this);
return true;
}
void metrics_stdout::stop()
{
if(started)
{
started = false;
pthread_join(metrics_thread, NULL);
}
ue = ue_;
}
void metrics_stdout::toggle_print(bool b)
@ -78,31 +64,17 @@ void metrics_stdout::toggle_print(bool b)
do_print = b;
}
void* metrics_stdout::metrics_thread_start(void *m_)
{
metrics_stdout *m = (metrics_stdout*)m_;
m->metrics_thread_run();
return NULL;
}
void metrics_stdout::metrics_thread_run()
void metrics_stdout::set_metrics(ue_metrics_t &metrics, float metrics_report_period)
{
while(started)
{
usleep(metrics_report_period*1e6);
if(ue_->get_metrics(metrics)) {
print_metrics();
} else {
print_disconnect();
}
}
}
void metrics_stdout::print_metrics()
{
if(!do_print)
if(!do_print || ue == NULL)
return;
if (!ue->is_attached()) {
cout << "--- disconnected ---" << endl;
return;
}
if(++n_reports > 10)
{
n_reports = 0;
@ -138,13 +110,6 @@ void metrics_stdout::print_metrics()
}
void metrics_stdout::print_disconnect()
{
if(do_print) {
cout << "--- disconnected ---" << endl;
}
}
std::string metrics_stdout::float_to_string(float f, int digits)
{
std::ostringstream os;

View File

@ -247,7 +247,7 @@ void ue::stop()
bool ue::is_attached()
{
return (EMM_STATE_REGISTERED == nas.get_state());
return (RRC_STATE_CONNECTED == rrc.get_state());
}
void ue::start_plot() {

View File

@ -21,3 +21,7 @@
add_subdirectory(phy)
add_subdirectory(mac)
add_subdirectory(upper)
add_executable(metrics_test metrics_test.cc ../src/metrics_stdout.cc ../src/metrics_csv.cc)
target_link_libraries(metrics_test srslte_phy srslte_common)
add_test(metrics_test metrics_test -o ${CMAKE_CURRENT_BINARY_DIR}/ue_metrics.csv)

122
srsue/test/metrics_test.cc Normal file
View File

@ -0,0 +1,122 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE 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.
*
* srsUE 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 <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include "ue_metrics_interface.h"
#include "srslte/common/metrics_hub.h"
#include "metrics_stdout.h"
#include "metrics_csv.h"
using namespace srsue;
namespace srsue {
char *csv_file_name = NULL;
// fake classes
class ue_dummy : public ue_metrics_interface
{
public:
bool get_metrics(ue_metrics_t &m)
{
// fill dummy values
bzero(&m, sizeof(ue_metrics_t));
m.rf.rf_o = 10;
m.phy.dl.rsrp = -10.0;
m.phy.dl.pathloss = 74;
return true;
}
bool is_attached()
{
return true;
}
};
}
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;
ue_dummy ue;
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_ue_handle(&ue);
// the CSV file writer
metrics_csv metrics_file(csv_file_name);
metrics_file.set_ue_handle(&ue);
// create metrics hub and register metrics for stdout
srslte::metrics_hub<ue_metrics_t> metricshub;
metricshub.init(&ue, 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;
}

View File

@ -130,6 +130,10 @@ enable = false
#
# pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance.
#
# metrics_csv_enable: Write UE metrics to CSV file.
#
# metrics_csv_filename: File path to use for CSV metrics.
#
#####################################################################
[expert]
#ue_category = 4
@ -149,6 +153,8 @@ enable = false
#sss_algorithm = full
#estimator_fil_w = 0.1
#pregenerate_signals = false
#metrics_csv_enable = false
#metrics_csv_filename = /tmp/ue_metrics.csv
#####################################################################
# Manual RF calibration