diff --git a/CMakeLists.txt b/CMakeLists.txt
index 94c49f89227f470ea9fc0da1c0cf0d8a85851537..b85faff90534d91711ee9e012d9829da608629cd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2124,7 +2124,7 @@ target_link_libraries(nr-uesoftmodem PRIVATE
   ITTI LIB_5GNAS_GNB LIB_NAS_SIMUE ${NAS_SIM_LIB} SIMU SIMU_ETH shlib_loader
   -Wl,--end-group z dl)
 
-target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt)
+target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_meas)
 target_link_libraries(nr-uesoftmodem PRIVATE ${T_LIB})
 target_link_libraries(nr-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
 
@@ -2256,7 +2256,7 @@ add_executable(nr_dlsim
   )
 target_link_libraries(nr_dlsim PRIVATE
   -Wl,--start-group UTIL SIMU SIMU_ETH PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR HASHTABLE x2ap SECURITY ngap -lz -Wl,--end-group
-  m pthread ${T_LIB} ITTI dl shlib_loader
+  m pthread ${T_LIB} ITTI dl shlib_loader nr_ue_phy_meas
   )
 target_link_libraries(nr_dlsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
 
@@ -2297,7 +2297,7 @@ endif()
 
 target_link_libraries(nr_ulsim PRIVATE
   -Wl,--start-group UTIL SIMU SIMU_ETH PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR HASHTABLE x2ap SECURITY ngap -lz -Wl,--end-group
-  m pthread ${T_LIB} ITTI dl shlib_loader
+  m pthread ${T_LIB} ITTI dl shlib_loader nr_ue_phy_meas
   )
 target_link_libraries(nr_ulsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
 
diff --git a/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c b/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c
index bdf508e6ef169d110f655381e2102d473bd19aaa..82f791cd2a1465bc7f2babce8e516977529638ca 100644
--- a/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c
+++ b/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c
@@ -86,7 +86,15 @@ int get_measurgroups(telnet_measurgroupdef_t **measurgroups) {
 
 void measurcmd_display_phycpu(telnet_printfunc_t prnt) {
   PHY_VARS_NR_UE *UE = PHY_vars_UE_g[0][0];
-  telnet_cpumeasurdef_t  cpumeasur[]=CPU_PHYNRUE_MEASURE;
+  telnet_cpumeasurdef_t cpumeasur[MAX_CPU_STAT_TYPE];
+  for (int i = 0; i < MAX_CPU_STAT_TYPE; i++) {
+    sprintf(cpumeasur[i].statname, "%s", UE->phy_cpu_stats.cpu_time_stats[i].meas_name);
+    cpumeasur[i].astatptr = &UE->phy_cpu_stats.cpu_time_stats[i];
+    cpumeasur[i].statemask = 0;
+    cpumeasur[i].num_occur1 = 1;
+    cpumeasur[i].num_occur2 = 0;
+    cpumeasur[i].num_occur3 = 0;
+  }
   prnt("%s cpu (%1.1g GHz) measurements: PHY (cpustats %s) %s\n",HDR,cpufreq,
        PRINT_CPUMEAS_STATE,HDR);
   measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t));
diff --git a/common/utils/telnetsrv/telnetsrv_cpumeasur_def.h b/common/utils/telnetsrv/telnetsrv_cpumeasur_def.h
index bbc9cb664d61781b323381c8f3cf78aa54b26c36..896c42d08a3c27351b7502550e5d1435e5845682 100644
--- a/common/utils/telnetsrv/telnetsrv_cpumeasur_def.h
+++ b/common/utils/telnetsrv/telnetsrv_cpumeasur_def.h
@@ -95,51 +95,4 @@
   {"ip_pdcp",                &(pdcpvars->ip_pdcp),0,1},\
 }
 
-/* from openair1/PHY/defs_nr_UE.h */
-#define CPU_PHYNRUE_MEASURE \
-{ \
-    {"phy_proc",          &(UE->phy_proc),0,1},\
-    {"phy_proc_rx",       &(UE-> phy_proc_rx),0,1},\
-    {"phy_proc_tx",       &(UE->phy_proc_tx),0,1},\
-    {"ue_ul_indication_stats",       &(UE->ue_ul_indication_stats),0,1},\
-    {"ofdm_mod_stats",       &(UE->ofdm_mod_stats),0,1},\
-    {"ulsch_encoding_stats",       &(UE->ulsch_encoding_stats),0,1},\
-    {"ulsch_modulation_stats",       &(UE->ulsch_modulation_stats),0,1},\
-    {"ulsch_segmentation_stats",       &(UE->ulsch_segmentation_stats),0,1},\
-    {"ulsch_rate_matching_stats",       &(UE->ulsch_rate_matching_stats),0,1},\
-    {"ulsch_ldpc_encoding_stats",       &(UE->ulsch_ldpc_encoding_stats),0,1},\
-    {"ulsch_interleaving_stats",       &(UE->ulsch_interleaving_stats),0,1},\
-    {"ulsch_multiplexing_stats",       &(UE->ulsch_multiplexing_stats),0,1},\
-    {"ofdm_demod_stats",       &(UE->ofdm_demod_stats),0,1},\
-    {"dlsch_rx_pdcch_stats",       &(UE->dlsch_rx_pdcch_stats),0,1},\
-    {"rx_dft_stats",       &(UE->rx_dft_stats),0,1},\
-    {"dlsch_c...timation_stats",       &(UE->dlsch_channel_estimation_stats),0,1},\
-    {"dlsch_f...timation_stats",       &(UE->dlsch_freq_offset_estimation_stats),0,1},\
-    {"dlsch_demodulation_stats",       &(UE->dlsch_demodulation_stats),0,1},\
-    {"dlsch_rate_unmatching_stats",       &(UE->dlsch_rate_unmatching_stats),0,1},\
-    {"dlsch_ldpc_decoding_stats",       &(UE->dlsch_ldpc_decoding_stats),0,1},\
-    {"dlsch_deinterleaving_stats",       &(UE->dlsch_deinterleaving_stats),0,1},\
-    {"dlsch_llr_stats",       &(UE->dlsch_llr_stats),0,1},\
-    {"dlsch_unscrambling_stats",       &(UE->dlsch_unscrambling_stats),0,1},\
-    {"dlsch_rate_matching_stats",       &(UE->dlsch_rate_matching_stats),0,1},\
-    {"dlsch_ldpc_encoding_stats",       &(UE->dlsch_ldpc_encoding_stats),0,1},\
-    {"dlsch_interleaving_stats",       &(UE->dlsch_interleaving_stats),0,1},\
-    {"dlsch_tc_init_stats",       &(UE->dlsch_tc_init_stats),0,1},\
-    {"dlsch_tc_alpha_stats",       &(UE->dlsch_tc_alpha_stats),0,1},\
-    {"dlsch_tc_beta_stats",       &(UE->dlsch_tc_beta_stats),0,1},\
-    {"dlsch_tc_gamma_stats",       &(UE->dlsch_tc_gamma_stats),0,1},\
-    {"dlsch_tc_ext_stats",       &(UE->dlsch_tc_ext_stats),0,1},\
-    {"dlsch_tc_intl1_stats",       &(UE->dlsch_tc_intl1_stats),0,1},\
-    {"dlsch_tc_intl2_stats",       &(UE->dlsch_tc_intl2_stats),0,1},\
-    {"tx_prach",       &(UE->tx_prach),0,1},\
-    {"ue_front_end_stat",       &(UE->ue_front_end_stat),0,1},\
-    {"ue_front_end_per_slot_stat",      &(UE->ue_front_end_per_slot_stat[0]),0,LTE_SLOTS_PER_SUBFRAME},\
-    {"pdcch_procedures_stat",       &(UE->pdcch_procedures_stat),0,1},\
-    {"rx_pdsch_stats",              &(UE->rx_pdsch_stats), 0, 1}, \
-    {"pdsch_procedures_stat",       &(UE->pdsch_procedures_stat),0,1},\
-    {"pdsch_procedures_per_slot_stat",  &(UE->pdsch_procedures_per_slot_stat[0]),0,LTE_SLOTS_PER_SUBFRAME},\
-    {"dlsch_procedures_stat",       &(UE->dlsch_procedures_stat),0,1},\
-    {"dlsch_decoding_stats",       &(UE->dlsch_decoding_stats),0,1},\
-    {"dlsch_llr_stats_para", &(UE->dlsch_llr_stats_parallelization[0]),0,LTE_SLOTS_PER_SUBFRAME},\
-}
 #endif
diff --git a/executables/nr-ue.c b/executables/nr-ue.c
index e3595f6cf8f70de27979ea31840770640d2dcfd7..d0f23437cc894775da5ddda4634534c5119f97f3 100644
--- a/executables/nr-ue.c
+++ b/executables/nr-ue.c
@@ -100,17 +100,14 @@ static size_t dump_L1_UE_meas_stats(PHY_VARS_NR_UE *ue, char *output, size_t max
 {
   const char *begin = output;
   const char *end = output + max_len;
-  output += print_meas_log(&ue->phy_proc_tx, "L1 TX processing", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->ulsch_encoding_stats, "ULSCH encoding", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->phy_proc_rx, "L1 RX processing", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->ue_ul_indication_stats, "UL Indication", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->rx_pdsch_stats, "PDSCH receiver", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->dlsch_decoding_stats, "PDSCH decoding", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->dlsch_deinterleaving_stats, " -> Deinterleive", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->dlsch_rate_unmatching_stats, " -> Rate Unmatch", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->dlsch_ldpc_decoding_stats, " ->  LDPC Decode", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->dlsch_unscrambling_stats, "PDSCH unscrambling", NULL, NULL, output, end - output);
-  output += print_meas_log(&ue->dlsch_rx_pdcch_stats, "PDCCH handling", NULL, NULL, output, end - output);
+  for (int i = 0; i < MAX_CPU_STAT_TYPE; i++) {
+    output += print_meas_log(&ue->phy_cpu_stats.cpu_time_stats[i],
+                             ue->phy_cpu_stats.cpu_time_stats[i].meas_name,
+                             NULL,
+                             NULL,
+                             output,
+                             end - output);
+  }
   return output - begin;
 }
 
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
index 105ffdbbaa45a385f950bf50b26714e3d5820996..20fc4248bdbf0aac0dbf7f4f281ab23ea9b9f881 100644
--- a/executables/nr-uesoftmodem.c
+++ b/executables/nr-uesoftmodem.c
@@ -503,6 +503,7 @@ int main(int argc, char **argv)
 
         set_options(CC_id, UE[CC_id]);
         NR_UE_MAC_INST_t *mac = get_mac_inst(inst);
+        init_nr_ue_phy_cpu_stats(&UE[CC_id]->phy_cpu_stats);
 
         if (get_softmodem_params()->sa || get_softmodem_params()->sl_mode) { // set frame config to initial values from command line
                                                                             // and assume that the SSB is centered on the grid
diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c
index ffcd0b13ad98adfbe673a335811ef135c0a3975a..faee44cc9e3bf9fef6d9d2d9f088f98d7c1d0f3a 100644
--- a/openair1/PHY/MODULATION/slot_fep_nr.c
+++ b/openair1/PHY/MODULATION/slot_fep_nr.c
@@ -184,14 +184,12 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
       rxdata_ptr = (int16_t *)tmp_dft_in;
     }
 
-    start_meas(&ue->rx_dft_stats);
-
+    start_meas_nr_ue_phy(ue, RX_DFT_STATS);
     dft(dftsize,
         rxdata_ptr,
         (int16_t *)&rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
         1);
-
-    stop_meas(&ue->rx_dft_stats);
+    stop_meas_nr_ue_phy(ue, RX_DFT_STATS);
 
     apply_nr_rotation_RX(frame_parms, rxdataF[aa], frame_parms->symbol_rotation[linktype], Ns, frame_parms->N_RB_DL, 0, symbol, 1);
   }
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
index 6c57130b3da45b25b4a4e563549a9b396c7492e2..e295681ae087cc9ee22668e4c7966ba0a7a31314 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
@@ -83,9 +83,9 @@ static bool nr_ue_postDecode(PHY_VARS_NR_UE *phy_vars_ue,
   NR_UE_DLSCH_t *dlsch = (NR_UE_DLSCH_t *) rdata->dlsch;
   int r = rdata->segment_r;
 
-  merge_meas(&phy_vars_ue->dlsch_deinterleaving_stats, &rdata->ts_deinterleave);
-  merge_meas(&phy_vars_ue->dlsch_rate_unmatching_stats, &rdata->ts_rate_unmatch);
-  merge_meas(&phy_vars_ue->dlsch_ldpc_decoding_stats, &rdata->ts_ldpc_decode);
+  merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_DEINTERLEAVING_STATS], &rdata->ts_deinterleave);
+  merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_RATE_UNMATCHING_STATS], &rdata->ts_rate_unmatch);
+  merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_LDPC_DECODING_STATS], &rdata->ts_ldpc_decode);
 
   bool decodeSuccess = (rdata->decodeIterations < (1+dlsch->max_ldpc_iterations));
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
index 7476309ad8922702e81bfb4a452d18029e3d8d29..6537e4b8401b7695bf955ef3c49704b7472bdcfe 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
@@ -438,12 +438,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
   //--------------------- RBs extraction ---------------------
   //----------------------------------------------------------
   const int n_rx = frame_parms->nb_antennas_rx;
