From d9235268b46e5c7ecedf783c2167b56669b404da Mon Sep 17 00:00:00 2001
From: Raymond Knopp <raymond.knopp@eurecom.fr>
Date: Wed, 29 Sep 2021 21:32:22 +0200
Subject: [PATCH] MAC statistics in separate thread

---
 openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 89 ++--------------------
 openair2/LAYER2/NR_MAC_gNB/mac_proto.h     |  1 +
 openair2/LAYER2/NR_MAC_gNB/main.c          | 81 ++++++++++++++++++++
 openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h    |  1 +
 4 files changed, 89 insertions(+), 83 deletions(-)

diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
index e3ee1d9888..f9f8524f7f 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
@@ -62,87 +62,6 @@ uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 };
 
 uint8_t vnf_first_sched_entry = 1;
 
-void clear_mac_stats(gNB_MAC_INST *gNB) {
-  memset((void*)gNB->UE_info.mac_stats,0,MAX_MOBILES_PER_GNB*sizeof(NR_mac_stats_t));
-}
-#define MACSTATSSTRLEN 16384
-void dump_mac_stats(gNB_MAC_INST *gNB)
-{
-  NR_UE_info_t *UE_info = &gNB->UE_info;
-  int num = 1;
-  FILE *fd=fopen("nrMAC_stats.log","w");
-  AssertFatal(fd!=NULL,"Cannot open nrMAC_stats.log, error %s\n",strerror(errno));
-  char output[MACSTATSSTRLEN];
-  memset(output,0,MACSTATSSTRLEN);
-  int stroff=0;
-  for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
-
-    stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n",
-      UE_id,
-      UE_info->rnti[UE_id],
-      num++,
-      UE_info->num_UEs,
-      UE_info->UE_sched_ctrl[UE_id].ph,
-      UE_info->UE_sched_ctrl[UE_id].pcmax);
-
-    LOG_I(NR_MAC, "UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n",
-          UE_id,
-          UE_info->rnti[UE_id],
-          num++,
-          UE_info->num_UEs,
-          UE_info->UE_sched_ctrl[UE_id].ph,
-          UE_info->UE_sched_ctrl[UE_id].pcmax);
-
-    NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id];
-    const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0;
-    stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, pucch0_DTX %d average RSRP %d (%d meas)\n",
-          UE_id,
-          stats->dlsch_rounds[0], stats->dlsch_rounds[1],
-          stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors,
-          stats->pucch0_DTX,
-          avg_rsrp, stats->num_rsrp_meas);
-    LOG_I(NR_MAC, "UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d\n",
-      UE_id,
-      stats->dlsch_rounds[0], stats->dlsch_rounds[1],
-      stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors);
-    stats->num_rsrp_meas = 0;
-    stats->cumul_rsrp = 0 ;
-    stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes);
-    stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_DTX %d, ulsch_errors %d\n",
-                    UE_id,
-                    stats->ulsch_rounds[0], stats->ulsch_rounds[1],
-                    stats->ulsch_rounds[2], stats->ulsch_rounds[3],
-                    stats->ulsch_DTX,
-                    stats->ulsch_errors);
-    stroff+=sprintf(output+stroff,
-                    "UE %d: ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n",
-                    UE_id,
-                    stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx);
-    LOG_I(NR_MAC, "UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes);
-    LOG_I(NR_MAC, "UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_errors %d\n",
-          UE_id,
-          stats->ulsch_rounds[0], stats->ulsch_rounds[1],
-          stats->ulsch_rounds[2], stats->ulsch_rounds[3],
-          stats->ulsch_errors);
-    LOG_I(NR_MAC,
-          "UE %d: ulsch_total_bytes (scheduled/received): %d / %d\n",
-          UE_id,
-          stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx);
-    for (int lc_id = 0; lc_id < 63; lc_id++) {
-      if (stats->lc_bytes_tx[lc_id] > 0) {
-        stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]);
-	LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]);
-      }
-      if (stats->lc_bytes_rx[lc_id] > 0) {
-        stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]);
-	LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]);
-      }
-    }
-  }
-  print_meas(&gNB->eNB_scheduler, "DL & UL scheduling timing stats", NULL, NULL);
-  if (stroff>0) fprintf(fd,"%s",output);
-  fclose(fd);
-}
 
 void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
                                 int CC_idP,
@@ -362,6 +281,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
   PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frame, slot,module_idP);
 
   const int bwp_id = 1;
+  char stats_output[16384];
 
   gNB_MAC_INST *gNB = RC.nrmac[module_idP];
   NR_COMMON_channels_t *cc = gNB->common_channels;
@@ -429,8 +349,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
   }
 
 
