Merge remote-tracking branch 'origin/t-gnb-mac' into integration_2025_w35 (!3538)

add a new graphical T tracer to see gNB MAC scheduling decisions

May be useful for debugging
This commit is contained in:
Robert Schmidt
2025-08-27 15:14:55 +02:00
27 changed files with 618 additions and 103 deletions
+1
View File
@@ -3,6 +3,7 @@
genids
tracer/enb
tracer/gnb
tracer/gnb_mac
tracer/extract_config
tracer/record
tracer/replay
+22 -2
View File
@@ -92,9 +92,13 @@ ID = UE_PHY_INITIATE_RA_PROCEDURE
GROUP = ALL:PHY:UE:WIRESHARK
FORMAT = int,frame : int,subframe_or_slot : int,preamble : int,power
ID = GNB_PHY_DL_TICK
DESC = gNodeB downlink tick - one tick per ms at start of downlink processing
DESC = gNodeB downlink tick - one tick per slot at start of downlink processing
GROUP = ALL:PHY:GRAPHIC:GNB
FORMAT = int,gNB_ID : int,frame : int,subframe
FORMAT = int,gNB_ID : int,frame : int,slot
ID = GNB_PHY_UL_TICK
DESC = gNodeB uplink tick - one tick per slot at start of uplink processing
GROUP = ALL:PHY:GRAPHIC:GNB
FORMAT = int,gNB_ID : int,frame : int,slot
ID = ENB_PHY_MIB
DESC = MIB data
GROUP = ALL:PHY:ENB:WIRESHARK
@@ -221,6 +225,22 @@ ID = NRUE_MAC_DL_RAR_PDU_WITH_DATA
DESC = NR MAC downlink PDU for RAR
GROUP = ALL:MAC:UE:WIRESHARK
FORMAT = int,rnti : int,frame : int,slot : buffer,data
ID = GNB_MAC_DL
DESC = NR MAC downlink scheduler decision for an UE
GROUP = ALL:MAC:GNB
FORMAT = int,rnti : int,frame : int,slot : int,mcs : int,tbs
ID = GNB_MAC_LCID_DL
DESC = NR MAC downlink scheduler decision for an UE for a specific LCID
GROUP = ALL:MAC:GNB
FORMAT = int,rnti : int,frame : int,slot : int,lcid : int,data_size : int,tx_list_occupancy
ID = GNB_MAC_UL
DESC = NR MAC uplink scheduler decision for an UE
GROUP = ALL:MAC:GNB
FORMAT = int,rnti : int,frame : int,slot : int,mcs : int,tbs
ID = GNB_MAC_LCID_UL
DESC = NR MAC uplink traffic received for an UE for a specific LCID
GROUP = ALL:MAC:GNB
FORMAT = int,rnti : int,frame : int,slot : int,lcid : int,data_size
#RLC logs
ID = ENB_RLC_DL
+7 -3
View File
@@ -62,9 +62,13 @@ if(T_TRACER_GUI)
tracer_logger tracer_view tracer_events)
target_link_libraries(gnb PRIVATE png)
add_executable(ue ue.c)
target_link_libraries(ue PRIVATE tracer_utils tracer_filter tracer_gui
add_executable(gnb_mac gnb_mac.c)
target_link_libraries(gnb_mac PRIVATE tracer_utils tracer_filter tracer_gui
tracer_logger tracer_view tracer_events)
add_executable(ue ue.c)
target_link_libraries(ue PRIVATE tracer_utils tracer_view tracer_gui
tracer_logger tracer_filter tracer_events)
target_link_libraries(ue PRIVATE png)
add_executable(vcd vcd.c)
@@ -77,5 +81,5 @@ if(T_TRACER_GUI)
add_subdirectory(gui)
add_dependencies(T_tools enb gnb ue vcd to_vcd)
add_dependencies(T_tools enb gnb gnb_mac ue vcd to_vcd)
endif()
+11 -6
View File
@@ -8,7 +8,7 @@ XLIBS=-lX11 -lpng -lXft
all: record replay extract_config textlog enb ue vcd macpdu2wireshark \
extract_input_subframe extract_output_subframe to_vcd extract multi \
gnb t_tracer_app_gnb t_tracer_app_ue
gnb t_tracer_app_gnb t_tracer_app_ue gnb_mac
record: utils.o record.o database.o configuration.o
$(CC) $(CFLAGS) -o record $^ $(LIBS)
@@ -65,14 +65,18 @@ gnb: utils.o gnb.o database.o event.o handler.o configuration.o \
filter/filter.a
$(CC) $(CFLAGS) -o gnb $^ $(LIBS) $(XLIBS)
t_tracer_app_gnb: utils.o t_tracer_app_gnb.o database.o event.o handler.o configuration.o \
logger/logger.a filter/filter.a
t_tracer_app_gnb: utils.o t_tracer_app_gnb.o database.o event.o handler.o \
configuration.o logger/logger.a filter/filter.a
$(CC) $(CFLAGS) -o t_tracer_app_gnb $^ $(LIBS) $(XLIBS)
t_tracer_app_ue: utils.o t_tracer_app_ue.o database.o event.o handler.o configuration.o \
logger/logger.a filter/filter.a
t_tracer_app_ue: utils.o t_tracer_app_ue.o database.o event.o handler.o \
configuration.o logger/logger.a filter/filter.a
$(CC) $(CFLAGS) -o t_tracer_app_ue $^ $(LIBS) $(XLIBS)
gnb_mac: gnb_mac.o gui/gui.a view/view.a logger/logger.a filter/filter.a \
utils.o database.o configuration.o handler.o event.o
$(CC) $(CFLAGS) -o gnb_mac $^ $(LIBS) $(XLIBS)
multi.o: ../incgen/T_IDs.h
../incgen/T_IDs.h: ../T_messages.txt
@@ -98,7 +102,8 @@ filter/filter.a:
clean:
rm -f *.o core tracer_remote textlog enb ue vcd record replay
rm -f extract_config macpdu2wireshark extract_input_subframe
rm -f extract_output_subframe to_vcd extract multi gnb t_tracer_app_gnb t_tracer_app_ue
rm -f extract_output_subframe to_vcd extract multi gnb
rm -f t_tracer_app_gnb t_tracer_app_ue gnb_mac
cd gui && $(MAKE) clean
cd view && $(MAKE) clean
cd logger && $(MAKE) clean
+8 -8
View File
@@ -340,12 +340,12 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database,
xy_plot_set_range(g, w, 0, 1024*10, -10, 80);
l = new_ttilog(h, database,
"ENB_PHY_PUCCH_1_ENERGY", "frame", "subframe", "threshold", 0);
v = new_view_tti(10, g, w, new_color(g, "#ff0000"));
v = new_view_tti(10, g, w, new_color(g, "#ff0000"), 10);
logger_add_view(l, v);
e->pucch1_energy_ue_threshold_logger = l;
l = new_ttilog(h, database,
"ENB_PHY_PUCCH_1_ENERGY", "frame", "subframe", "energy", 1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"));
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10);
logger_add_view(l, v);
e->pucch1_energy_ue_energy_logger = l;
@@ -368,7 +368,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database,
widget_add_child(g, line, w, -1);
l = new_ticked_ttilog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe",
"ENB_PHY_DLSCH_UE_DCI", "mcs", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"));
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10);
logger_add_view(l, v);
e->dl_mcs_logger = l;
@@ -379,7 +379,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database,
widget_add_child(g, line, w, -1);
l = new_ticked_ttilog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe",
"ENB_PHY_ULSCH_UE_DCI", "mcs", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"));
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10);
logger_add_view(l, v);
e->ul_mcs_logger = l;
@@ -394,8 +394,8 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database,
widget_add_child(g, col, w, -1);
container_set_child_growable(g, col, w, 1);
l = new_throughputlog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe",
"ENB_PHY_DLSCH_UE_DCI", "TBS");
v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2);
"ENB_PHY_DLSCH_UE_DCI", "TBS", 10);
v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 10);
logger_add_view(l, v);
/* UE x UL PHY (truly: DCI) throughput */
@@ -409,8 +409,8 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database,
widget_add_child(g, col, w, -1);
container_set_child_growable(g, col, w, 1);
l = new_throughputlog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe",
"ENB_PHY_ULSCH_UE_DCI", "TBS");
v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2);
"ENB_PHY_ULSCH_UE_DCI", "TBS", 10);
v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 10);
logger_add_view(l, v);
/* downlink/uplink UE DCIs */
+332
View File
@@ -0,0 +1,332 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "utils.h"
#include "gui/gui.h"
#include "view/view.h"
#include "logger/logger.h"
#include "filter/filter.h"
#include "database.h"
#include "configuration.h"
#include "handler.h"
typedef struct {
int used;
} ue_list_item;
typedef struct {
widget *container;
} gnb_gui;
typedef struct {
int socket;
gui *g;
gnb_gui *gg;
event_handler *h;
void *database;
ue_list_item ues[65536];
int rnti_arg;
} gnb_data;
void *gui_thread(void *_g)
{
gui *g = _g;
gui_loop(g);
return 0;
}
void add_ue(gnb_data *gd, int rnti, int lcid)
{
event_handler *h = gd->h;
void *database = gd->database;
gnb_gui *gg = gd->gg;
gui *g = gd->g;
widget *line;
widget *w, *w2, *col;
view *v;
logger *l;
gd->ues[rnti].used = 1;
line = new_container(g, HORIZONTAL);
widget_add_child(g, gg->container, line, -1);
/* label */
char s[512];
sprintf(s, "UE %d", rnti);
widget *label = new_label(g, s);
widget_add_child(g, line, label, -1);
/* DL MCS */
w = new_xy_plot(g, 128, 55, "DL mcs", 20);
xy_plot_set_range(g, w, 0, 1024*20, -2, 30);
widget_add_child(g, line, w, -1);
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
"GNB_MAC_DL", "mcs", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
logger_add_view(l, v);
logger_set_filter(l,
filter_eq(
filter_evarg(database, "GNB_MAC_DL", "rnti"),
filter_int(rnti)));
/* DL TBS */
col = new_container(g, VERTICAL);
widget_add_child(g, line, col, -1);
w = new_xy_plot(g, 70, 10, "DL tbs", 35);
w2 = new_textarea(g, 70, 11, 64);
xy_plot_set_range(g, w, 0, 1024*20, 0, 1000);
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
widget_add_child(g, col, w2, -1);
widget_add_child(g, col, w, -1);
container_set_child_growable(g, col, w, 1);
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
"GNB_MAC_DL", "tbs", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
view_tti_enable_automax(v, w2);
logger_add_view(l, v);
logger_set_filter(l,
filter_eq(
filter_evarg(database, "GNB_MAC_DL", "rnti"),
filter_int(rnti)));
/* DL lcid throughput */
col = new_container(g, VERTICAL);
widget_add_child(g, line, col, -1);
sprintf(s, "DL lcid %d", lcid);
w = new_xy_plot(g, 70, 10, s, 35);
w2 = new_textarea(g, 70, 11, 64);
xy_plot_set_range(g, w, 0, 1000, 0, 100000);
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
widget_add_child(g, col, w2, -1);
widget_add_child(g, col, w, -1);
container_set_child_growable(g, col, w, 1);
l = new_throughputlog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
"GNB_MAC_LCID_DL", "data_size", 20);
v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 20);
logger_add_view(l, v);
logger_set_filter(l,
filter_and(
filter_eq(
filter_evarg(database, "GNB_MAC_LCID_DL", "rnti"),
filter_int(rnti)),
filter_eq(
filter_evarg(database, "GNB_MAC_LCID_DL", "lcid"),
filter_int(lcid))));
/* UL MCS */
w = new_xy_plot(g, 128, 55, "UL mcs", 20);
xy_plot_set_range(g, w, 0, 1024*20, -2, 30);
widget_add_child(g, line, w, -1);
/* GNB_PHY_DL_TICK (and not UL) because GNB_MAC_UL is from DCI */
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
"GNB_MAC_UL", "mcs", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
logger_add_view(l, v);
logger_set_filter(l,
filter_eq(
filter_evarg(database, "GNB_MAC_UL", "rnti"),
filter_int(rnti)));
/* UL TBS */
col = new_container(g, VERTICAL);
widget_add_child(g, line, col, -1);
w = new_xy_plot(g, 70, 10, "UL tbs", 35);
w2 = new_textarea(g, 70, 11, 64);
xy_plot_set_range(g, w, 0, 1024*20, 0, 1000);
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
widget_add_child(g, col, w2, -1);
widget_add_child(g, col, w, -1);
container_set_child_growable(g, col, w, 1);
/* GNB_PHY_DL_TICK (and not UL) because GNB_MAC_UL is from DCI */
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
"GNB_MAC_UL", "tbs", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
view_tti_enable_automax(v, w2);
logger_add_view(l, v);
logger_set_filter(l,
filter_eq(
filter_evarg(database, "GNB_MAC_UL", "rnti"),
filter_int(rnti)));
/* UL lcid throughput */
col = new_container(g, VERTICAL);
widget_add_child(g, line, col, -1);
sprintf(s, "UL lcid %d", lcid);
w = new_xy_plot(g, 70, 10, s, 35);
w2 = new_textarea(g, 70, 11, 64);
xy_plot_set_range(g, w, 0, 1000, 0, 100000);
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
widget_add_child(g, col, w2, -1);
widget_add_child(g, col, w, -1);
container_set_child_growable(g, col, w, 1);
l = new_throughputlog(h, database, "GNB_PHY_UL_TICK", "frame", "slot",
"GNB_MAC_LCID_UL", "data_size", 20);
v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 20);
logger_add_view(l, v);
logger_set_filter(l,
filter_and(
filter_eq(
filter_evarg(database, "GNB_MAC_LCID_UL", "rnti"),
filter_int(rnti)),
filter_eq(
filter_evarg(database, "GNB_MAC_LCID_UL", "lcid"),
filter_int(lcid))));
/* lcid RLC tx buffer occupancy */
col = new_container(g, VERTICAL);
widget_add_child(g, line, col, -1);
sprintf(s, "rlc tx %d", lcid);
w = new_xy_plot(g, 70, 10, s, 35);
w2 = new_textarea(g, 70, 11, 64);
xy_plot_set_range(g, w, 0, 1024*20, 0, 1000);
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
widget_add_child(g, col, w2, -1);
widget_add_child(g, col, w, -1);
container_set_child_growable(g, col, w, 1);
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
"GNB_MAC_LCID_DL", "tx_list_occupancy", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
view_tti_enable_automax(v, w2);
logger_add_view(l, v);
logger_set_filter(l,
filter_and(
filter_eq(
filter_evarg(database, "GNB_MAC_LCID_DL", "rnti"),
filter_int(rnti)),
filter_eq(
filter_evarg(database, "GNB_MAC_LCID_DL", "lcid"),
filter_int(lcid))));
}
void build_gui(gnb_gui *gg, gui *g)
{
widget *main_window;
main_window = new_toplevel_window(g, 900, 1000, "gNB MAC tracer");
gg->container = new_container(g, VERTICAL);
widget_add_child(g, main_window, gg->container, -1);
}
void usage(void)
{
printf(
"options:\n"
" -d <database file> this option is mandatory\n"
" -ip <host> connect to given IP address (default %s)\n"
" -p <port> connect to given port (default %d)\n",
DEFAULT_REMOTE_IP,
DEFAULT_REMOTE_PORT
);
exit(1);
}
void check_new_ue(void *_gd, event e)
{
gnb_data *gd = _gd;
int rnti = e.e[gd->rnti_arg].i;
if (!gd->ues[rnti].used)
add_ue(gd, rnti, 4);
}
int main(int n, char **v)
{
gui *g;
gnb_gui gg;
gnb_data *gd;
char *database_filename = NULL;
void *database;
char *ip = DEFAULT_REMOTE_IP;
int port = DEFAULT_REMOTE_PORT;
event_handler *h;
int *is_on;
int number_of_events;
int i;
for (i = 1; i < n; i++) {
if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
if (!strcmp(v[i], "-d")) { if (i > n-2) usage(); database_filename = v[++i]; continue; }
if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
if (!strcmp(v[i], "-p")) { if (i > n-2) usage(); port = atoi(v[++i]); continue; }
usage();
}
if (database_filename == NULL) {
printf("ERROR: provide a database file (-d)\n");
exit(1);
}
database = parse_database(database_filename);
load_config_file(database_filename);
number_of_events = number_of_ids(database);
is_on = calloc(number_of_events, sizeof(int));
if (is_on == NULL) abort();
on_off(database, "GNB_PHY_DL_TICK", is_on, 1);
on_off(database, "GNB_MAC_DL", is_on, 1);
on_off(database, "GNB_MAC_LCID_DL", is_on, 1);
on_off(database, "GNB_PHY_UL_TICK", is_on, 1);
on_off(database, "GNB_MAC_UL", is_on, 1);
on_off(database, "GNB_MAC_LCID_UL", is_on, 1);
gd = calloc(1, sizeof(*gd)); if (!gd) abort();
h = new_handler(database);
g = gui_init();
new_thread(gui_thread, g);
build_gui(&gg, g);
gd->g = g;
gd->gg = &gg;
gd->h = h;
gd->database = database;
/* get rnti_arg from event GNB_MAC_DL */
int event_id = event_id_from_name(database, "GNB_MAC_DL");
database_event_format f = get_format(database, event_id);
gd->rnti_arg = -1;
for (i = 0; i < f.count; i++) {
if (!strcmp(f.name[i], "rnti")) gd->rnti_arg = i;
}
if (gd->rnti_arg == -1) {
printf("fatal: event 'GNB_MAC_DL' does not have argument 'rnti'\n");
exit(1);
}
if (strcmp(f.type[gd->rnti_arg], "int") != 0) {
printf("fatal: argument 'rnti' of event 'GNB_MAC_DL' is not 'int'\n");
exit(1);
}
register_handler_function(h, event_id, check_new_ue, gd);
OBUF ebuf = {.osize = 0, .omaxsize = 0, .obuf = NULL};
gd->socket = -1;
restart:
clear_remote_config();
if (gd->socket != -1) close(gd->socket);
gd->socket = connect_to(ip, port);
/* send the first message - activate selected traces */
int t = 1;
if (socket_send(gd->socket, &t, 1) == -1 ||
socket_send(gd->socket, &number_of_events, sizeof(int)) == -1 ||
socket_send(gd->socket, is_on, number_of_events * sizeof(int)) == -1)
goto restart;
while (1) {
event e;
e = get_event(gd->socket, &ebuf, database);
if (e.type == -1) goto restart;
handle_event(h, e);
}
return 0;
}
+2
View File
@@ -54,6 +54,8 @@ void container_set_child_growable(gui *_gui, widget *_this,
int xy_plot_new_plot(gui *gui, widget *this, int color);
void xy_plot_set_range(gui *gui, widget *this,
float xmin, float xmax, float ymin, float ymax);
void xy_plot_get_range(gui *gui, widget *this,
float *xmin, float *xmax, float *ymin, float *ymax);
void xy_plot_set_points(gui *gui, widget *this,
int plot, int npoints, float *x, float *y);
void xy_plot_get_dimensions(gui *gui, widget *this, int *width, int *height);
+16
View File
@@ -280,6 +280,22 @@ void xy_plot_set_range(gui *_gui, widget *_this,
gunlock(g);
}
void xy_plot_get_range(gui *_gui, widget *_this,
float *xmin, float *xmax, float *ymin, float *ymax)
{
struct gui *g = _gui;
struct xy_plot_widget *this = _this;
glock(g);
*xmin = this->xmin;
*xmax = this->xmax;
*ymin = this->ymin;
*ymax = this->ymax;
gunlock(g);
}
void xy_plot_set_points(gui *_gui, widget *_this, int plot,
int npoints, float *x, float *y)
{
+2 -2
View File
@@ -15,8 +15,8 @@ logger *new_ticked_ttilog(void *event_handler, void *database,
char *event_name, char *data_varname,
int convert_to_dB, float empty_value);
logger *new_throughputlog(void *event_handler, void *database,
char *tick_event_name, char *frame_varname, char *subframe_varname,
char *event_name, char *data_varname);
char *tick_event_name, char *frame_varname, char *tick_varname,
char *event_name, char *data_varname, int ticks_per_frame);
logger *new_timelog(void *event_handler, void *database, char *event_name);
logger *new_ticklog(void *event_handler, void *database,
char *event_name, char *frame_name, char *subframe_name);
+44 -33
View File
@@ -13,13 +13,14 @@ struct throughputlog {
struct logger common;
void *database;
int tick_frame_arg;
int tick_subframe_arg;
int tick_tick_arg;
int data_frame_arg;
int data_subframe_arg;
int data_tick_arg;
int data_arg;
int last_tick_frame;
int last_tick_subframe;
unsigned long bits[1000];
int last_tick_tick;
int ticks_per_frame;
unsigned long *bits;
unsigned long total;
int insert_point;
char *tick_event_name;
@@ -32,16 +33,16 @@ static void _event(void *p, event e)
{
struct throughputlog *l = p;
int frame;
int subframe;
int tick;
unsigned long value;
if (l->common.filter != NULL && filter_eval(l->common.filter, e) == 0)
return;
frame = e.e[l->data_frame_arg].i;
subframe = e.e[l->data_subframe_arg].i;
tick = e.e[l->data_tick_arg].i;
if (frame != l->last_tick_frame || subframe != l->last_tick_subframe) {
if (frame != l->last_tick_frame || tick != l->last_tick_tick) {
printf("WARNING: %s:%d: data comes without previous tick!\n",
__FILE__, __LINE__);
return;
@@ -62,28 +63,34 @@ static void _tick_event(void *p, event e)
struct throughputlog *l = p;
int i;
int frame;
int subframe;
int tick;
if (l->tick_filter != NULL && filter_eval(l->tick_filter, e) == 0)
return;
frame = e.e[l->tick_frame_arg].i;
subframe = e.e[l->tick_subframe_arg].i;
tick = e.e[l->tick_tick_arg].i;
for (i = 0; i < l->common.vsize; i++)
l->common.v[i]->append(l->common.v[i], frame, subframe, (double)l->total);
l->common.v[i]->append(l->common.v[i], frame, tick, (double)l->total);
l->insert_point = (l->insert_point + 1) % 1000;
l->total -= l->bits[l->insert_point];
l->bits[l->insert_point] = 0;
while (l->last_tick_frame != frame || l->last_tick_tick != tick) {
l->insert_point = (l->insert_point + 1) % (100 * l->ticks_per_frame);
l->total -= l->bits[l->insert_point];
l->bits[l->insert_point] = 0;
l->last_tick_tick++;
if (l->last_tick_tick == l->ticks_per_frame) {
l->last_tick_tick = 0;
l->last_tick_frame++;
l->last_tick_frame %= 1024;
}
}
l->last_tick_frame = frame;
l->last_tick_subframe = subframe;
}
logger *new_throughputlog(event_handler *h, void *database,
char *tick_event_name, char *frame_varname, char *subframe_varname,
char *event_name, char *data_varname)
char *tick_event_name, char *frame_varname, char *tick_varname,
char *event_name, char *data_varname, int ticks_per_frame)
{
struct throughputlog *ret;
int event_id;
@@ -106,21 +113,21 @@ logger *new_throughputlog(event_handler *h, void *database,
f = get_format(database, event_id);
/* look for frame and subframe */
/* look for frame and tick */
ret->tick_frame_arg = -1;
ret->tick_subframe_arg = -1;
ret->tick_tick_arg = -1;
for (i = 0; i < f.count; i++) {
if (!strcmp(f.name[i], frame_varname)) ret->tick_frame_arg = i;
if (!strcmp(f.name[i], subframe_varname)) ret->tick_subframe_arg = i;
if (!strcmp(f.name[i], tick_varname)) ret->tick_tick_arg = i;
}
if (ret->tick_frame_arg == -1) {
printf("%s:%d: frame argument '%s' not found in event '%s'\n",
__FILE__, __LINE__, frame_varname, event_name);
abort();
}
if (ret->tick_subframe_arg == -1) {
printf("%s:%d: subframe argument '%s' not found in event '%s'\n",
__FILE__, __LINE__, subframe_varname, event_name);
if (ret->tick_tick_arg == -1) {
printf("%s:%d: tick argument '%s' not found in event '%s'\n",
__FILE__, __LINE__, tick_varname, event_name);
abort();
}
if (strcmp(f.type[ret->tick_frame_arg], "int") != 0) {
@@ -128,9 +135,9 @@ logger *new_throughputlog(event_handler *h, void *database,
__FILE__, __LINE__, frame_varname);
abort();
}
if (strcmp(f.type[ret->tick_subframe_arg], "int") != 0) {
if (strcmp(f.type[ret->tick_tick_arg], "int") != 0) {
printf("%s:%d: argument '%s' has wrong type (should be 'int')\n",
__FILE__, __LINE__, subframe_varname);
__FILE__, __LINE__, tick_varname);
abort();
}
@@ -141,13 +148,13 @@ logger *new_throughputlog(event_handler *h, void *database,
f = get_format(database, event_id);
/* look for frame, subframe and data args */
/* look for frame, tick and data args */
ret->data_frame_arg = -1;
ret->data_subframe_arg = -1;
ret->data_tick_arg = -1;
ret->data_arg = -1;
for (i = 0; i < f.count; i++) {
if (!strcmp(f.name[i], frame_varname)) ret->data_frame_arg = i;
if (!strcmp(f.name[i], subframe_varname)) ret->data_subframe_arg = i;
if (!strcmp(f.name[i], tick_varname)) ret->data_tick_arg = i;
if (!strcmp(f.name[i], data_varname)) ret->data_arg = i;
}
if (ret->data_frame_arg == -1) {
@@ -155,9 +162,9 @@ logger *new_throughputlog(event_handler *h, void *database,
__FILE__, __LINE__, frame_varname, event_name);
abort();
}
if (ret->data_subframe_arg == -1) {
printf("%s:%d: subframe argument '%s' not found in event '%s'\n",
__FILE__, __LINE__, subframe_varname, event_name);
if (ret->data_tick_arg == -1) {
printf("%s:%d: tick argument '%s' not found in event '%s'\n",
__FILE__, __LINE__, tick_varname, event_name);
abort();
}
if (ret->data_arg == -1) {
@@ -170,9 +177,9 @@ logger *new_throughputlog(event_handler *h, void *database,
__FILE__, __LINE__, frame_varname);
abort();
}
if (strcmp(f.type[ret->data_subframe_arg], "int") != 0) {
if (strcmp(f.type[ret->data_tick_arg], "int") != 0) {
printf("%s:%d: argument '%s' has wrong type (should be 'int')\n",
__FILE__, __LINE__, subframe_varname);
__FILE__, __LINE__, tick_varname);
abort();
}
if (strcmp(f.type[ret->data_arg], "int") != 0 &&
@@ -183,6 +190,10 @@ logger *new_throughputlog(event_handler *h, void *database,
abort();
}
ret->ticks_per_frame = ticks_per_frame;
ret->bits = calloc(100 * ticks_per_frame, sizeof(unsigned long));
if (ret->bits == NULL) abort();
return ret;
}
+17 -17
View File
@@ -250,15 +250,15 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
widget_add_child(g, line, w, -1);
xy_plot_set_range(g, w, 0, 1024*10, -130, 35);
/*l = new_ticked_ttilog(h, database,"UE_PHY_DL_TICK", "frame", "subframe","UE_PHY_MEAS", "rssi", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#720c0c"));
v = new_view_tti(10, g, w, new_color(g, "#720c0c"), 10);
logger_add_view(l, v);
e->phy_meas_logger = l;*/
l = new_ticked_ttilog(h, database,"UE_PHY_DL_TICK", "frame", "subframe","UE_PHY_MEAS", "rsrp", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"));
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10);
logger_add_view(l, v);
e->phy_meas_logger = l;
l = new_ticked_ttilog(h, database,"UE_PHY_DL_TICK", "frame", "subframe","UE_PHY_MEAS", "snr", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c720c"));
v = new_view_tti(10, g, w, new_color(g, "#0c720c"), 10);
logger_add_view(l, v);
e->phy_meas_logger = l;
@@ -277,7 +277,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
widget_add_child(g, line, w, -1);
l = new_ticked_ttilog(h, database, "UE_PHY_DL_TICK", "frame", "subframe",
"UE_PHY_DLSCH_UE_DCI", "mcs", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"));
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10);
logger_add_view(l, v);
e->dl_mcs_logger = l;
@@ -288,7 +288,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
widget_add_child(g, line, w, -1);
l = new_ticked_ttilog(h, database, "UE_PHY_DL_TICK", "frame", "subframe",
"UE_PHY_ULSCH_UE_DCI", "mcs", 0, -1);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"));
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10);
logger_add_view(l, v);
e->ul_mcs_logger = l;
@@ -301,12 +301,12 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
xy_plot_set_range(g, w, 0, 1024*10, -30, 50);
l = new_ttilog(h, database,
"UE_PHY_PUSCH_TX_POWER", "frame", "subframe", "p0_pusch", 0);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"));
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10);
logger_add_view(l, v);
e->pusch_power_logger = l;
l = new_ttilog(h, database,
"UE_PHY_PUSCH_TX_POWER", "frame", "subframe", "ampl", 1);
v = new_view_tti(10, g, w, new_color(g, "#720c0c"));
v = new_view_tti(10, g, w, new_color(g, "#720c0c"), 10);
logger_add_view(l, v);
e->pusch_ampl_logger = l;
@@ -319,12 +319,12 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
xy_plot_set_range(g, w, 0, 1024*10, -30, 50);
l = new_ttilog(h, database,
"UE_PHY_PUCCH_TX_POWER", "frame", "subframe", "p0_pucch", 0);
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"));
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10);
logger_add_view(l, v);
e->pucch_power_logger = l;
l = new_ttilog(h, database,
"UE_PHY_PUCCH_TX_POWER", "frame", "subframe", "ampl", 1);
v = new_view_tti(10, g, w, new_color(g, "#720c0c"));
v = new_view_tti(10, g, w, new_color(g, "#720c0c"), 10);
logger_add_view(l, v);
e->pucch_ampl_logger = l;
@@ -335,22 +335,22 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
xy_plot_set_range(g, w, 0, 1024*10, -10, 80);
l = new_ttilog(h, database,
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level00", 1);
v = new_view_tti(10, g, w, new_color(g, "#ff0000"));
v = new_view_tti(10, g, w, new_color(g, "#ff0000"), 10);
logger_add_view(l, v);
e->pdsch_energy_logger = l;
l = new_ttilog(h, database,
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level01", 1);
v = new_view_tti(10, g, w, new_color(g, "#00ff00"));
v = new_view_tti(10, g, w, new_color(g, "#00ff00"), 10);
logger_add_view(l, v);
e->pdsch_energy_logger = l;
l = new_ttilog(h, database,
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level10", 1);
v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"));
v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"), 10);
logger_add_view(l, v);
e->pdsch_energy_logger = l;
l = new_ttilog(h, database,
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level11", 1);
v = new_view_tti(10, g, w, new_color(g, "#0000ff"));
v = new_view_tti(10, g, w, new_color(g, "#0000ff"), 10);
logger_add_view(l, v);
e->pdsch_energy_logger = l;
@@ -361,22 +361,22 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
xy_plot_set_range(g, w, 0, 1024*10, -10, 80);
l = new_ttilog(h, database,
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level00", 1);
v = new_view_tti(10, g, w, new_color(g, "#ff0000"));
v = new_view_tti(10, g, w, new_color(g, "#ff0000"), 10);
logger_add_view(l, v);
e->pdcch_energy_logger = l;
l = new_ttilog(h, database,
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level01", 1);
v = new_view_tti(10, g, w, new_color(g, "#00ff00"));
v = new_view_tti(10, g, w, new_color(g, "#00ff00"), 10);
logger_add_view(l, v);
e->pdcch_energy_logger = l;
l = new_ttilog(h, database,
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level10", 1);
v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"));
v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"), 10);
logger_add_view(l, v);
e->pdcch_energy_logger = l;
l = new_ttilog(h, database,
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level11", 1);
v = new_view_tti(10, g, w, new_color(g, "#0000ff"));
v = new_view_tti(10, g, w, new_color(g, "#0000ff"), 10);
logger_add_view(l, v);
e->pdcch_energy_logger = l;
+46 -15
View File
@@ -15,11 +15,14 @@ struct scrolltti {
int plot;
float refresh_rate;
pthread_mutex_t lock;
unsigned long data[1000];
unsigned long total; /* sum data[0..999] to have smoother value printed */
float xout[1000];
float yout[1000];
int ticks_per_frame;
unsigned long *data;
unsigned long total; /* sum data[0..n] to have smoother value printed */
float *xout;
float *yout;
int insert_point;
int next_tick_frame;
int next_tick_tick;
};
/* this array is used to get Y range 1000, 2000, 5000, 10000, ... */
@@ -38,21 +41,21 @@ static void *scrolltti_thread(void *_this)
/* TODO: optimize */
p = this->insert_point;
max = 0;
for (i = 0; i < 1000; i++) {
for (i = 0; i < this->ticks_per_frame * 100; i++) {
this->xout[i] = i;
this->yout[i] = this->data[p];
if (this->data[p] > max) max = this->data[p];
p = (p + 1) % 1000;
p = (p + 1) % (this->ticks_per_frame * 100);
}
bps(o, this->total/1000., "b/s");
bps(o, this->total/(this->ticks_per_frame * 100.), "b/s");
textarea_set_text(this->g, this->throughput_textarea, o);
/* for Y range we want 1000, 2000, 5000, 10000, 20000, 50000, etc. */
if (max < 1000) max = 1000;
mlog = pow(10, floor(log10(max)));
max = tolog[(int)ceil(max/mlog)] * mlog;
xy_plot_set_range(this->g, this->w, 0, 1000, 0, max);
xy_plot_set_range(this->g, this->w, 0, this->ticks_per_frame * 100, 0, max);
xy_plot_set_points(this->g, this->w, this->plot,
1000, this->xout, this->yout);
this->ticks_per_frame * 100, this->xout, this->yout);
if (pthread_mutex_unlock(&this->lock)) abort();
sleepms(1000/this->refresh_rate);
}
@@ -65,20 +68,40 @@ static void clear(view *this)
/* TODO */
}
static void append(view *_this, int frame, int subframe, double value)
static void insert(struct scrolltti *this, double value)
{
this->total -= this->data[this->insert_point];
this->data[this->insert_point] = value;
this->total += this->data[this->insert_point];
this->insert_point = (this->insert_point + 1) % (this->ticks_per_frame * 100);
}
static void next_tick(struct scrolltti *this)
{
this->next_tick_tick++;
if (this->next_tick_tick == this->ticks_per_frame) {
this->next_tick_tick = 0;
this->next_tick_frame++;
this->next_tick_frame %= 1024;
}
}
static void append(view *_this, int frame, int tick, double value)
{
struct scrolltti *this = (struct scrolltti *)_this;
if (pthread_mutex_lock(&this->lock)) abort();
this->total -= this->data[this->insert_point];
this->data[this->insert_point] = value;
this->total += this->data[this->insert_point];
this->insert_point = (this->insert_point + 1) % 1000;
while (this->next_tick_frame != frame || this->next_tick_tick != tick) {
insert(this, 0);
next_tick(this);
}
insert(this, value);
next_tick(this);
if (pthread_mutex_unlock(&this->lock)) abort();
}
view *new_view_scrolltti(float refresh_rate, gui *g, widget *w, int color,
widget *throughput_textarea)
widget *throughput_textarea, int ticks_per_frame)
{
struct scrolltti *ret = calloc(1, sizeof(struct scrolltti));
if (ret == NULL) abort();
@@ -92,6 +115,14 @@ view *new_view_scrolltti(float refresh_rate, gui *g, widget *w, int color,
ret->throughput_textarea = throughput_textarea;
ret->plot = xy_plot_new_plot(g, w, color);
ret->ticks_per_frame = ticks_per_frame;
ret->data = calloc(ticks_per_frame * 100, sizeof(unsigned long));
if (ret->data == NULL) abort();
ret->xout = calloc(ticks_per_frame * 100, sizeof(float));
if (ret->xout == NULL) abort();
ret->yout = calloc(ticks_per_frame * 100, sizeof(float));
if (ret->yout == NULL) abort();
if (pthread_mutex_init(&ret->lock, NULL)) abort();
new_thread(scrolltti_thread, ret);
+53 -14
View File
@@ -5,31 +5,36 @@
#include <pthread.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
struct tti {
view common;
gui *g;
widget *w;
int automax;
widget *w2;
int plot;
float refresh_rate;
pthread_mutex_t lock;
float data[1024*10];
int valid[1024*10];
float xout[1024*10];
float yout[1024*10];
float *data;
int *valid;
float *xout;
float *yout;
int last_insert_point;
int ticks_per_frame;
};
static int far_enough(int i, int last_insert, int plot_width)
static int far_enough(int i, int last_insert, int plot_width,
int ticks_per_frame)
{
int p1;
int p2;
int hole_size_px;
int hole_size_tti;
hole_size_px = 10;
hole_size_tti = 10240 * hole_size_px / plot_width;
hole_size_tti = 1024 * ticks_per_frame * hole_size_px / plot_width;
p1 = last_insert;
p2 = (last_insert + hole_size_tti) % (1024*10);
p2 = (last_insert + hole_size_tti) % (1024 * ticks_per_frame);
if (p1 < p2) {
return !(i > p1 && i < p2);
}
@@ -48,15 +53,31 @@ static void *tti_thread(void *_this)
if (pthread_mutex_lock(&this->lock)) abort();
xy_plot_get_dimensions(this->g, this->w, &plot_width, &plot_height);
length = 0;
double max = 0;
/* TODO: optimize */
for (i = 0; i < 1024*10; i++)
for (i = 0; i < 1024 * this->ticks_per_frame; i++)
/* do not take points too close after last insertion point */
if (this->valid[i] &&
far_enough(i, this->last_insert_point, plot_width)) {
far_enough(i, this->last_insert_point, plot_width,
this->ticks_per_frame)) {
this->xout[length] = i;
this->yout[length] = this->data[i];
if (this->data[i] > max) max = this->data[i];
length++;
}
if (this->automax) {
char o[128];
sprintf(o, "%d", (int)max);
textarea_set_text(this->g, this->w2, o);
/* for Y range we want 10, 20, 50, 100, 200, 500, etc. */
if (max < 10) max = 10;
double mlog = pow(10, floor(log10(max)));
static int tolog[11] = { -1, 1, 2, 5, 5, 5, 10, 10, 10, 10, 10 };
max = tolog[(int)ceil(max/mlog)] * mlog;
float xmin, xmax, ymin, ymax;
xy_plot_get_range(this->g, this->w, &xmin, &xmax, &ymin, &ymax);
xy_plot_set_range(this->g, this->w, xmin, xmax, 0, max);
}
xy_plot_set_points(this->g, this->w, this->plot,
length, this->xout, this->yout);
if (pthread_mutex_unlock(&this->lock)) abort();
@@ -71,11 +92,11 @@ static void clear(view *this)
/* TODO */
}
static void append(view *_this, int frame, int subframe, double value)
static void append(view *_this, int frame, int tick, double value)
{
struct tti *this = (struct tti *)_this;
int i;
int index = frame * 10 + subframe;
int index = frame * this->ticks_per_frame + tick;
if (pthread_mutex_lock(&this->lock)) abort();
@@ -84,10 +105,10 @@ static void append(view *_this, int frame, int subframe, double value)
* this may be wrong if delay between two append is
* greater than 1024 frames (something like that)
*/
i = (this->last_insert_point + 1) % (1024*10);
i = (this->last_insert_point + 1) % (1024 * this->ticks_per_frame);
while (i != index) {
this->valid[i] = 0;
i = (i + 1) % (1024*10);
i = (i + 1) % (1024 * this->ticks_per_frame);
}
this->data[index] = value;
@@ -98,7 +119,8 @@ static void append(view *_this, int frame, int subframe, double value)
if (pthread_mutex_unlock(&this->lock)) abort();
}
view *new_view_tti(float refresh_rate, gui *g, widget *w, int color)
view *new_view_tti(float refresh_rate, gui *g, widget *w, int color,
int ticks_per_frame)
{
struct tti *ret = calloc(1, sizeof(struct tti));
if (ret == NULL) abort();
@@ -115,7 +137,24 @@ view *new_view_tti(float refresh_rate, gui *g, widget *w, int color)
if (pthread_mutex_init(&ret->lock, NULL)) abort();
ret->ticks_per_frame = ticks_per_frame;
ret->data = calloc(ticks_per_frame * 1024, sizeof(float));
if (ret->data == NULL) abort();
ret->valid = calloc(ticks_per_frame * 1024, sizeof(int));
if (ret->valid == NULL) abort();
ret->xout = calloc(ticks_per_frame * 1024, sizeof(float));
if (ret->xout == NULL) abort();
ret->yout = calloc(ticks_per_frame * 1024, sizeof(float));
if (ret->yout == NULL) abort();
new_thread(tti_thread, ret);
return (view *)ret;
}
void view_tti_enable_automax(view *_tti, widget *w2)
{
struct tti *tti = (struct tti *)_tti;
tti->automax = 1;
tti->w2 = w2;
}
+4 -3
View File
@@ -17,15 +17,16 @@ view *new_view_stdout(void);
view *new_view_textlist(int maxsize, float refresh_rate, gui *g, widget *w);
view *new_view_xy(int length, float refresh_rate, gui *g, widget *w,
int color, enum xy_mode mode);
view *new_view_tti(float refresh_rate, gui *g, widget *w,
int color);
view *new_view_tti(float refresh_rate, gui *g, widget *w, int color,
int ticks_per_frame);
view *new_view_scrolltti(float refresh_rate, gui *g, widget *w,
int color, widget *throughput_label);
int color, widget *throughput_label, int ticks_per_frame);
view *new_view_time(int number_of_seconds, float refresh_rate,
gui *g, widget *w);
view *new_subview_time(view *time, int line, int color, int size);
view *new_view_ticktime(float refresh_rate, gui *g, widget *w);
view *new_subview_ticktime(view *ticktime, int line, int color, int size);
void ticktime_set_tick(view *ticktime, void *logger);
void view_tti_enable_automax(view *tti, widget *w2);
#endif /* _VIEW_H_ */