-  time_stats_t meas = {0};
   const bool meas_enabled = cpumeas(CPUMEAS_GETSTATE);
 
-  if (meas_enabled)
-    start_meas(&meas);
   {
+    start_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
     __attribute__((aligned(32))) c16_t rxdataF_ext[nbRx][rx_size_symbol];
     memset(rxdataF_ext, 0, sizeof(rxdataF_ext));
 
@@ -469,15 +467,15 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                          dlsch_config->dlDmrsSymbPos,
                          csi_res_bitmap,
                          ue->chest_time);
+    stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
     if (meas_enabled) {
-      stop_meas(&meas);
       LOG_D(PHY,
             "[AbsSFN %u.%d] Slot%d Symbol %d: Pilot/Data extraction %5.2f \n",
             frame,
             nr_slot_rx,
             slot,
             symbol,
-            meas.p_time / (cpuf * 1000.0));
+            ue->phy_cpu_stats.cpu_time_stats[DLSCH_EXTRACT_RBS_STATS].p_time / (cpuf * 1000.0));
     }
     if (ue->phy_sim_pdsch_rxdataF_ext)
       for (unsigned char aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
@@ -491,25 +489,23 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
     //----------------------------------------------------------
     //--------------------- Channel Scaling --------------------
     //----------------------------------------------------------
-    if (meas_enabled)
-      start_meas(&meas);
+    start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS);
     nr_dlsch_scale_channel(rx_size_symbol, dl_ch_estimates_ext, frame_parms, nl, n_rx, symbol, pilots, nb_re_pdsch, nb_rb_pdsch);
