* INTC Contribution to the O-RAN F Release for O-DU Low
[o-du/phy.git] / fhi_lib / app / src / app_profile_xran.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2020 Intel.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 *
17 *******************************************************************************/
18
19 #include <assert.h>
20 #include <err.h>
21 #include <arpa/inet.h>
22 #include <sys/time.h>
23 #include <time.h>
24 #include <immintrin.h>
25 #include <libgen.h>
26 #include "common.h"
27 #include "xran_fh_o_du.h"
28 #include "xran_pkt.h"
29 #include "xran_pkt_up.h"
30 #include "xran_cp_api.h"
31 #include "xran_up_api.h"
32
33 #include "xran_mlog_lnx.h"
34 #include "app_profile_xran.h"
35 #include "xran_timer.h"
36 #include "xran_lib_mlog_tasks_id.h"
37 #include "xran_mlog_task_id.h"
38
39 #define XRAN_REPORT_FILE    "xran_mlog_stats"
40
41 int32_t xran_init_mlog_stats(char *file, uint64_t nTscFreq);
42 int32_t xran_get_mlog_stats(char *, UsecaseConfig *, RuntimeConfig *[], struct xran_mlog_times *);
43
44 struct xran_mlog_times mlog_times = {0};
45 struct xran_mlog_stats tmp;
46 uint64_t xran_total_ticks = 0, xran_mlog_time;
47 uint64_t tWake, tWakePrev = 0;
48
49 extern UsecaseConfig* p_usecaseConfiguration;
50 extern RuntimeConfig* p_startupConfiguration[XRAN_PORTS_NUM];
51
52 #ifdef MLOG_ENABLED
53 /*
54  * Covert a test case path into a test case name
55  *   with the last two basenames in the path.
56  */
57 int32_t
58 test_path_to_name(char *path, char *name)
59 {
60     if (path == NULL || name == NULL)
61     {
62         print_err("Null path(%#p) or name(%#p)", path, name);
63         return -1;
64     }
65
66     char *dir, *base, *np = strdup(path);
67     int num=0;
68
69     if (np)
70     {
71         base = basename(np);
72         if (isdigit(*base))
73         {
74             num = atoi(base);
75             *--base = '\0';     /* trim the last basename */
76             base = basename(np);
77         }
78
79         dir = dirname(np);
80         sprintf(name, "%s-%s-%d", basename(dir), base, num);
81         free(np);
82         return 0;
83     }
84
85     return -1;
86 }
87
88
89
90
91 //-------------------------------------------------------------------------------------------
92 /** @ingroup group_source_flexran_xran
93  *
94  *  @param[in]   nTscFreq Frequency of the Time Stamp Counter (TSC) that the CPU currently is
95  *                        programmed with
96  *  @return  0 if SUCCESS
97  *
98  *  @description
99  *  This function dumps current CPU information onto the XRAN_REPORT_FILE file which is used
100  *  for automation of report generation
101  *
102 **/
103 //-------------------------------------------------------------------------------------------
104 int32_t
105 xran_init_mlog_stats(char *file, uint64_t nTscFreq)
106 {
107     char command[1024];
108     FILE *pFile= NULL;
109
110     pFile = fopen(file, "w");
111     if (pFile == NULL)
112     {
113         printf("1: Cannot open %s to write in phydi_init_mlog_stats\n", file);
114         return -1;
115     }
116     fprintf(pFile, "------------------------------------------------------------------------------------------------------------\n");
117     fprintf(pFile, "SYSTEM_PARAMS:\n");
118     fprintf(pFile, "TSC_FREQ: %ld\n", nTscFreq);
119
120 #ifdef BBDEV_FEC_ACCL_NR5G
121     PPHYCFG_VARS pPhyCfgVars = phycfg_get_ctx();
122
123     if (pPhyCfgVars->dpdkBasebandFecMode == 0)
124     {
125         fprintf(pFile, "FEC_OFFLOAD: SOFT_LDPC\n");
126     }
127     else
128     {
129         uint32_t nRet = phy_gnb_check_bbdev_hw_type();
130
131         if (nRet == BBDEV_DEV_NAME_MOUNT_BRYCE)
132             fprintf(pFile, "FEC_OFFLOAD: MOUNT_BRYCE\n");
133         else if (nRet == BBDEV_DEV_NAME_VISTA_CREEK)
134             fprintf(pFile, "FEC_OFFLOAD: VISTA_CREEK\n");
135         else if (nRet == BBDEV_DEV_NAME_SW_LDPC)
136             fprintf(pFile, "FEC_OFFLOAD: SOFT_LDPC\n");
137         else
138             fprintf(pFile, "FEC_OFFLOAD: UNKNOWN\n");
139     }
140 #else
141     fprintf(pFile, "FEC_OFFLOAD: TERASIC\n");
142 #endif
143
144     fclose(pFile);
145     pFile = NULL;
146     usleep(100000);
147     sprintf(command, "lscpu >> %s", file);
148     system(command);
149     usleep(100000);
150
151     pFile = fopen(file, "a");
152     if (pFile == NULL)
153     {
154         printf("2: Cannot open %s to write in %s\n", file, __FUNCTION__);
155         return -1;
156     }
157     fprintf(pFile, "------------------------------------------------------------------------------------------------------------\n");
158     fprintf(pFile, "COMMAND_LINE:\n");
159     fclose(pFile);
160
161     usleep(100000);
162     sprintf(command, "cat /proc/cmdline >> %s", file);
163     system(command);
164     usleep(100000);
165
166     pFile = fopen(file, "a");
167     if (pFile == NULL)
168     {
169         printf("3: Cannot open %s to write in %s\n", file, __FUNCTION__);
170         return -1;
171     }
172     fprintf(pFile, "------------------------------------------------------------------------------------------------------------\n");
173     fprintf(pFile, "MEMORY_INFO:\n");
174     fclose(pFile);
175     pFile = NULL;
176
177     usleep(100000);
178     sprintf(command, "dmidecode -t memory >> %s", file);
179     system(command);
180     usleep(100000);
181
182     pFile = fopen(file, "a");
183     if (pFile == NULL)
184     {
185         printf("4: Cannot open %s to write in %s\n", file, __FUNCTION__);
186         return -1;
187     }
188     fprintf(pFile, "------------------------------------------------------------------------------------------------------------\n");
189     fprintf(pFile, "TURBOSTAT_INFO:\n");
190     fclose(pFile);
191     pFile = NULL;
192     usleep(100000);
193     sprintf(command, "turbostat --num_iterations 1 --interval 1 -q >> %s", file);
194
195     system(command);
196     usleep(100000);
197
198     pFile = fopen(file, "a");
199     if (pFile == NULL)
200     {
201         printf("5: Cannot open %s to write in %s\n", file, __FUNCTION__);
202         return -1;
203     }
204     fprintf(pFile, "---------------------------------------------------------------------------\n");
205     fflush(pFile);
206     fclose(pFile);
207
208     return 0;
209 }
210
211 int32_t
212 xran_get_mlog_stats(char *usecase, UsecaseConfig *puConf, RuntimeConfig *psConf[], struct xran_mlog_times *mlog_times_p)
213 {
214     int i, ret=0;
215     FILE *pFile= NULL;
216     char stats_file[512]={0};
217     struct xran_mlog_stats tti, tmp;
218     uint32_t ttiDuration = 1000;
219
220     printf("%s: Usecase: %s\n", __FUNCTION__, usecase);
221     if (puConf == NULL || psConf == NULL || mlog_times_p == NULL) {
222         print_err("Null puConf(%p), psConf(%p), or mlog_times(%p)!",
223                 puConf, psConf, mlog_times_p);
224         ret = -1;
225         goto exit;
226     }
227
228     MLogPrint((char *)MLogGetFileName());
229
230     MLogGetStats(PID_TTI_TIMER, &tti.cnt, &tti.max, &tti.min, &tti.avg);
231     if (tti.cnt != 0) {
232         sprintf(stats_file, "%s-%s-%s", XRAN_REPORT_FILE, (puConf->appMode == APP_O_DU)? "o-du" : "o-ru", usecase);
233         printf("xran report file: %s\n", stats_file);
234         ret = xran_init_mlog_stats(stats_file, mlog_times_p->ticks_per_usec);
235         if (ret != 0)
236         {
237             print_err("xran_init_mlog_stats(%s) returned %d!!", stats_file, ret);
238             ret = -2;
239             goto exit;
240         }
241
242         pFile = fopen(stats_file, "a");
243         if (pFile == NULL)
244         {
245             print_err("Cannot create %s!!", stats_file);
246             ret = -2;
247             goto exit;
248         }
249
250         for (i = 0; i < psConf[0]->mu_number; i++)
251             ttiDuration = ttiDuration >> 1;
252
253         fprintf(pFile, "All data in this sheet are presented in usecs\n");
254         fprintf(pFile, "ORANTest: %s-%s (Num Cells: %d) (Num TTI: %d) (nNumerology: %d) (ttiDuration: %d usecs) (testStats: %d %ld %ld)\n",
255             (puConf->appMode == APP_O_DU)? "O-DU" : "O-RU", usecase, puConf->oXuNum * psConf[0]->numCC, tti.cnt, psConf[0]->mu_number, ttiDuration, puConf->appMode, mlog_times_p->xran_total_time, mlog_times_p->mlog_total_time);
256
257         double xran_task_type_sum[XRAN_TASK_TYPE_MAX] = {0, 0, 0, 0, 0, 0};
258         char * xran_task_type_name[XRAN_TASK_TYPE_MAX] =
259             { "GNB", "BBDEV", "Timer", "Radio", "CP", "UP" };
260 #define NUM_GNB_TASKS           (5)
261 #define NUM_BBDEV_TASKS         (4)
262 #define NUM_TIMER_TASKS         (7)
263 #define NUM_RADIO_TASKS         (2)
264 #define NUM_CP_TASKS            (7)
265 #define NUM_UP_TASKS            (5)
266 #define NUM_ALL_TASKS (NUM_GNB_TASKS+NUM_BBDEV_TASKS+NUM_TIMER_TASKS+NUM_RADIO_TASKS+NUM_CP_TASKS+NUM_UP_TASKS)
267         struct xran_mlog_taskid xranTasks[NUM_ALL_TASKS] = {
268             {PID_GNB_PROC_TIMING, XRAN_TASK_TYPE_GNB,              "GNB_PROCC_TIMING                    \0"},
269             {PID_GNB_PROC_TIMING_TIMEOUT, XRAN_TASK_TYPE_GNB,      "GNB_PROCC_TIMING_TIMEOUT            \0"},
270             {PID_GNB_SYM_CB, XRAN_TASK_TYPE_GNB,                   "GNB_SYM_CB                          \0"},
271             {PID_GNB_PRACH_CB, XRAN_TASK_TYPE_GNB,                 "GNB_PRACH_CB                        \0"},
272             {PID_GNB_SRS_CB, XRAN_TASK_TYPE_GNB,                   "GNB_SRS_CB                          \0"},
273
274             {PID_XRAN_BBDEV_DL_POLL, XRAN_TASK_TYPE_BBDEV,         "BBDEV_DL_POLL                       \0"},
275             {PID_XRAN_BBDEV_DL_POLL_DISPATCH, XRAN_TASK_TYPE_BBDEV,"BBDEV_DL_POLL_DISPATCH              \0"},
276             {PID_XRAN_BBDEV_UL_POLL, XRAN_TASK_TYPE_BBDEV,         "BBDEV_UL_POLL                       \0"},
277             {PID_XRAN_BBDEV_UL_POLL_DISPATCH, XRAN_TASK_TYPE_BBDEV,"BBDEV_UL_POLL_DISPATCH              \0"},
278
279             {PID_TTI_TIMER, XRAN_TASK_TYPE_TIMER,                  "TTI_TIMER                           \0"},
280             {PID_TTI_CB, XRAN_TASK_TYPE_TIMER,                     "TTI_CB                              \0"},
281             {PID_TIME_SYSTIME_POLL, XRAN_TASK_TYPE_TIMER,          "TIME_SYSTIME_POLL                   \0"},
282             {PID_TIME_SYSTIME_STOP, XRAN_TASK_TYPE_TIMER,          "TIME_SYSTIME_STOP                   \0"},
283             {PID_TIME_ARM_TIMER, XRAN_TASK_TYPE_TIMER,             "TIME_ARM_TIMER                      \0"},
284             {PID_TIME_ARM_TIMER_DEADLINE, XRAN_TASK_TYPE_TIMER,    "TIME_ARM_TIMER_DEADLINE             \0"},
285             {PID_TIME_ARM_USER_TIMER_DEADLINE, XRAN_TASK_TYPE_TIMER,"TIME_ARM_USER_TIMER_DEADLINE        \0"},
286
287             {PID_RADIO_ETH_TX_BURST, XRAN_TASK_TYPE_RADIO,         "RADIO_ETH_TX_BURST                  \0"},
288             {PID_RADIO_RX_VALIDATE, XRAN_TASK_TYPE_RADIO,          "RADIO_RX_VALIDATE                   \0"},
289
290             {PID_PROCESS_TX_SYM, XRAN_TASK_TYPE_CP,                "PROCESS_TX_SYM                      \0"},
291             {PID_DISPATCH_TX_SYM, XRAN_TASK_TYPE_CP,               "PID_DISPATCH_TX_SYM                 \0"},
292             {PID_CP_DL_CB, XRAN_TASK_TYPE_CP,                      "PID_CP_DL_CB                        \0"},
293             {PID_CP_UL_CB, XRAN_TASK_TYPE_CP,                      "PID_CP_UL_CB                        \0"},
294             {PID_SYM_OTA_CB, XRAN_TASK_TYPE_CP,                    "SYM_OTA_CB                          \0"},
295             {PID_TTI_CB_TO_PHY, XRAN_TASK_TYPE_CP,                 "TTI_CB_TO_PHY                       \0"},
296             {PID_PROCESS_CP_PKT, XRAN_TASK_TYPE_CP,                "PROCESS_CP_PKT                      \0"},
297
298             {PID_UP_UL_HALF_DEAD_LINE_CB, XRAN_TASK_TYPE_UP,       "UP_UL_HALF_DEAD_LINE_CB             \0"},
299             {PID_UP_UL_FULL_DEAD_LINE_CB, XRAN_TASK_TYPE_UP,       "UP_UL_FULL_DEAD_LINE_CB             \0"},
300             {PID_UP_UL_USER_DEAD_LINE_CB, XRAN_TASK_TYPE_UP,       "UP_UL_USER_DEAD_LINE_CB             \0"},
301             {PID_PROCESS_UP_PKT, XRAN_TASK_TYPE_UP,                "PROCESS_UP_PKT                      \0"},
302             {PID_PROCESS_UP_PKT_SRS, XRAN_TASK_TYPE_UP,            "PROCESS_UP_PKT_SRS                  \0"},
303         };
304
305 #if 1
306         fprintf(pFile, "mlog_times: core used/total %lu/%lu, xran %lu(us)\n",
307                 mlog_times_p->core_used_time, mlog_times_p->core_total_time,
308                 mlog_times_p->xran_total_time);
309 #endif
310
311         fprintf(pFile, "---------------------------------------------------------------------------\n");
312         fprintf(pFile, "All task breakdown\n");
313         for (i=0; i < NUM_ALL_TASKS; i++) {
314             struct xran_mlog_taskid *p;
315
316             p = &xranTasks[i];
317             MLogGetStats(p->taskId, &tmp.cnt, &tmp.max, &tmp.min, &tmp.avg);
318             fprintf(pFile, "%4u:%s\t\t:\t%5.2f\n",
319                     p->taskId, p->taskName, tmp.avg);
320             if (p->taskId != PID_TIME_SYSTIME_POLL) /* Skip TIME_SYSTIME_POLL */
321                 xran_task_type_sum[p->taskType] += tmp.avg * tmp.cnt;
322         }
323         fprintf(pFile, "---------------------------------------------------------------------------\n");
324         fprintf(pFile, "Task type breakdown:\t\ttotal time\t(busy %%)\n");
325         for (i=0; i < XRAN_TASK_TYPE_MAX; i++) {
326             char name[32] ={' '};
327
328             sprintf(name,"%5s tasks", xran_task_type_name[i]);
329             name[31]='\0';
330             fprintf(pFile, "%s:\t\t\t\t\t%7.2f\t(%5.2f%%)\n",
331                     name, xran_task_type_sum[i] / tti.cnt,
332                     xran_task_type_sum[i] * 100 / mlog_times_p->xran_total_time);
333         }
334         fprintf(pFile, "---------------------------------------------------------------------------\n\n");
335         fprintf(pFile, "====~~~~====~~~~====~~~~====~~~~====~~~~====~~~~====~~~~====~~~~====~~~~====~~~~====~~~~====~~~~====~~~~====~~~~~~~~====~~~~====~~~~");
336     }
337
338 exit:
339     if (pFile)
340     {
341         fflush(pFile);
342         printf("Closing [%s] ...\n", stats_file);
343         fclose(pFile);
344         pFile = NULL;
345     }
346     printf("%s: exit: %d\n", __FUNCTION__, ret);
347     return ret;
348 }
349
350 int32_t
351 app_profile_xran_print_mlog_stats(char *usecase_file)
352 {
353     int32_t ret = 0;
354     char filename[512];
355
356     printf("core_total_time\t\t%lu,\tcore_used_time\t\t%lu,\t%5.2f%% busy\n",
357             mlog_times.core_total_time, mlog_times.core_used_time,
358             ((float)mlog_times.core_used_time * 100.0) / (float)mlog_times.core_total_time);
359     mlog_times.xran_total_time = xran_total_ticks / MLogGetFreq();
360     printf("xran_total_ticks %lu (%lu usec)\n", xran_total_ticks, mlog_times.xran_total_time);
361
362     MLogGetStats(PID_XRAN_MAIN, &tmp.cnt, &tmp.max, &tmp.min, &tmp.avg);
363     mlog_times.mlog_total_time = tmp.cnt * (uint64_t)tmp.avg;
364     printf("xran_mlog_time: %lu usec\n", mlog_times.mlog_total_time);
365
366     MLogSetMask(0); /* Turned off MLOG */
367     test_path_to_name(usecase_file, filename);
368     printf("test cases: %s\n", filename);
369     ret = xran_get_mlog_stats(filename, p_usecaseConfiguration, p_startupConfiguration, &mlog_times);
370
371     return ret;
372 }
373
374 #endif  /* MLOG_ENABLED */