-  if ((slot == 0) && (frame & 127) == 0) dump_mac_stats(RC.nrmac[module_idP]);
-
+  if ((slot == 0) && (frame & 127) == 0) {
+     stats_output[0]='\0';
+     dump_mac_stats(RC.nrmac[module_idP],stats_output,16384);
+     LOG_I(NR_MAC,"Frame.Slot %d.%d\n%s\n",frame,slot,stats_output);
+  }
 
   // This schedules MIB
   schedule_nr_mib(module_idP, frame, slot);
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index 321476d513..51bbcf1c8a 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -442,4 +442,5 @@ bool nr_find_nb_rb(uint16_t Qm,
 
 void nr_sr_reporting(int Mod_idP, frame_t frameP, sub_frame_t slotP);
 
+void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen);
 #endif /*__LAYER2_NR_MAC_PROTO_H__*/
diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c
index 117c18ae8d..0497eea7e1 100644
--- a/openair2/LAYER2/NR_MAC_gNB/main.c
+++ b/openair2/LAYER2/NR_MAC_gNB/main.c
@@ -45,6 +45,85 @@
 extern RAN_CONTEXT_t RC;
 
 
+#define MACSTATSSTRLEN 16384
+
+void nrmac_stats_thread(void *arg) {
+
+  gNB_MAC_INST *gNB = (gNB_MAC_INST *)arg;
+
+  char output[MACSTATSSTRLEN];
+  memset(output,0,MACSTATSSTRLEN);
+  FILE *fd=fopen("nrMAC_stats.log","w");
+  AssertFatal(fd!=NULL,"Cannot open nrMAC_stats.log, error %s\n",strerror(errno));
+
+  while (oai_exit == 0) {
+     dump_mac_stats(gNB,output,MACSTATSSTRLEN);
+     fprintf(fd,"%s\n",output);
+     fflush(fd);
+     usleep(200000);
+     fseek(fd,0,SEEK_SET);
+  }
+  fclose(fd);
+}
+
+void clear_mac_stats(gNB_MAC_INST *gNB) {
+  memset((void*)gNB->UE_info.mac_stats,0,MAX_MOBILES_PER_GNB*sizeof(NR_mac_stats_t));
+}
+
+void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen)
+{
+  NR_UE_info_t *UE_info = &gNB->UE_info;
+  int num = 1;
+ 
+  int stroff=0;
+  if (UE_info->num_UEs == 0) return;
+
+  for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
+
+    stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n",
+      UE_id,
+      UE_info->rnti[UE_id],
+      num++,
+      UE_info->num_UEs,
+      UE_info->UE_sched_ctrl[UE_id].ph,
+      UE_info->UE_sched_ctrl[UE_id].pcmax);
+
+    NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id];
+    const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0;
+    stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, pucch0_DTX %d average RSRP %d (%d meas)\n",
+          UE_id,
+          stats->dlsch_rounds[0], stats->dlsch_rounds[1],
+          stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors,
+          stats->pucch0_DTX,
+          avg_rsrp, stats->num_rsrp_meas);
+    stats->num_rsrp_meas = 0;
+    stats->cumul_rsrp = 0 ;
+    stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes);
+    stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_DTX %d, ulsch_errors %d\n",
+                    UE_id,
+                    stats->ulsch_rounds[0], stats->ulsch_rounds[1],
+                    stats->ulsch_rounds[2], stats->ulsch_rounds[3],
+                    stats->ulsch_DTX,
+                    stats->ulsch_errors);
+    stroff+=sprintf(output+stroff,
+                    "UE %d: ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n",
+                    UE_id,
+                    stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx);
+    for (int lc_id = 0; lc_id < 63; lc_id++) {
+      if (stats->lc_bytes_tx[lc_id] > 0) {
+        stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]);
+	LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]);
+      }
+      if (stats->lc_bytes_rx[lc_id] > 0) {
+        stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]);
+	LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]);
+      }
+    }
+  }
+  print_meas(&gNB->eNB_scheduler, "DL & UL scheduling timing stats", NULL, NULL);
+}
+
+
 void mac_top_init_gNB(void)
 {
   module_id_t     i;
@@ -90,6 +169,7 @@ void mac_top_init_gNB(void)
         RC.nrmac[i]->pre_processor_dl = nr_init_fr1_dlsch_preprocessor(i, 0);
         RC.nrmac[i]->pre_processor_ul = nr_init_fr1_ulsch_preprocessor(i, 0);
       }
+      pthread_create(&RC.nrmac[i]->stats_thread,NULL,nrmac_stats_thread,(void*)RC.nrmac[i]);
 
     }//END for (i = 0; i < RC.nb_nr_macrlc_inst; i++)
 
@@ -103,6 +183,7 @@ void mac_top_init_gNB(void)
 
     rrc_init_nr_global_param();
 
+
   } else {
     RC.nrmac = NULL;
   }
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index c2e2b8d562..1a3b654727 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -665,6 +665,7 @@ typedef struct gNB_MAC_INST_s {
   NR_TAG_t                        *tag;
   /// Pointer to IF module instance for PHY
   NR_IF_Module_t                  *if_inst;
+  pthread_t                       stats_thread;
   /// Pusch target SNR
   int                             pusch_target_snrx10;
   /// Pucch target SNR
-- 
2.26.2