+    stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS);
     if (meas_enabled) {
-      stop_meas(&meas);
       LOG_D(PHY,
             "[AbsSFN %u.%d] Slot%d Symbol %d: Channel Scale  %5.2f \n",
             frame,
             nr_slot_rx,
             slot,
             symbol,
-            meas.p_time / (cpuf * 1000.0));
+            ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_SCALE_STATS].p_time / (cpuf * 1000.0));
     }
 
     //----------------------------------------------------------
     //--------------------- Channel Level Calc. ----------------
     //----------------------------------------------------------
-    if (meas_enabled)
-      start_meas(&meas);
+    start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
     if (first_symbol_flag) {
       int32_t avg[MAX_ANT][MAX_ANT] = {};
       if (nb_re_pdsch)
@@ -537,8 +533,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
       // LOG_I(PHY, "avgs Power per SC is %d lg2_maxh %d\n", avgs,  log2_maxh);
       LOG_D(PHY, "[DLSCH] AbsSubframe %d.%d log2_maxh = %d (%d)\n", frame % 1024, nr_slot_rx, *log2_maxh, avgs);
     }
+    stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
     if (meas_enabled) {
-      stop_meas(&meas);
       LOG_D(PHY,
             "[AbsSFN %u.%d] Slot%d Symbol %d first_symbol_flag %d: Channel Level  %5.2f \n",
             frame,
@@ -546,7 +542,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
             slot,
             symbol,
             first_symbol_flag,
-            meas.p_time / (cpuf * 1000.0));
+            ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_LEVEL_STATS].p_time / (cpuf * 1000.0));
     }
 #if T_TRACER
     T(T_UE_PHY_PDSCH_ENERGY, T_INT(gNB_id), T_INT(0), T_INT(frame % 1024), T_INT(nr_slot_rx));
@@ -556,8 +552,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
     //--------------------- channel compensation ---------------
     //----------------------------------------------------------
     // Disable correlation measurement for optimizing UE
-    if (meas_enabled)
-      start_meas(&meas);
+    start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
     nr_dlsch_channel_compensation(rx_size_symbol,
                                   nbRx,
                                   rxdataF_ext,
@@ -576,8 +571,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                                   nb_rb_pdsch,
                                   *log2_maxh,
                                   measurements); // log2_maxh+I0_shift
+    stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
     if (meas_enabled) {
-      stop_meas(&meas);
       LOG_D(PHY,
             "[AbsSFN %u.%d] Slot%d Symbol %d log2_maxh %d Channel Comp  %5.2f \n",
             frame,
@@ -585,13 +580,11 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
             slot,
             symbol,
             *log2_maxh,
-            meas.p_time / (cpuf * 1000.0));
+            ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_COMPENSATION_STATS].p_time / (cpuf * 1000.0));
     }
   }
 
-  if (meas_enabled)
-    start_meas(&meas);
-
+  start_meas_nr_ue_phy(ue, DLSCH_MRC_MMSE_STATS);
   if (n_rx > 1) {
     nr_dlsch_detection_mrc(rx_size_symbol,
                            nl,
@@ -620,20 +613,20 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                     nb_re_pdsch,
                     nvar);
   }
+  stop_meas_nr_ue_phy(ue, DLSCH_MRC_MMSE_STATS);
 
   if (meas_enabled) {
-    stop_meas(&meas);
     LOG_D(PHY,
           "[AbsSFN %u.%d] Slot%d Symbol %d: Channel Combine and MMSE %5.2f \n",
           frame,
           nr_slot_rx,
           slot,
           symbol,
-          meas.p_time / (cpuf * 1000.0));
+          ue->phy_cpu_stats.cpu_time_stats[DLSCH_MRC_MMSE_STATS].p_time / (cpuf * 1000.0));
   }
 
-  if (meas_enabled)
-    start_meas(&meas);
+
+
   /* Store the valid DL RE's */
   dl_valid_re[symbol-1] = nb_re_pdsch;
   int startSymbIdx = 0;
@@ -682,6 +675,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
       else
         first_symbol_flag = 0;
       /* Calculate LLR's for each symbol */
+      start_meas_nr_ue_phy(ue, DLSCH_LLR_STATS);
       nr_dlsch_llr(rx_size_symbol,
                    nbRx,
                    rx_llr_layer_size,
@@ -703,8 +697,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                    nr_slot_rx,
                    dlsch,
                    llr_offset);
+      stop_meas_nr_ue_phy(ue, DLSCH_LLR_STATS);
     }
 
+    start_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING);
     nr_dlsch_layer_demapping(llr,
                              dlsch[0].Nl,
                              dlsch[0].dlsch_config.qamModOrder,
@@ -713,6 +709,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                              codeword_TB1,
                              rx_llr_layer_size,
                              layer_llr);
+    stop_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING);
     // Please keep it: useful for debugging
 #ifdef DEBUG_PDSCH_RX
     char filename[50];
@@ -742,14 +739,13 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
   }
 
   if (meas_enabled) {
-    stop_meas(&meas);
     LOG_D(PHY,
           "[AbsSFN %u.%d] Slot%d Symbol %d: LLR Computation  %5.2f \n",
           frame,
           nr_slot_rx,
           slot,
           symbol,
-          meas.p_time / (cpuf * 1000.0));
+          ue->phy_cpu_stats.cpu_time_stats[DLSCH_LLR_STATS].p_time / (cpuf * 1000.0));
   }
 
 #if T_TRACER
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
index 1d7a8fd6d83ba407b8d237e27893f6de41fa8af2..98c6dc3dfbead18a9b63a07cbede6ec443826ef2 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
@@ -48,7 +48,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
                       uint32_t tb_size,
                       unsigned int G)
 {
-  start_meas(&ue->ulsch_encoding_stats);
+  start_meas_nr_ue_phy(ue, ULSCH_ENCODING_STATS);
 
   /////////////////////////parameters and variables initialization/////////////////////////
 
@@ -107,7 +107,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
     harq_process->BG = ulsch->pusch_pdu.ldpcBaseGraph;
 
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_IN);
-    start_meas(&ue->ulsch_segmentation_stats);
+    start_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS);
     impp.Kb = nr_segmentation(harq_process->payload_AB,
                               harq_process->c,
                               B,
@@ -126,7 +126,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
       LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", impp.n_segments, B);
       return(-1);
     }
-    stop_meas(&ue->ulsch_segmentation_stats);
+    stop_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS);
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_OUT);
 
 #ifdef DEBUG_ULSCH_CODING
@@ -148,7 +148,8 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
     }
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN);
   }
-  start_meas(&ue->ulsch_ldpc_encoding_stats);
+
+  start_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS);
   if (ldpc_interface_offload.LDPCencoder) {
     for (int j = 0; j < impp.n_segments; j++) {
       impp.perCB[j].E_cb = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, j);
@@ -168,6 +169,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
       write_output("ulsch_enc_output0.m", "enc0", &harq_process->d[0][0], (3 * 8 * Kr_bytes) + 12, 1, 4);
 #endif
     }
+    stop_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS);
 ///////////////////////////////////////////////////////////////////////////////
     for (int r = 0; r < impp.n_segments; r++) { // looping over C segments
       if (impp.F > 0) {
@@ -191,7 +193,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
       impp.perCB[r].E_cb = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, r);
 
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_IN);
-      start_meas(&ue->ulsch_rate_matching_stats);
+      start_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_RATE_MATCHING_STATS]);
       if (nr_rate_matching_ldpc(ulsch->pusch_pdu.tbslbrm,
                                 impp.BG,
                                 impp.Zc,
@@ -205,7 +207,7 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
           == -1)
         return -1;
 
-      stop_meas(&ue->ulsch_rate_matching_stats);
+      stop_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_RATE_MATCHING_STATS]);
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_OUT);
 
 #ifdef DEBUG_ULSCH_CODING
@@ -215,9 +217,9 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
 
 ///////////////////////// e---->| Rate matching bit interleaving |---->f /////////////////////////
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_IN);
-      start_meas(&ue->ulsch_interleaving_stats);
+      start_meas_nr_ue_phy(ue, ULSCH_INTERLEAVING_STATS);
       nr_interleaving_ldpc(impp.perCB[r].E_cb, impp.Qm, harq_process->e + r_offset, harq_process->f + r_offset);
-      stop_meas(&ue->ulsch_interleaving_stats);
+      stop_meas_nr_ue_phy(ue, ULSCH_INTERLEAVING_STATS);
     
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_OUT);
 #ifdef DEBUG_ULSCH_CODING
@@ -231,6 +233,6 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
   }
   ///////////////////////////////////////////////////////////////////////////////////////////////
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT);
-  stop_meas(&ue->ulsch_encoding_stats);
+  stop_meas_nr_ue_phy(ue, ULSCH_ENCODING_STATS);
   return(0);
 }
diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h
index 70b0dc041f1d76be39c43e5125a09ebd38616b96..4fc26193cfcedd850a5d008ad733b5a595476195 100644
--- a/openair1/PHY/defs_nr_UE.h
+++ b/openair1/PHY/defs_nr_UE.h
@@ -40,6 +40,7 @@
 #include "defs_nr_common.h"
 #include "CODING/nrPolar_tools/nr_polar_pbch_defs.h"
 #include "PHY/defs_nr_sl_UE.h"
+#include "openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -527,56 +528,10 @@ typedef struct PHY_VARS_NR_UE_s {
   scheduling_request_config_t scheduling_request_config_nr[NUMBER_OF_CONNECTED_gNB_MAX];
 
 #endif
-
-  time_stats_t phy_proc;
-  time_stats_t phy_proc_tx;
-  time_stats_t phy_proc_rx;
-
-  time_stats_t ue_ul_indication_stats;
-
   uint32_t use_ia_receiver;
-
-  time_stats_t ofdm_mod_stats;
-  time_stats_t ulsch_encoding_stats;
-  time_stats_t ulsch_ldpc_encoding_stats;
-  time_stats_t ulsch_modulation_stats;
-  time_stats_t ulsch_segmentation_stats;
-  time_stats_t ulsch_rate_matching_stats;
-  time_stats_t ulsch_interleaving_stats;
-  time_stats_t ulsch_multiplexing_stats;
-
-  time_stats_t ue_front_end_stat;
-  time_stats_t ue_front_end_per_slot_stat[LTE_SLOTS_PER_SUBFRAME];
-  time_stats_t pdcch_procedures_stat;
-  time_stats_t pdsch_procedures_stat;
-  time_stats_t pdsch_procedures_per_slot_stat[LTE_SLOTS_PER_SUBFRAME];
-  time_stats_t dlsch_procedures_stat;
-
-  time_stats_t rx_pdsch_stats;
-  time_stats_t ofdm_demod_stats;
-  time_stats_t dlsch_rx_pdcch_stats;
-  time_stats_t rx_dft_stats;
-  time_stats_t dlsch_channel_estimation_stats;
-  time_stats_t dlsch_freq_offset_estimation_stats;
-  time_stats_t dlsch_decoding_stats;
-  time_stats_t dlsch_demodulation_stats;
-  time_stats_t dlsch_rate_unmatching_stats;
-  time_stats_t dlsch_ldpc_decoding_stats;
-  time_stats_t dlsch_deinterleaving_stats;
-  time_stats_t dlsch_llr_stats;
-  time_stats_t dlsch_llr_stats_parallelization[LTE_SLOTS_PER_SUBFRAME];
-  time_stats_t dlsch_unscrambling_stats;
-  time_stats_t dlsch_rate_matching_stats;
-  time_stats_t dlsch_ldpc_encoding_stats;
-  time_stats_t dlsch_interleaving_stats;
-  time_stats_t dlsch_tc_init_stats;
-  time_stats_t dlsch_tc_alpha_stats;
-  time_stats_t dlsch_tc_beta_stats;
-  time_stats_t dlsch_tc_gamma_stats;
-  time_stats_t dlsch_tc_ext_stats;
-  time_stats_t dlsch_tc_intl1_stats;
-  time_stats_t dlsch_tc_intl2_stats;
-  time_stats_t tx_prach;
+  // TODO: move this out of phy
+  time_stats_t ue_ul_indication_stats;
+  nr_ue_phy_cpu_stat_t phy_cpu_stats;
 
   /// RF and Interface devices per CC
   openair0_device rfdevice;
@@ -706,5 +661,13 @@ typedef struct LDPCDecode_ue_s {
   UE_nr_rxtx_proc_t proc;
 } ldpcDecode_ue_t;
 
+static inline void start_meas_nr_ue_phy(PHY_VARS_NR_UE *ue, int meas_index) {
+  start_meas(&ue->phy_cpu_stats.cpu_time_stats[meas_index]);
+}
+
+static inline void stop_meas_nr_ue_phy(PHY_VARS_NR_UE *ue, int meas_index) {
+  stop_meas(&ue->phy_cpu_stats.cpu_time_stats[meas_index]);
+}
+
 #include "SIMULATION/ETH_TRANSPORT/defs.h"
 #endif
diff --git a/openair1/PHY/nr_phy_common/CMakeLists.txt b/openair1/PHY/nr_phy_common/CMakeLists.txt
index 3ba2666b0829892358dcf75cc98f00cc2123d680..ebbc3fcbc709e27e00b3f19237431bed85145d4c 100644
--- a/openair1/PHY/nr_phy_common/CMakeLists.txt
+++ b/openair1/PHY/nr_phy_common/CMakeLists.txt
@@ -1,3 +1,7 @@
 add_library(nr_phy_common src/nr_phy_common.c)
 target_link_libraries(nr_phy_common PRIVATE UTIL)
 target_include_directories(nr_phy_common PUBLIC inc/)
+
+add_library(nr_ue_phy_meas src/nr_ue_phy_meas.c)
+target_include_directories(nr_ue_phy_meas PUBLIC inc/)
+target_link_libraries(nr_ue_phy_meas PUBLIC utils)
diff --git a/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h b/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c667e3c1dedc6a1ed7755146738b8a99b038f50
--- /dev/null
+++ b/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#ifndef __NR_UE_PHY_MEAS__H__
+#define __NR_UE_PHY_MEAS__H__
+#include "time_meas.h"
+#include "utils.h"
+
+#define NOOP(a) a
+#define FOREACH_NR_PHY_CPU_MEAS(FN) \
+  FN(RX_PDSCH_STATS),\
+  FN(DLSCH_RX_PDCCH_STATS),\
+  FN(RX_DFT_STATS),\
+  FN(DLSCH_CHANNEL_ESTIMATION_STATS),\
+  FN(DLSCH_DECODING_STATS),\
+  FN(DLSCH_RATE_UNMATCHING_STATS),\
+  FN(DLSCH_LDPC_DECODING_STATS),\
+  FN(DLSCH_DEINTERLEAVING_STATS),\
+  FN(DLSCH_EXTRACT_RBS_STATS),\
+  FN(DLSCH_CHANNEL_SCALE_STATS),\
+  FN(DLSCH_CHANNEL_LEVEL_STATS),\
+  FN(DLSCH_MRC_MMSE_STATS),\
+  FN(DLSCH_UNSCRAMBLING_STATS),\
+  FN(DLSCH_CHANNEL_COMPENSATION_STATS),\
+  FN(DLSCH_LLR_STATS),\
+  FN(DLSCH_LAYER_DEMAPPING),\
+  FN(PHY_RX_PDCCH_STATS),\
+  FN(DLSCH_PROCEDURES_STATS),\
+  FN(PHY_PROC_TX),\
+  FN(ULSCH_SEGMENTATION_STATS),\
+  FN(ULSCH_LDPC_ENCODING_STATS),\
+  FN(ULSCH_RATE_MATCHING_STATS),\
+  FN(ULSCH_INTERLEAVING_STATS),\
+  FN(ULSCH_ENCODING_STATS)
+
+typedef enum {
+  FOREACH_NR_PHY_CPU_MEAS(NOOP),
+  MAX_CPU_STAT_TYPE
+} nr_ue_phy_cpu_stat_type_t;
+
+typedef struct nr_ue_phy_cpu_stat_t {
+  time_stats_t cpu_time_stats[MAX_CPU_STAT_TYPE];
+} nr_ue_phy_cpu_stat_t;
+
+void init_nr_ue_phy_cpu_stats(nr_ue_phy_cpu_stat_t *ue_phy_cpu_stats);
+void reset_nr_ue_phy_cpu_stats(nr_ue_phy_cpu_stat_t *ue_phy_cpu_stats);
+
+#endif
diff --git a/openair1/PHY/nr_phy_common/src/nr_ue_phy_meas.c b/openair1/PHY/nr_phy_common/src/nr_ue_phy_meas.c
new file mode 100644
index 0000000000000000000000000000000000000000..75ad7a5b7297abeb9cf2e8fb58b515995dec20af
--- /dev/null
+++ b/openair1/PHY/nr_phy_common/src/nr_ue_phy_meas.c
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#include <string.h>
+#include "nr_ue_phy_meas.h"
+#include <stdbool.h>
+
+void init_nr_ue_phy_cpu_stats(nr_ue_phy_cpu_stat_t *ue_phy_cpu_stats) {
+  reset_nr_ue_phy_cpu_stats(ue_phy_cpu_stats);
+  const char* cpu_stats_enum_to_string_table[] = {
+    FOREACH_NR_PHY_CPU_MEAS(TO_STRING)
+  };
+  for (int i = 0; i < MAX_CPU_STAT_TYPE; i++) {
+    ue_phy_cpu_stats->cpu_time_stats[i].meas_name = strdup(cpu_stats_enum_to_string_table[i]);
+  }
+}
+
+void reset_nr_ue_phy_cpu_stats(nr_ue_phy_cpu_stat_t *ue_phy_cpu_stats) {
+  for (int i = 0; i < MAX_CPU_STAT_TYPE; i++) {
+    reset_meas(&ue_phy_cpu_stats->cpu_time_stats[i]);
+  }
+}
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index cfb52f3266a95b61453440d22b68d76772c9efee..123423283f6901710db465b0528523a7dfc4d301 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -275,8 +275,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
 
   LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
 
-  start_meas(&ue->phy_proc_tx);
-
+  start_meas_nr_ue_phy(ue, PHY_PROC_TX);
   for (uint8_t harq_pid = 0; harq_pid < NR_MAX_ULSCH_HARQ_PROCESSES; harq_pid++) {
     if (ue->ul_harq_processes[harq_pid].ULstatus == ACTIVE) {
       nr_ue_ulsch_procedures(ue, harq_pid, frame_tx, slot_tx, gNB_id, phy_data, (c16_t **)&txdataF);
@@ -300,7 +299,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
   LOG_D(PHY, "****** end TX-Chain for AbsSubframe %d.%d ******\n", proc->frame_tx, proc->nr_slot_tx);
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_FUNCTION_OUT);
-  stop_meas(&ue->phy_proc_tx);
+  stop_meas_nr_ue_phy(ue, PHY_PROC_TX);
 }
 
 void nr_ue_measurement_procedures(uint16_t l,
@@ -426,7 +425,7 @@ int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue,
 
   fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15 = &phy_pdcch_config->pdcch_config[n_ss];
 
-  start_meas(&ue->dlsch_rx_pdcch_stats);
+  start_meas_nr_ue_phy(ue, DLSCH_RX_PDCCH_STATS);
 
   /// PDCCH/DCI e-sequence (input to rate matching).
   int32_t pdcch_e_rx_size = NR_MAX_PDCCH_SIZE;
@@ -454,9 +453,7 @@ int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue,
   nr_fill_dl_indication(&dl_indication, &dci_ind, NULL, proc, ue, phy_data);
   //  send to mac
   ue->if_inst->dl_indication(&dl_indication);
-
-  stop_meas(&ue->dlsch_rx_pdcch_stats);
-
+  stop_meas_nr_ue_phy(ue, DLSCH_RX_PDCCH_STATS);
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PDCCH_PROCEDURES, VCD_FUNCTION_OUT);
   return (dci_ind.number_of_dcis);
 }
@@ -468,7 +465,6 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
                                   c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
                                   int G)
 {
-  int frame_rx = proc->frame_rx;
   int nr_slot_rx = proc->nr_slot_rx;
 
   // We handle only one CW now
@@ -510,6 +506,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
 
     uint32_t nvar = 0;
 
+    start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_ESTIMATION_STATS);
     for (int m = dlschCfg->start_symbol; m < (dlschCfg->start_symbol + dlschCfg->number_symbols); m++) {
       if (dlschCfg->dlDmrsSymbPos & (1 << m)) {
         for (int nl = 0; nl < dlsch0->Nl; nl++) { //for MIMO Config: it shall loop over no_layers
@@ -546,6 +543,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
         }
       }
     }
+    stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_ESTIMATION_STATS);
 
     nvar /= (dlschCfg->number_symbols * dlsch0->Nl * ue->frame_parms.nb_antennas_rx);
 
@@ -576,16 +574,12 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
     uint32_t llr_offset[NR_SYMBOLS_PER_SLOT] = {0};
 
     int32_t log2_maxh = 0;
-    start_meas(&ue->rx_pdsch_stats);
+    start_meas_nr_ue_phy(ue, RX_PDSCH_STATS);
     for (int m = dlschCfg->start_symbol; m < (dlschCfg->number_symbols + dlschCfg->start_symbol); m++) {
       bool first_symbol_flag = false;
       if (m == first_symbol_with_data)
         first_symbol_flag = true;
 
-      uint8_t slot = 0;
-      if(m >= ue->frame_parms.symbols_per_slot>>1)
-        slot = 1;
-      start_meas(&ue->dlsch_llr_stats_parallelization[slot]);
       // process DLSCH received symbols in the slot
       // symbol by symbol processing (if data/DMRS are multiplexed is checked inside the function)
       if (nr_rx_pdsch(ue,
@@ -610,17 +604,8 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
                       nvar)
           < 0)
         return -1;
-
-      stop_meas(&ue->dlsch_llr_stats_parallelization[slot]);
-      if (cpumeas(CPUMEAS_GETSTATE))
-        LOG_D(PHY,
-              "[AbsSFN %d.%d] LLR Computation Symbol %d %5.2f \n",
-              frame_rx,
-              nr_slot_rx,
-              m,
-              ue->dlsch_llr_stats_parallelization[slot].p_time / (cpuf * 1000.0));
     } // CRNTI active
-    stop_meas(&ue->rx_pdsch_stats);
+    stop_meas_nr_ue_phy(ue, RX_PDSCH_STATS);
   }
   return 0;
 }
@@ -734,13 +719,11 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
     return false;
   }
 
-  start_meas(&ue->dlsch_unscrambling_stats);
+  start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
   nr_dlsch_unscrambling(llr[0], G, 0, dlsch[0].dlsch_config.dlDataScramblingId, dlsch[0].rnti);
+  stop_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
 
-  stop_meas(&ue->dlsch_unscrambling_stats);
-
-  start_meas(&ue->dlsch_decoding_stats);
-
+  start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
   // create memory to store decoder output
   int a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*NR_MAX_NB_LAYERS;  //number of segments to be allocated
   int num_rb = dlsch[0].dlsch_config.number_rbs;
@@ -796,12 +779,16 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
 
   LOG_D(PHY, "DL PDU length in bits: %d, in bytes: %d \n", dlsch[0].dlsch_config.TBS, dlsch[0].dlsch_config.TBS / 8);
 
-  stop_meas(&ue->dlsch_decoding_stats);
-  if (cpumeas(CPUMEAS_GETSTATE))  {
-    LOG_D(PHY, " --> Unscrambling for CW0 %5.3f\n",
-          (ue->dlsch_unscrambling_stats.p_time)/(cpuf*1000.0));
-    LOG_D(PHY, "AbsSubframe %d.%d --> LDPC Decoding for CW0 %5.3f\n",
-          frame_rx%1024, nr_slot_rx,(ue->dlsch_decoding_stats.p_time)/(cpuf*1000.0));
+  stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
+  if (cpumeas(CPUMEAS_GETSTATE)) {
+    LOG_D(PHY,
+          " --> Unscrambling for CW0 %5.3f\n",
+          ue->phy_cpu_stats.cpu_time_stats[DLSCH_UNSCRAMBLING_STATS].p_time / (cpuf * 1000.0));
+    LOG_D(PHY,
+          "AbsSubframe %d.%d --> LDPC Decoding for CW0 %5.3f\n",
+          frame_rx % 1024,
+          nr_slot_rx,
+          ue->phy_cpu_stats.cpu_time_stats[DLSCH_DECODING_STATS].p_time / (cpuf * 1000.0));
   }
 
   if(is_cw1_active) {
@@ -819,14 +806,13 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
       int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, dlsch_config->start_symbol, dlsch_config->number_symbols);
       unav_res = n_ptrs * ptrsSymbPerSlot;
     }
+    start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
     unav_res += compute_csi_rm_unav_res(dlsch_config);
     G = nr_get_G(dlsch_config->number_rbs, nb_symb_sch, nb_re_dmrs, dmrs_len, unav_res, dlsch_config->qamModOrder, dlsch[1].Nl);
-    start_meas(&ue->dlsch_unscrambling_stats);
     nr_dlsch_unscrambling(llr[1], G, 0, dlsch[1].dlsch_config.dlDataScramblingId, dlsch[1].rnti);
-    stop_meas(&ue->dlsch_unscrambling_stats);
-
-    start_meas(&ue->dlsch_decoding_stats);
+    stop_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
 
+    start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
     ret1 = nr_dlsch_decoding(ue,
                              proc,
                              gNB_id,
@@ -843,14 +829,16 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
                              G);
     LOG_T(PHY,"CW dlsch decoding, ret1 = %d\n", ret1);
 
-    stop_meas(&ue->dlsch_decoding_stats);
+    stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
     if (cpumeas(CPUMEAS_GETSTATE)) {
-      LOG_D(PHY, " --> Unscrambling for CW1 %5.3f\n", (ue->dlsch_unscrambling_stats.p_time) / (cpuf * 1000.0));
+      LOG_D(PHY,
+            " --> Unscrambling for CW1 %5.3f\n",
+            ue->phy_cpu_stats.cpu_time_stats[DLSCH_UNSCRAMBLING_STATS].p_time / (cpuf * 1000.0));
       LOG_D(PHY,
             "AbsSubframe %d.%d --> ldpc Decoding for CW1 %5.3f\n",
             frame_rx % 1024,
             nr_slot_rx,
-            (ue->dlsch_decoding_stats.p_time) / (cpuf * 1000.0));
+            ue->phy_cpu_stats.cpu_time_stats[DLSCH_DECODING_STATS].p_time / (cpuf * 1000.0));
     }
     LOG_D(PHY, "harq_pid: %d, TBS expected dlsch1: %d \n", harq_pid, dlsch[1].dlsch_config.TBS);
   }
@@ -884,7 +872,6 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
   nr_ue_dlsch_init(phy_data->dlsch, NR_MAX_NB_LAYERS>4 ? 2:1, ue->max_ldpc_iterations);
   
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN);
-  start_meas(&ue->phy_proc_rx);
 
   LOG_D(PHY," ****** start RX-Chain for Frame.Slot %d.%d ******  \n",
         frame_rx%1024, nr_slot_rx);
@@ -913,7 +900,6 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
           for (int i=1; i<4; i++) {
             nr_slot_fep(ue, fp, proc, (ssb_start_symbol + i) % (fp->symbols_per_slot), rxdataF, link_type_dl);
 
-            start_meas(&ue->dlsch_channel_estimation_stats);
             nr_pbch_channel_estimation(&ue->frame_parms,
                                        NULL,
                                        ue->nr_gold_pbch,
@@ -929,7 +915,6 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
                                        rxdataF,
                                        false,
                                        fp->Nid_cell);
-            stop_meas(&ue->dlsch_channel_estimation_stats);
 
             if (i - 1 == 2)
               UEscopeCopy(ue,
@@ -1007,8 +992,6 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
 
   uint8_t nb_symb_pdcch = phy_pdcch_config->nb_search_space > 0 ? phy_pdcch_config->pdcch_config[0].coreset.duration : 0;
   for (uint16_t l=0; l<nb_symb_pdcch; l++) {
-
-    start_meas(&ue->ofdm_demod_stats);
     nr_slot_fep(ue, fp, proc, l, rxdataF, link_type_dl);
   }
 
@@ -1032,8 +1015,6 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
                                   pdcch_dl_ch_estimates,
                                   rxdataF);
 
-      stop_meas(&ue->ofdm_demod_stats);
-
     }
     dci_cnt = dci_cnt + nr_ue_pdcch_procedures(ue, proc, pdcch_est_size, pdcch_dl_ch_estimates, phy_data, n_ss, rxdataF);
   }
@@ -1050,8 +1031,6 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
   int gNB_id = proc->gNB_id;
 
   NR_UE_DLSCH_t *dlsch = &phy_data->dlsch[0];
-  time_stats_t meas = {0};
-  start_meas(&meas);
   // do procedures for C-RNTI
 
   bool slot_fep_map[14] = {0};
@@ -1146,7 +1125,7 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
     LOG_D(PHY, "DLSCH data reception at nr_slot_rx: %d\n", nr_slot_rx);
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN);
 
-    start_meas(&ue->dlsch_procedures_stat);
+    start_meas_nr_ue_phy(ue, DLSCH_PROCEDURES_STATS);
 
     if (ret_pdsch >= 0)
       nr_ue_dlsch_procedures(ue, proc, dlsch, llr, G);
@@ -1158,10 +1137,9 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
       LOG_W(NR_PHY, "nr_ue_pdsch_procedures failed in slot %d\n", proc->nr_slot_rx);
     }
 
-    stop_meas(&ue->dlsch_procedures_stat);
+    stop_meas_nr_ue_phy(ue, DLSCH_PROCEDURES_STATS);
     if (cpumeas(CPUMEAS_GETSTATE)) {
-      LOG_D(PHY, "[SFN %d] Slot1:       Pdsch Proc %5.2f\n",nr_slot_rx,ue->pdsch_procedures_stat.p_time/(cpuf*1000.0));
-      LOG_D(PHY, "[SFN %d] Slot0 Slot1: Dlsch Proc %5.2f\n",nr_slot_rx,ue->dlsch_procedures_stat.p_time/(cpuf*1000.0));
+      LOG_D(PHY, "[SFN %d] Slot0 Slot1: Dlsch Proc %5.2f\n",nr_slot_rx,ue->phy_cpu_stats.cpu_time_stats[DLSCH_PROCEDURES_STATS].p_time/(cpuf*1000.0));
     }
 
     if (ue->phy_sim_rxdataF)
@@ -1174,8 +1152,6 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
       free(llr[i]);
   }
 
-  start_meas(&meas);
-
   if (nr_slot_rx==9) {
     if (frame_rx % 10 == 0) {
       if ((ue->dlsch_received[gNB_id] - ue->dlsch_received_last[gNB_id]) != 0)
@@ -1200,10 +1176,6 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
 
   }
 
-  stop_meas(&meas);
-  if (cpumeas(CPUMEAS_GETSTATE))
-    LOG_D(PHY, "after ldpc decode until end of Rx %5.2f \n", meas.p_time / (cpuf * 1000.0));
-
 #ifdef EMOS
   phy_procedures_emos_UE_RX(ue,slot,gNB_id);
 #endif
@@ -1211,10 +1183,6 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT);
 
-  stop_meas(&ue->phy_proc_rx);
-  if (cpumeas(CPUMEAS_GETSTATE))
-    LOG_D(PHY, "------FULL RX PROC [SFN %d]: %5.2f ------\n",nr_slot_rx,ue->phy_proc_rx.p_time/(cpuf*1000.0));
-
   LOG_D(PHY," ****** end RX-Chain  for AbsSubframe %d.%d ******  \n", frame_rx%1024, nr_slot_rx);
   UEscopeCopy(ue, commonRxdataF, rxdataF, sizeof(int32_t), ue->frame_parms.nb_antennas_rx, rxdataF_sz, 0);
 }
diff --git a/openair1/SIMULATION/LTE_PHY/common_sim.h b/openair1/SIMULATION/LTE_PHY/common_sim.h
index 5625cf8e2f65c22a00c66f8ead548d9ebb5cd40b..aaea26c5bb8c80773ead9090f7945f1f3df91817 100644
--- a/openair1/SIMULATION/LTE_PHY/common_sim.h
+++ b/openair1/SIMULATION/LTE_PHY/common_sim.h
@@ -62,18 +62,20 @@ void printDistribution(time_stats_t *ptr, varArray_t *sortedList, char *txt) {
 }
 
 void printStatIndent(time_stats_t *ptr, char *txt) {
-  printf("|__ %-38s %6.2f us (%3d trials)\n",
+  printf("|__ %-38s %6.2f us (%3d trials)\t\t(%6.2f total [ms])\n",
          txt,
          ptr->trials?inMicroS(ptr->diff/ptr->trials):0,
-         ptr->trials);
+         ptr->trials,
+         ptr->trials?inMicroS(ptr->diff)/1000:0);
 }
 
 void printStatIndent2(time_stats_t *ptr, char *txt) {
   double timeBase=1/(1000*get_cpu_freq_GHz());
-  printf("    |__ %-34s %6.2f us (%3d trials)\n",
+  printf("    |__ %-34s %6.2f us (%3d trials)\t\t(%6.2f total [ms])\n",
          txt,
          ptr->trials?((double)ptr->diff)/ptr->trials*timeBase:0,
-	 ptr->trials);
+         ptr->trials,
+         ptr->trials?inMicroS(ptr->diff)/1000:0);
 }
 
 void printStatIndent3(time_stats_t *ptr, char *txt) {
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index 27236d140ea0c7511b22d92107788a9c374b397b..61835126f6765cfa0e28ba494caf9276a4064ede 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -826,6 +826,7 @@ int main(int argc, char **argv)
   UE->frame_parms.nb_antennas_rx = n_rx;
   UE->frame_parms.nb_antenna_ports_gNB = n_tx;
   UE->max_ldpc_iterations = max_ldpc_iterations;
+  init_nr_ue_phy_cpu_stats(&UE->phy_cpu_stats);
 
   if (run_initial_sync==1)
     UE->is_synchronized = 0;
@@ -1244,36 +1245,10 @@ int main(int argc, char **argv)
       printStatIndent2(&gNB->dlsch_resource_mapping_stats, "DLSCH Resource Mapping time");
       printStatIndent2(&gNB->dlsch_precoding_stats,"DLSCH Layer Precoding time");
 
-      printf("\nUE RX function statistics (per %d us slot)\n",1000>>*scc->ssbSubcarrierSpacing);
-      /*
-      printDistribution(&phy_proc_rx_tot, table_rx,"Total PHY proc rx");
-      printStatIndent(&ue_front_end_tot,"Front end processing");
-      printStatIndent(&dlsch_llr_tot,"rx_pdsch processing");
-      printStatIndent2(&pdsch_procedures_tot,"pdsch processing");
-      printStatIndent2(&dlsch_procedures_tot,"dlsch processing");
-      printStatIndent2(&UE->crnti_procedures_stats,"C-RNTI processing");
-      printStatIndent(&UE->ofdm_demod_stats,"ofdm demodulation");
-      printStatIndent(&UE->dlsch_channel_estimation_stats,"DLSCH channel estimation time");
-      printStatIndent(&UE->dlsch_freq_offset_estimation_stats,"DLSCH frequency offset estimation time");
-      printStatIndent(&dlsch_decoding_tot, "DLSCH Decoding time ");
-      printStatIndent(&UE->dlsch_unscrambling_stats,"DLSCH unscrambling time");
-      printStatIndent(&UE->dlsch_rate_unmatching_stats,"DLSCH Rate Unmatching");
-      printf("|__ DLSCH Turbo Decoding(%d bits), avg iterations: %.1f       %.2f us (%d cycles, %d trials)\n",
-	     UE->dlsch[0][0]->harq_processes[0]->Cminus ?
-	     UE->dlsch[0][0]->harq_processes[0]->Kminus :
-	     UE->dlsch[0][0]->harq_processes[0]->Kplus,
-	     UE->dlsch_tc_intl1_stats.trials/(double)UE->dlsch_tc_init_stats.trials,
-	     (double)UE->dlsch_turbo_decoding_stats.diff/UE->dlsch_turbo_decoding_stats.trials*timeBase,
-	     (int)((double)UE->dlsch_turbo_decoding_stats.diff/UE->dlsch_turbo_decoding_stats.trials),
-	     UE->dlsch_turbo_decoding_stats.trials);
-      printStatIndent2(&UE->dlsch_tc_init_stats,"init");
-      printStatIndent2(&UE->dlsch_tc_alpha_stats,"alpha");
-      printStatIndent2(&UE->dlsch_tc_beta_stats,"beta");
-      printStatIndent2(&UE->dlsch_tc_gamma_stats,"gamma");
-      printStatIndent2(&UE->dlsch_tc_ext_stats,"ext");
-      printStatIndent2(&UE->dlsch_tc_intl1_stats,"turbo internal interleaver");
-      printStatIndent2(&UE->dlsch_tc_intl2_stats,"intl2+HardDecode+CRC");
-      */
+      printf("\nUE function statistics (per %d us slot)\n", 1000 >> *scc->ssbSubcarrierSpacing);
+      for (int i = RX_PDSCH_STATS; i <= DLSCH_PROCEDURES_STATS; i++) {
+        printStatIndent(&UE->phy_cpu_stats.cpu_time_stats[i], UE->phy_cpu_stats.cpu_time_stats[i].meas_name);
+      }
     }
 
     if (n_trials == 1) {
diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c
index c280bd64de795e0d2daf85f1eafc45e188887098..91046d920d8e56905e5c3058cf6cdf6383e826f4 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -955,10 +955,6 @@ int main(int argc, char *argv[])
     reset_meas(&gNB->rx_pusch_symbol_processing_stats);
     reset_meas(&gNB->ulsch_decoding_stats);
     reset_meas(&gNB->ulsch_channel_estimation_stats);
-    reset_meas(&UE->ulsch_ldpc_encoding_stats);
-    reset_meas(&UE->ulsch_rate_matching_stats);
-    reset_meas(&UE->ulsch_interleaving_stats);
-    reset_meas(&UE->ulsch_encoding_stats);
     reset_meas(&gNB->rx_srs_stats);
     reset_meas(&gNB->generate_srs_stats);
     reset_meas(&gNB->get_srs_signal_stats);
@@ -967,6 +963,7 @@ int main(int argc, char *argv[])
     reset_meas(&gNB->srs_report_tlv_stats);
     reset_meas(&gNB->srs_beam_report_stats);
     reset_meas(&gNB->srs_iq_matrix_stats);
+    init_nr_ue_phy_cpu_stats(&UE->phy_cpu_stats);
 
     uint32_t errors_scrambling[16] = {0};
     int n_errors[16] = {0};
@@ -1580,11 +1577,9 @@ int main(int argc, char *argv[])
       printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
 
       printf("\nUE TX\n");
-      printStatIndent(&UE->ulsch_encoding_stats,"ULSCH total encoding time");
-      printStatIndent2(&UE->ulsch_segmentation_stats,"ULSCH segmentation time");
-      printStatIndent2(&UE->ulsch_ldpc_encoding_stats,"ULSCH LDPC encoder time");
-      printStatIndent2(&UE->ulsch_rate_matching_stats,"ULSCH rate-matching time");
-      printStatIndent2(&UE->ulsch_interleaving_stats,"ULSCH interleaving time");
+      for (int i = PHY_PROC_TX; i <= ULSCH_ENCODING_STATS; i++) {
+        printStatIndent(&UE->phy_cpu_stats.cpu_time_stats[i], UE->phy_cpu_stats.cpu_time_stats[i].meas_name);
+      }
       printStatIndent(&gNB->rx_srs_stats,"RX SRS time");
       printStatIndent2(&gNB->generate_srs_stats,"Generate SRS sequence time");
       printStatIndent2(&gNB->get_srs_signal_stats,"Get SRS signal time");