T: add a tracer 'gnb_mac'

To see MAC scheduling decisions. May be useful for debugging.
This commit is contained in:
Cedric Roux
2025-08-27 15:13:59 +02:00
committed by Robert Schmidt
parent c4562df2e7
commit fcd0013981
4 changed files with 349 additions and 7 deletions
+1
View File
@@ -3,6 +3,7 @@
genids
tracer/enb
tracer/gnb
tracer/gnb_mac
tracer/extract_config
tracer/record
tracer/replay
+5 -1
View File
@@ -62,6 +62,10 @@ if(T_TRACER_GUI)
tracer_logger tracer_view tracer_events)
target_link_libraries(gnb PRIVATE png)
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)
@@ -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
+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;
}