Commit 91329928 authored by Robert Schmidt's avatar Robert Schmidt

T: add tutorial for new trace

parent ad8612ab
......@@ -17,3 +17,4 @@ It is made of two main parts:
* [MAC PDUs and wireshark](./T/wireshark.md)
* [The *enb* tracer](./T/enb.md)
* [The *to_vcd* tracer](./T/to_vcd.md)
* [Tutorial: how to create a new trace](./T/howto_new_trace.md)
# T tracer - a simple tutorial
There is a diff file with all modifications:
[howto_new_trace.patch](./howto_new_trace.patch).
We use tag 2023.w28
To use the patch, clone the repository,
then in the top directory of openairinterface:
```
git checkout 2023.w28
patch -p1 < common/utils/T/DOC/T/howto_new_trace.patch
```
Then compile nr-softmodem as usual.
## 1 - create a new trace
As an example, let's add a new trace to dump LDPC decoding success.
In the file `common/utils/T/T_messages.txt`
we add those two lines:
```
ID = LDPC_OK
FORMAT = int,segment : int,nb_segments : int,offset : buffer,data
```
- You create an ID for the new trace.
- You give the format as a list of variables with there types.
Then, in the file `openair1/SCHED_NR/phy_procedures_nr_gNB.c`,
in function `nr_postDecode()`, we add, at the place where we want to trace:
```
T(T_LDPC_OK,
T_INT(rdata->segment_r),
T_INT(rdata->nbSegments),
T_INT(rdata->offset),
T_BUFFER(ulsch_harq->c[r], rdata->Kr_bytes - (ulsch_harq->F>>3) -((ulsch_harq->C>1)?3:0)));
```
And that's all, the code is instrumented, a trace is created,
we now need a tracer to process the trace.
## 2. create a tracer
See `trace_ldpc.c` in the attached diff. Read it, there is documentation.
To compile, just do `make trace_ldpc` in `common/utils/T/tracer`
To use: `cd common/utils/T/tracer; ./trace_ldpc -d ../T_messages.txt`
Your tracer can do whatever it wants with the data.
The Makefile has been modified to compile it. See the diff.
Use it as a basis for your own tracer.
You can also look at the other tracers, especially `textlog.c`
and `macpdu2wireshark.c` which are the most useful for me to
trace/debug the nr-softmodem.
## 3. available types in a trace
You trace the code with:
```
T(T_trace_name, T_xxx(variable1), T_xxx(variables2), ...);
```
`T_xxx` can be:
- `T_INT(variable)`
- `T_FLOAT(variable)` (not tested much, may fail)
- `T_BUFFER(variable, length)`
- `T_STRING(variable)`
- `T_PRINTF(format, arg1, ... argn)`
What is traced is obvious from the name. `T_INT` traces an int for example.
corresponding type to put in `T_messages.txt`
- `T_INT`: int
- `T_FLOAT`: float
- `T_BUFFER`: buffer
- `T_STRING`: string
- `T_PRINTF`: string
And that's all.
You can add as many traces as you want, just add them in `T_messages.txt`,
put the `T()` macro in the code where you want to trace, and modify your
tracer to deal with it.
An alternative to writing your own tracer could be to use `textlog`
with `-full` command line and process the text with some external
tools.
It is also possible to record the events in a file using the tracer
`record` and then use `replay` to process the recorded file later.
diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt
index c535f36f5e..1632131ceb 100644
--- a/common/utils/T/T_messages.txt
+++ b/common/utils/T/T_messages.txt
@@ -4,6 +4,9 @@ ID = ENB_MASTER_TICK
GROUP = ALL:GENERAL:ENB
FORMAT = int,eNB_ID : int,frame : int,subframe
+ID = LDPC_OK
+ FORMAT = int,segment : int,nb_segments : int,offset : buffer,data
+
#PHY logs
ID = ENB_PHY_UL_TICK
DESC = eNodeB uplink tick - one tick per ms at start of uplink processing
diff --git a/common/utils/T/tracer/CMakeLists.txt b/common/utils/T/tracer/CMakeLists.txt
index 02e0e2dc9b..db438c42d3 100644
--- a/common/utils/T/tracer/CMakeLists.txt
+++ b/common/utils/T/tracer/CMakeLists.txt
@@ -57,6 +57,10 @@ target_link_libraries(gnb PRIVATE tracer_utils tracer_filter tracer_gui
tracer_logger tracer_view tracer_events)
target_link_libraries(gnb PRIVATE png)
+add_executable(trace_ldpc trace_ldpc.c)
+target_link_libraries(trace_ldpc PRIVATE tracer_utils tracer_filter
+ tracer_logger tracer_view)
+
add_subdirectory(filter)
add_subdirectory(gui)
add_subdirectory(logger)
@@ -66,4 +70,4 @@ add_custom_target(T_tools)
add_dependencies(T_tools
record replay extract_config textlog enb ue vcd macpdu2wireshark
extract_input_subframe extract_output_subframe to_vcd extract multi
- gnb)
+ gnb trace_ldpc)
diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile
index d3c959a689..d13ff1e996 100644
--- a/common/utils/T/tracer/Makefile
+++ b/common/utils/T/tracer/Makefile
@@ -7,4 +7,4 @@ clean:
rm -rf tracer_build
rm record replay extract_config textlog enb ue vcd macpdu2wireshark \
extract_input_subframe extract_output_subframe to_vcd extract multi \
- gnb
+ gnb trace_ldpc
diff --git a/common/utils/T/tracer/trace_ldpc.c b/common/utils/T/tracer/trace_ldpc.c
new file mode 100644
index 0000000000..00baf34774
--- /dev/null
+++ b/common/utils/T/tracer/trace_ldpc.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+#include "database.h"
+#include "event.h"
+#include "handler.h"
+#include "logger/logger.h"
+#include "utils.h"
+#include "event_selector.h"
+#include "config.h"
+
+/* this function sends the activated traces to the nr-softmodem */
+void activate_traces(int socket, int number_of_events, int *is_on)
+{
+ char t = 1;
+ if (socket_send(socket, &t, 1) == -1 ||
+ socket_send(socket, &number_of_events, sizeof(int)) == -1 ||
+ socket_send(socket, is_on, number_of_events * sizeof(int)) == -1)
+ abort();
+}
+
+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);
+}
+
+int main(int n, char **v)
+{
+ char *database_filename = NULL;
+ void *database;
+ char *ip = DEFAULT_REMOTE_IP;
+ int port = DEFAULT_REMOTE_PORT;
+ int *is_on;
+ int number_of_events;
+ int i;
+ int socket;
+ int ldpc_ok_id;
+ database_event_format f;
+ int segment;
+ int nb_segments;
+ int offset;
+ int data;
+
+ /* write on a socket fails if the other end is closed and we get SIGPIPE */
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort();
+
+ /* parse command line options */
+ 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);
+ }
+
+ /* load the database T_messages.txt */
+ database = parse_database(database_filename);
+ load_config_file(database_filename);
+
+ /* an array of int for all the events defined in the database is needed */
+ number_of_events = number_of_ids(database);
+ is_on = calloc(number_of_events, sizeof(int));
+ if (is_on == NULL) abort();
+
+ /* activate the LDPC_OK trace in this array */
+ on_off(database, "LDPC_OK", is_on, 1);
+
+ /* connect to the nr-softmodem */
+ socket = connect_to(ip, port);
+
+ /* activate the trace LDPC_OK in the nr-softmodem */
+ activate_traces(socket, number_of_events, is_on);
+
+ free(is_on);
+
+ /* get the format of the LDPC_OK trace */
+ ldpc_ok_id = event_id_from_name(database, "LDPC_OK");
+ f = get_format(database, ldpc_ok_id);
+
+/* this macro looks for a particular element and checks its type */
+#define G(var_name, var_type, var) \
+ if (!strcmp(f.name[i], var_name)) { \
+ if (strcmp(f.type[i], var_type)) { printf("bad type for %s\n", var_name); exit(1); } \
+ var = i; \
+ continue; \
+ }
+
+ /* get the elements of the LDPC_OK trace
+ * the value is an index in the event, see below
+ */
+ for (i = 0; i < f.count; i++) {
+ G("segment", "int", segment);
+ G("nb_segments", "int", nb_segments);
+ G("offset", "int", offset);
+ G("data", "buffer", data);
+ }
+
+ /* a buffer needed to receive events from the nr-softmodem */
+ OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
+
+ /* read events */
+ while (1) {
+ event e;
+ e = get_event(socket, &ebuf, database);
+ if (e.type == -1) break;
+ if (e.type == ldpc_ok_id) {
+ /* this is how to access the elements of the LDPC_OK trace.
+ * we use e.e[<element>] and then the correct suffix, here
+ * it's .i for the integer and .b for the buffer and .bsize
+ * for the buffer size
+ * see in event.h the structure event_arg
+ */
+ unsigned char *buf = e.e[data].b;
+ printf("get LDPC_OK event segment %d nb_segments %d offset %d buffer length %d = [",
+ e.e[segment].i,
+ e.e[nb_segments].i,
+ e.e[offset].i,
+ e.e[data].bsize);
+ for (i = 0; i < e.e[data].bsize; i++)
+ printf(" %2.2x", buf[i]);
+ printf("]\n");
+ }
+ }
+
+ return 0;
+}
diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
index f33106ecaa..129b3606b6 100644
--- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c
+++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
@@ -255,6 +255,11 @@ static void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req)
ulsch_harq->processedSegments,
rdata->nbSegments);
if (decodeSuccess) {
+ T(T_LDPC_OK,
+ T_INT(rdata->segment_r),
+ T_INT(rdata->nbSegments),
+ T_INT(rdata->offset),
+ T_BUFFER(ulsch_harq->c[r], rdata->Kr_bytes - (ulsch_harq->F >> 3) - ((ulsch_harq->C > 1) ? 3 : 0)));
memcpy(ulsch_harq->b + rdata->offset, ulsch_harq->c[r], rdata->Kr_bytes - (ulsch_harq->F >> 3) - ((ulsch_harq->C > 1) ? 3 : 0));
} else {
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment