Merged latest develop to nfapi
This commit is contained in:
+12
-9
@@ -397,18 +397,21 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int
|
||||
/* define variable only used in LOG macro's */
|
||||
# define LOG_VAR(A,B) A B
|
||||
# else /* T_TRACER: remove all debugging and tracing messages, except errors */
|
||||
# define LOG_I(c, x...) do {logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ; } while(0)/* */
|
||||
# define LOG_W(c, x...) do {logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_WARNING, x) ; } while(0)/* */
|
||||
# define LOG_E(c, x...) do {logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_ERR, x) ; } while(0)/* */
|
||||
# define LOG_D(c, x...) do {logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_DEBUG, x) ; } while(0)/* */
|
||||
# define LOG_T(c, x...) /* */
|
||||
|
||||
# define LOG_DUMPMSG(c, b, s, x...) /* */
|
||||
# define LOG_E(c, x...) do { if( g_log->log_component[c].level >= OAILOG_ERR ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_ERR, x) ;} while (0)
|
||||
# define LOG_W(c, x...) do { if( g_log->log_component[c].level >= OAILOG_WARNING) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_WARNING, x) ;} while (0)
|
||||
# define LOG_I(c, x...) do { if( g_log->log_component[c].level >= OAILOG_INFO ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ;} while (0)
|
||||
# define LOG_D(c, x...) do { if( g_log->log_component[c].level >= OAILOG_DEBUG ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_DEBUG, x) ;} while (0)
|
||||
# define LOG_T(c, x...) do { if( g_log->log_component[c].level >= OAILOG_TRACE ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_TRACE, x) ;} while (0)
|
||||
# define VLOG(c,l, f, args) do { if( g_log->log_component[c].level >= l ) vlogRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, l, f, args) ; } while (0)
|
||||
|
||||
# define nfapi_log(FILE, FNC, LN, COMP, LVL, FMT...)
|
||||
# define LOG_DEBUGFLAG(D) ( 0 )
|
||||
# define LOG_DUMPFLAG(D) ( 0 )
|
||||
# define LOG_DEBUGFLAG(D) (g_log->dump_mask & D)
|
||||
# define LOG_DUMPFLAG(D) (g_log->debug_mask & D)
|
||||
# define LOG_DUMPMSG(c, f, b, s, x...) do { if(g_log->dump_mask & f) log_dump(c, b, s, LOG_DUMP_CHAR, x) ;} while (0) /* */
|
||||
|
||||
# define LOG_M(file, vector, data, len, dec, format) do { write_file_matlab(file, vector, data, len, dec, format);} while(0)
|
||||
# define LOG_VAR(A,B)
|
||||
# define LOG_VAR(A,B) A B
|
||||
# endif /* T_TRACER */
|
||||
/* avoid warnings for variables only used in LOG macro's but set outside debug section */
|
||||
#define GCC_NOTUSED __attribute__((unused))
|
||||
|
||||
@@ -814,6 +814,7 @@ static inline unsigned long long int vcd_get_time(void)
|
||||
return (long long unsigned int)((time.tv_nsec - g_time_start.tv_nsec)) +
|
||||
((long long unsigned int)time.tv_sec - (long long unsigned int)g_time_start.tv_sec) * 1000000000UL;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vcd_signal_dumper_create_header(void)
|
||||
|
||||
@@ -601,11 +601,19 @@ extern int ouput_vcd;
|
||||
|
||||
#else /* T_TRACER */
|
||||
|
||||
#if ENABLE_VCD
|
||||
#define VCD_SIGNAL_DUMPER_INIT(aRgUmEnT) vcd_signal_dumper_init(aRgUmEnT)
|
||||
#define VCD_SIGNAL_DUMPER_CLOSE() vcd_signal_dumper_close()
|
||||
#define VCD_SIGNAL_DUMPER_CREATE_HEADER() vcd_signal_dumper_create_header()
|
||||
#define VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(vAr1,vAr2) vcd_signal_dumper_dump_variable_by_name(vAr1,vAr2)
|
||||
#define VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(vAr1,vAr2) vcd_signal_dumper_dump_function_by_name(vAr1,vAr2)
|
||||
#else
|
||||
#define VCD_SIGNAL_DUMPER_INIT(aRgUmEnT)
|
||||
#define VCD_SIGNAL_DUMPER_CLOSE()
|
||||
#define VCD_SIGNAL_DUMPER_CREATE_HEADER()
|
||||
#define VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(vAr1,vAr2)
|
||||
#define VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(vAr1,vAr2)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* T_TRACER */
|
||||
|
||||
@@ -85,6 +85,10 @@ ID = ENB_PHY_MIB
|
||||
DESC = MIB data
|
||||
GROUP = ALL:PHY:ENB:WIRESHARK
|
||||
FORMAT = int,eNB_ID : int,frame : int,subframe : buffer,data
|
||||
ID = GNB_PHY_MIB
|
||||
DESC = NR MIB data
|
||||
GROUP = ALL:PHY:GNB:WIRESHARK
|
||||
FORMAT = int,gNB_ID : int,frame : int,slot : buffer,data
|
||||
|
||||
#MAC logs
|
||||
ID = ENB_MAC_UE_DL_SDU
|
||||
@@ -131,6 +135,18 @@ ID = ENB_MAC_UE_DL_RAR_PDU_WITH_DATA
|
||||
DESC = MAC downlink PDU for an UE
|
||||
GROUP = ALL:MAC:ENB:WIRESHARK
|
||||
FORMAT = int,eNB_ID : int,CC_id : int,rnti : int,frame : int,subframe : int,harq_pid : buffer,data
|
||||
ID = GNB_MAC_DL_PDU_WITH_DATA
|
||||
DESC = NR MAC downlink PDU for an UE
|
||||
GROUP = ALL:MAC:GNB:WIRESHARK
|
||||
FORMAT = int,gNB_ID : int,CC_id : int,rnti : int,frame : int,slot : int,harq_pid : buffer,data
|
||||
ID = GNB_MAC_UL_PDU_WITH_DATA
|
||||
DESC = NR MAC uplink PDU for an UE
|
||||
GROUP = ALL:MAC:GNB:WIRESHARK
|
||||
FORMAT = int,gNB_ID : int,CC_id : int,rnti : int,frame : int,slot : int,harq_pid : buffer,data
|
||||
ID = GNB_MAC_DL_RAR_PDU_WITH_DATA
|
||||
DESC = NR MAC downlink PDU for RAR
|
||||
GROUP = ALL:MAC:GNB:WIRESHARK
|
||||
FORMAT = int,gNB_ID : int,CC_id : int,rnti : int,frame : int,slot : int,harq_pid : buffer,data
|
||||
|
||||
#RLC logs
|
||||
ID = ENB_RLC_DL
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _TRACER_DEFS_H_
|
||||
#define _TRACER_DEFS_H_
|
||||
#ifndef _COMMON_UTILS_T_DEFS_H_
|
||||
#define _COMMON_UTILS_T_DEFS_H_
|
||||
|
||||
/* types of plots */
|
||||
#define PLOT_VS_TIME 0
|
||||
@@ -27,4 +27,4 @@ void *forwarder(char *ip, int port);
|
||||
void forward(void *forwarder, char *buf, int size);
|
||||
void forward_start_client(void *forwarder, int socket);
|
||||
|
||||
#endif /* _TRACER_DEFS_H_ */
|
||||
#endif /* _COMMON_UTILS_T_DEFS_H_ */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _TRACER_DEFS_H_
|
||||
#define _TRACER_DEFS_H_
|
||||
#ifndef _COMMON_UTILS_T_TRACER_DEFS_H_
|
||||
#define _COMMON_UTILS_T_TRACER_DEFS_H_
|
||||
|
||||
/* types of plots */
|
||||
#define PLOT_VS_TIME 0
|
||||
@@ -21,4 +21,4 @@ void t_gui_start(void);
|
||||
void t_gui_set_input_signal(int eNB, int frame, int subframe, int antenna,
|
||||
int size, void *buf);
|
||||
|
||||
#endif /* _TRACER_DEFS_H_ */
|
||||
#endif /* _COMMON_UTILS_T_TRACER_DEFS_H_ */
|
||||
|
||||
@@ -23,6 +23,8 @@ typedef struct {
|
||||
int socket;
|
||||
struct sockaddr_in to;
|
||||
OBUF buf;
|
||||
|
||||
/* LTE traces */
|
||||
/* ul */
|
||||
int ul_rnti;
|
||||
int ul_frame;
|
||||
@@ -46,6 +48,28 @@ typedef struct {
|
||||
int rar_frame;
|
||||
int rar_subframe;
|
||||
int rar_data;
|
||||
|
||||
/* NR traces */
|
||||
/* NR ul */
|
||||
int nr_ul_rnti;
|
||||
int nr_ul_frame;
|
||||
int nr_ul_slot;
|
||||
int nr_ul_data;
|
||||
/* NR dl */
|
||||
int nr_dl_rnti;
|
||||
int nr_dl_frame;
|
||||
int nr_dl_slot;
|
||||
int nr_dl_data;
|
||||
/* NR mib */
|
||||
int nr_mib_frame;
|
||||
int nr_mib_slot;
|
||||
int nr_mib_data;
|
||||
/* NR RAR */
|
||||
int nr_rar_rnti;
|
||||
int nr_rar_frame;
|
||||
int nr_rar_slot;
|
||||
int nr_rar_data;
|
||||
|
||||
/* config */
|
||||
int no_mib;
|
||||
int no_sib;
|
||||
@@ -58,8 +82,13 @@ typedef struct {
|
||||
int cur_sib;
|
||||
} ev_data;
|
||||
|
||||
void trace(ev_data *d, int direction, int rnti_type, int rnti,
|
||||
int frame, int subframe, void *buf, int bufsize, int preamble) {
|
||||
/****************************************************************************/
|
||||
/* LTE */
|
||||
/****************************************************************************/
|
||||
|
||||
void trace_lte(ev_data *d, int direction, int rnti_type, int rnti,
|
||||
int frame, int subframe, void *buf, int bufsize, int preamble)
|
||||
{
|
||||
ssize_t ret;
|
||||
int fsf;
|
||||
int i;
|
||||
@@ -100,15 +129,17 @@ void trace(ev_data *d, int direction, int rnti_type, int rnti,
|
||||
if (ret != d->buf.osize) abort();
|
||||
}
|
||||
|
||||
void ul(void *_d, event e) {
|
||||
void ul(void *_d, event e)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
trace(d, DIRECTION_UPLINK, C_RNTI, e.e[d->ul_rnti].i,
|
||||
e.e[d->ul_frame].i, e.e[d->ul_subframe].i,
|
||||
e.e[d->ul_data].b, e.e[d->ul_data].bsize,
|
||||
NO_PREAMBLE);
|
||||
trace_lte(d, DIRECTION_UPLINK, C_RNTI, e.e[d->ul_rnti].i,
|
||||
e.e[d->ul_frame].i, e.e[d->ul_subframe].i,
|
||||
e.e[d->ul_data].b, e.e[d->ul_data].bsize,
|
||||
NO_PREAMBLE);
|
||||
}
|
||||
|
||||
void dl(void *_d, event e) {
|
||||
void dl(void *_d, event e)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
|
||||
if (e.e[d->dl_rnti].i == 0xffff) {
|
||||
@@ -119,14 +150,15 @@ void dl(void *_d, event e) {
|
||||
d->cur_sib++;
|
||||
}
|
||||
|
||||
trace(d, DIRECTION_DOWNLINK,
|
||||
e.e[d->dl_rnti].i != 0xffff ? C_RNTI : SI_RNTI, e.e[d->dl_rnti].i,
|
||||
e.e[d->dl_frame].i, e.e[d->dl_subframe].i,
|
||||
e.e[d->dl_data].b, e.e[d->dl_data].bsize,
|
||||
NO_PREAMBLE);
|
||||
trace_lte(d, DIRECTION_DOWNLINK,
|
||||
e.e[d->dl_rnti].i != 0xffff ? C_RNTI : SI_RNTI, e.e[d->dl_rnti].i,
|
||||
e.e[d->dl_frame].i, e.e[d->dl_subframe].i,
|
||||
e.e[d->dl_data].b, e.e[d->dl_data].bsize,
|
||||
NO_PREAMBLE);
|
||||
}
|
||||
|
||||
void mib(void *_d, event e) {
|
||||
void mib(void *_d, event e)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
|
||||
if (d->no_mib) return;
|
||||
@@ -134,30 +166,141 @@ void mib(void *_d, event e) {
|
||||
if (d->max_mib && d->cur_mib == d->max_mib) return;
|
||||
|
||||
d->cur_mib++;
|
||||
trace(d, DIRECTION_DOWNLINK, NO_RNTI, 0,
|
||||
e.e[d->mib_frame].i, e.e[d->mib_subframe].i,
|
||||
e.e[d->mib_data].b, e.e[d->mib_data].bsize,
|
||||
NO_PREAMBLE);
|
||||
trace_lte(d, DIRECTION_DOWNLINK, NO_RNTI, 0,
|
||||
e.e[d->mib_frame].i, e.e[d->mib_subframe].i,
|
||||
e.e[d->mib_data].b, e.e[d->mib_data].bsize,
|
||||
NO_PREAMBLE);
|
||||
}
|
||||
|
||||
void preamble(void *_d, event e) {
|
||||
void preamble(void *_d, event e)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
trace(d, DIRECTION_UPLINK, NO_RNTI, 0,
|
||||
e.e[d->preamble_frame].i, e.e[d->preamble_subframe].i,
|
||||
NULL, 0,
|
||||
e.e[d->preamble_preamble].i);
|
||||
trace_lte(d, DIRECTION_UPLINK, NO_RNTI, 0,
|
||||
e.e[d->preamble_frame].i, e.e[d->preamble_subframe].i,
|
||||
NULL, 0,
|
||||
e.e[d->preamble_preamble].i);
|
||||
}
|
||||
|
||||
void rar(void *_d, event e) {
|
||||
void rar(void *_d, event e)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
trace(d, DIRECTION_DOWNLINK, RA_RNTI, e.e[d->rar_rnti].i,
|
||||
e.e[d->rar_frame].i, e.e[d->rar_subframe].i,
|
||||
e.e[d->rar_data].b, e.e[d->rar_data].bsize,
|
||||
NO_PREAMBLE);
|
||||
trace_lte(d, DIRECTION_DOWNLINK, RA_RNTI, e.e[d->rar_rnti].i,
|
||||
e.e[d->rar_frame].i, e.e[d->rar_subframe].i,
|
||||
e.e[d->rar_data].b, e.e[d->rar_data].bsize,
|
||||
NO_PREAMBLE);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* NR */
|
||||
/****************************************************************************/
|
||||
|
||||
#define MAC_NR_START_STRING "mac-nr"
|
||||
|
||||
#define MAC_NR_PAYLOAD_TAG 0x01
|
||||
#define MAC_NR_RNTI_TAG 0x02
|
||||
#define MAC_NR_FRAME_SLOT_TAG 0x07
|
||||
|
||||
#define NR_FDD_RADIO 1
|
||||
#define NR_TDD_RADIO 2
|
||||
|
||||
#define NR_DIRECTION_UPLINK 0
|
||||
#define NR_DIRECTION_DOWNLINK 1
|
||||
|
||||
#define NR_NO_RNTI 0
|
||||
#define NR_RA_RNTI 2
|
||||
#define NR_C_RNTI 3
|
||||
|
||||
void trace_nr(ev_data *d, int direction, int rnti_type, int rnti,
|
||||
int frame, int slot, void *buf, int bufsize, int preamble)
|
||||
{
|
||||
ssize_t ret;
|
||||
int i;
|
||||
d->buf.osize = 0;
|
||||
PUTS(&d->buf, MAC_NR_START_STRING);
|
||||
PUTC(&d->buf, NR_TDD_RADIO);
|
||||
PUTC(&d->buf, direction);
|
||||
PUTC(&d->buf, rnti_type);
|
||||
|
||||
if (rnti_type == NR_C_RNTI || rnti_type == NR_RA_RNTI) {
|
||||
PUTC(&d->buf, MAC_NR_RNTI_TAG);
|
||||
PUTC(&d->buf, (rnti>>8) & 255);
|
||||
PUTC(&d->buf, rnti & 255);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* for old versions of wireshark; not sure if correct */
|
||||
int fsf = (frame << 4) + slot;
|
||||
PUTC(&d->buf, 4 /* MAC_NR_FRAME_SUBFRAME_TAG */);
|
||||
PUTC(&d->buf, (fsf>>8) & 255);
|
||||
PUTC(&d->buf, fsf & 255);
|
||||
#else
|
||||
PUTC(&d->buf, MAC_NR_FRAME_SLOT_TAG);
|
||||
PUTC(&d->buf, (frame>>8) & 255);
|
||||
PUTC(&d->buf, frame & 255);
|
||||
PUTC(&d->buf, (slot>>8) & 255);
|
||||
PUTC(&d->buf, slot & 255);
|
||||
#endif
|
||||
|
||||
PUTC(&d->buf, MAC_NR_PAYLOAD_TAG);
|
||||
|
||||
for (i = 0; i < bufsize; i++)
|
||||
PUTC(&d->buf, ((char *)buf)[i]);
|
||||
|
||||
ret = sendto(d->socket, d->buf.obuf, d->buf.osize, 0,
|
||||
(struct sockaddr *)&d->to, sizeof(struct sockaddr_in));
|
||||
|
||||
if (ret != d->buf.osize) abort();
|
||||
}
|
||||
|
||||
void nr_ul(void *_d, event e)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
|
||||
trace_nr(d, NR_DIRECTION_UPLINK, NR_C_RNTI, e.e[d->nr_ul_rnti].i,
|
||||
e.e[d->nr_ul_frame].i, e.e[d->nr_ul_slot].i,
|
||||
e.e[d->nr_ul_data].b, e.e[d->nr_ul_data].bsize, NO_PREAMBLE);
|
||||
}
|
||||
|
||||
void nr_dl(void *_d, event e)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
|
||||
trace_nr(d, NR_DIRECTION_DOWNLINK, NR_C_RNTI, e.e[d->nr_dl_rnti].i,
|
||||
e.e[d->nr_dl_frame].i, e.e[d->nr_dl_slot].i,
|
||||
e.e[d->nr_dl_data].b, e.e[d->nr_dl_data].bsize, NO_PREAMBLE);
|
||||
}
|
||||
|
||||
void nr_mib(void *_d, event e)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
|
||||
if (d->no_mib) return;
|
||||
|
||||
if (d->max_mib && d->cur_mib == d->max_mib) return;
|
||||
|
||||
d->cur_mib++;
|
||||
|
||||
trace_nr(d, NR_DIRECTION_DOWNLINK, NR_NO_RNTI, 0,
|
||||
e.e[d->nr_mib_frame].i, e.e[d->nr_mib_slot].i,
|
||||
e.e[d->nr_mib_data].b, e.e[d->nr_mib_data].bsize, NO_PREAMBLE);
|
||||
}
|
||||
|
||||
void nr_rar(void *_d, event e)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
|
||||
trace_nr(d, NR_DIRECTION_DOWNLINK, NR_RA_RNTI, e.e[d->nr_rar_rnti].i,
|
||||
e.e[d->nr_rar_frame].i, e.e[d->nr_rar_slot].i,
|
||||
e.e[d->nr_rar_data].b, e.e[d->nr_rar_data].bsize, NO_PREAMBLE);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
void setup_data(ev_data *d, void *database, int ul_id, int dl_id, int mib_id,
|
||||
int preamble_id, int rar_id) {
|
||||
int preamble_id, int rar_id,
|
||||
int nr_ul_id, int nr_dl_id, int nr_mib_id, int nr_rar_id)
|
||||
{
|
||||
database_event_format f;
|
||||
int i;
|
||||
d->ul_rnti = -1;
|
||||
@@ -174,10 +317,27 @@ void setup_data(ev_data *d, void *database, int ul_id, int dl_id, int mib_id,
|
||||
d->preamble_frame = -1;
|
||||
d->preamble_subframe = -1;
|
||||
d->preamble_preamble = -1;
|
||||
d->rar_rnti = -1;
|
||||
d->rar_frame = -1;
|
||||
d->rar_subframe = -1;
|
||||
d->rar_data = -1;
|
||||
d->rar_rnti = -1;
|
||||
d->rar_frame = -1;
|
||||
d->rar_subframe = -1;
|
||||
d->rar_data = -1;
|
||||
|
||||
d->nr_ul_rnti = -1;
|
||||
d->nr_ul_frame = -1;
|
||||
d->nr_ul_slot = -1;
|
||||
d->nr_ul_data = -1;
|
||||
d->nr_dl_rnti = -1;
|
||||
d->nr_dl_frame = -1;
|
||||
d->nr_dl_slot = -1;
|
||||
d->nr_dl_data = -1;
|
||||
d->nr_mib_frame = -1;
|
||||
d->nr_mib_slot = -1;
|
||||
d->nr_mib_data = -1;
|
||||
d->nr_rar_rnti = -1;
|
||||
d->nr_rar_frame = -1;
|
||||
d->nr_rar_slot = -1;
|
||||
d->nr_rar_data = -1;
|
||||
|
||||
#define G(var_name, var_type, var) \
|
||||
if (!strcmp(f.name[i], var_name)) { \
|
||||
if (strcmp(f.type[i], var_type)) goto error; \
|
||||
@@ -247,6 +407,60 @@ void setup_data(ev_data *d, void *database, int ul_id, int dl_id, int mib_id,
|
||||
if (d->rar_rnti == -1 || d->rar_frame == -1 || d->rar_subframe == -1 ||
|
||||
d->rar_data == -1) goto error;
|
||||
|
||||
/* NR ul: rnti, frame, slot, data */
|
||||
f = get_format(database, nr_ul_id);
|
||||
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("rnti", "int", d->nr_ul_rnti);
|
||||
G("frame", "int", d->nr_ul_frame);
|
||||
G("slot", "int", d->nr_ul_slot);
|
||||
G("data", "buffer", d->nr_ul_data);
|
||||
}
|
||||
|
||||
if (d->nr_ul_rnti == -1 || d->nr_ul_frame == -1 || d->nr_ul_slot == -1 ||
|
||||
d->nr_ul_data == -1)
|
||||
goto error;
|
||||
|
||||
/* NR dl: rnti, frame, slot, data */
|
||||
f = get_format(database, nr_dl_id);
|
||||
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("rnti", "int", d->nr_dl_rnti);
|
||||
G("frame", "int", d->nr_dl_frame);
|
||||
G("slot", "int", d->nr_dl_slot);
|
||||
G("data", "buffer", d->nr_dl_data);
|
||||
}
|
||||
|
||||
if (d->nr_dl_rnti == -1 || d->nr_dl_frame == -1 || d->nr_dl_slot == -1 ||
|
||||
d->nr_dl_data == -1)
|
||||
goto error;
|
||||
|
||||
/* NR MIB: frame, slot, data */
|
||||
f = get_format(database, nr_mib_id);
|
||||
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("frame", "int", d->nr_mib_frame);
|
||||
G("slot", "int", d->nr_mib_slot);
|
||||
G("data", "buffer", d->nr_mib_data);
|
||||
}
|
||||
|
||||
if (d->nr_mib_frame == -1 || d->nr_mib_slot== -1 || d->nr_mib_data == -1)
|
||||
goto error;
|
||||
|
||||
/* NR RAR: rnti, frame, slot, data */
|
||||
f = get_format(database, nr_rar_id);
|
||||
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("rnti", "int", d->nr_rar_rnti);
|
||||
G("frame", "int", d->nr_rar_frame);
|
||||
G("slot", "int", d->nr_rar_slot);
|
||||
G("data", "buffer", d->nr_rar_data);
|
||||
}
|
||||
|
||||
if (d->nr_rar_rnti == -1 || d->nr_rar_frame == -1 || d->nr_rar_slot == -1 ||
|
||||
d->nr_rar_data == -1)
|
||||
goto error;
|
||||
|
||||
#undef G
|
||||
return;
|
||||
error:
|
||||
@@ -254,7 +468,8 @@ error:
|
||||
abort();
|
||||
}
|
||||
|
||||
void *receiver(void *_d) {
|
||||
void *receiver(void *_d)
|
||||
{
|
||||
ev_data *d = _d;
|
||||
int s;
|
||||
char buf[100000];
|
||||
@@ -279,7 +494,8 @@ void *receiver(void *_d) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(void) {
|
||||
void usage(void)
|
||||
{
|
||||
printf(
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
@@ -304,14 +520,16 @@ void usage(void) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int n, char **v) {
|
||||
int main(int n, char **v)
|
||||
{
|
||||
char *database_filename = NULL;
|
||||
char *input_filename = NULL;
|
||||
void *database;
|
||||
event_handler *h;
|
||||
int in;
|
||||
int i;
|
||||
int ul_id, dl_id, mib_id = -1, preamble_id, rar_id;
|
||||
int ul_id, dl_id, mib_id, preamble_id, rar_id;
|
||||
int nr_ul_id, nr_dl_id, nr_mib_id, nr_rar_id;
|
||||
ev_data d;
|
||||
char *ip = DEFAULT_IP;
|
||||
int port = DEFAULT_PORT;
|
||||
@@ -382,6 +600,11 @@ int main(int n, char **v) {
|
||||
on_off(database, "ENB_PHY_INITIATE_RA_PROCEDURE", is_on, 1);
|
||||
on_off(database, "ENB_MAC_UE_DL_RAR_PDU_WITH_DATA", is_on, 1);
|
||||
|
||||
on_off(database, "GNB_MAC_UL_PDU_WITH_DATA", is_on, 1);
|
||||
on_off(database, "GNB_MAC_DL_PDU_WITH_DATA", is_on, 1);
|
||||
on_off(database, "GNB_PHY_MIB", is_on, 1);
|
||||
on_off(database, "GNB_MAC_DL_RAR_PDU_WITH_DATA", is_on, 1);
|
||||
|
||||
/* activate selected traces */
|
||||
if (socket_send(in, &mt, 1) == -1 ||
|
||||
socket_send(in, &number_of_events, sizeof(int)) == -1 ||
|
||||
@@ -398,12 +621,26 @@ int main(int n, char **v) {
|
||||
mib_id = event_id_from_name(database, "ENB_PHY_MIB");
|
||||
preamble_id = event_id_from_name(database, "ENB_PHY_INITIATE_RA_PROCEDURE");
|
||||
rar_id = event_id_from_name(database, "ENB_MAC_UE_DL_RAR_PDU_WITH_DATA");
|
||||
setup_data(&d, database, ul_id, dl_id, mib_id, preamble_id, rar_id);
|
||||
|
||||
nr_ul_id = event_id_from_name(database, "GNB_MAC_UL_PDU_WITH_DATA");
|
||||
nr_dl_id = event_id_from_name(database, "GNB_MAC_DL_PDU_WITH_DATA");
|
||||
nr_mib_id = event_id_from_name(database, "GNB_PHY_MIB");
|
||||
nr_rar_id = event_id_from_name(database, "GNB_MAC_DL_RAR_PDU_WITH_DATA");
|
||||
|
||||
setup_data(&d, database, ul_id, dl_id, mib_id, preamble_id, rar_id,
|
||||
nr_ul_id, nr_dl_id, nr_mib_id, nr_rar_id);
|
||||
|
||||
register_handler_function(h, ul_id, ul, &d);
|
||||
register_handler_function(h, dl_id, dl, &d);
|
||||
register_handler_function(h, mib_id, mib, &d);
|
||||
register_handler_function(h, preamble_id, preamble, &d);
|
||||
register_handler_function(h, rar_id, rar, &d);
|
||||
|
||||
register_handler_function(h, nr_ul_id, nr_ul, &d);
|
||||
register_handler_function(h, nr_dl_id, nr_dl, &d);
|
||||
register_handler_function(h, nr_mib_id, nr_mib, &d);
|
||||
register_handler_function(h, nr_rar_id, nr_rar, &d);
|
||||
|
||||
d.socket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
if (d.socket == -1) {
|
||||
@@ -424,8 +661,10 @@ int main(int n, char **v) {
|
||||
|
||||
if (e.type == -1) break;
|
||||
|
||||
if (!(e.type == ul_id || e.type == dl_id || e.type == mib_id ||
|
||||
e.type == preamble_id || e.type == rar_id)) continue;
|
||||
if (!(e.type == ul_id || e.type == dl_id || e.type == mib_id ||
|
||||
e.type == preamble_id || e.type == rar_id ||
|
||||
e.type == nr_ul_id || e.type == nr_dl_id ||
|
||||
e.type == nr_mib_id || e.type == nr_rar_id)) continue;
|
||||
|
||||
handle_event(h, e);
|
||||
}
|
||||
|
||||
@@ -101,11 +101,11 @@ static inline uint64_t BIT_STRING_to_uint64(BIT_STRING_t *asn) {
|
||||
|
||||
shift = ((asn->size - 1) * 8) - asn->bits_unused;
|
||||
for (index = 0; index < (asn->size - 1); index++) {
|
||||
result |= asn->buf[index] << shift;
|
||||
result |= ((uint64_t)asn->buf[index]) << shift;
|
||||
shift -= 8;
|
||||
}
|
||||
|
||||
result |= asn->buf[index] >> asn->bits_unused;
|
||||
result |= ((uint64_t)asn->buf[index]) >> asn->bits_unused;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,490 +0,0 @@
|
||||
/*
|
||||
* 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 "assertions.h"
|
||||
#include "memory_pools.h"
|
||||
|
||||
#if T_TRACER
|
||||
#include <string.h>
|
||||
#include "T.h"
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
const static int mp_debug = 0;
|
||||
|
||||
# define MP_DEBUG(x, args...) do { if (mp_debug) fprintf(stdout, "[MP][D]"x, ##args); fflush (stdout); } \
|
||||
while(0)
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
#ifndef CHARS_TO_UINT32
|
||||
#define CHARS_TO_UINT32(c1, c2, c3, c4) (((c1) << 24) | ((c2) << 16) | ((c3) << 8) | (c4))
|
||||
#endif
|
||||
|
||||
#define MEMORY_POOL_ITEM_INFO_NUMBER 2
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
typedef int32_t items_group_position_t;
|
||||
typedef int32_t items_group_index_t;
|
||||
|
||||
typedef union items_group_positions_u {
|
||||
uint64_t all;
|
||||
struct {
|
||||
items_group_position_t put;
|
||||
items_group_position_t get;
|
||||
} ind;
|
||||
} items_group_positions_t;
|
||||
|
||||
typedef struct items_group_s {
|
||||
items_group_position_t number_plus_one;
|
||||
volatile uint32_t minimum;
|
||||
volatile items_group_positions_t positions;
|
||||
volatile items_group_index_t *indexes;
|
||||
} items_group_t;
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
//static const items_group_position_t ITEMS_GROUP_POSITION_INVALID = -1;
|
||||
static const items_group_index_t ITEMS_GROUP_INDEX_INVALID = -1;
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
typedef uint32_t pool_item_start_mark_t;
|
||||
typedef uint32_t pool_item_end_mark_t;
|
||||
|
||||
typedef uint32_t memory_pool_data_t;
|
||||
|
||||
typedef uint32_t pool_start_mark_t;
|
||||
|
||||
typedef uint32_t pools_start_mark_t;
|
||||
|
||||
typedef uint8_t pool_id_t;
|
||||
typedef uint8_t item_status_t;
|
||||
|
||||
typedef struct memory_pool_item_start_s {
|
||||
pool_item_start_mark_t start_mark;
|
||||
|
||||
pool_id_t pool_id;
|
||||
item_status_t item_status;
|
||||
uint16_t info[MEMORY_POOL_ITEM_INFO_NUMBER];
|
||||
} memory_pool_item_start_t;
|
||||
|
||||
typedef struct memory_pool_item_end_s {
|
||||
pool_item_end_mark_t end_mark;
|
||||
} memory_pool_item_end_t;
|
||||
|
||||
typedef struct memory_pool_item_s {
|
||||
memory_pool_item_start_t start;
|
||||
memory_pool_data_t data[0];
|
||||
memory_pool_item_end_t end;
|
||||
} memory_pool_item_t;
|
||||
|
||||
typedef struct memory_pool_s {
|
||||
pool_start_mark_t start_mark;
|
||||
|
||||
pool_id_t pool_id;
|
||||
uint32_t item_data_number;
|
||||
uint32_t pool_item_size;
|
||||
items_group_t items_group_free;
|
||||
memory_pool_item_t *items;
|
||||
} memory_pool_t;
|
||||
|
||||
|
||||
typedef struct memory_pools_s {
|
||||
pools_start_mark_t start_mark;
|
||||
|
||||
uint32_t pools_number;
|
||||
uint32_t pools_defined;
|
||||
memory_pool_t *pools;
|
||||
} memory_pools_t;
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static const uint32_t MAX_POOLS_NUMBER = 20;
|
||||
static const uint32_t MAX_POOL_ITEMS_NUMBER = 200 * 1000;
|
||||
static const uint32_t MAX_POOL_ITEM_SIZE = 100 * 1000;
|
||||
|
||||
static const pool_item_start_mark_t POOL_ITEM_START_MARK = CHARS_TO_UINT32 ('P', 'I', 's', 't');
|
||||
static const pool_item_end_mark_t POOL_ITEM_END_MARK = CHARS_TO_UINT32 ('p', 'i', 'E', 'N');
|
||||
|
||||
static const item_status_t ITEM_STATUS_FREE = 'F';
|
||||
static const item_status_t ITEM_STATUS_ALLOCATED = 'a';
|
||||
|
||||
static const pool_start_mark_t POOL_START_MARK = CHARS_TO_UINT32 ('P', '_', 's', 't');
|
||||
|
||||
static const pools_start_mark_t POOLS_START_MARK = CHARS_TO_UINT32 ('P', 'S', 's', 't');
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static inline uint32_t items_group_number_items (items_group_t *items_group) {
|
||||
return items_group->number_plus_one - 1;
|
||||
}
|
||||
|
||||
static inline uint32_t items_group_free_items (items_group_t *items_group) {
|
||||
items_group_positions_t positions;
|
||||
uint32_t free_items;
|
||||
positions.all = items_group->positions.all;
|
||||
free_items = items_group->number_plus_one + positions.ind.put - positions.ind.get;
|
||||
free_items %= items_group->number_plus_one;
|
||||
return free_items;
|
||||
}
|
||||
|
||||
static inline items_group_index_t items_group_get_free_item (items_group_t *items_group) {
|
||||
items_group_position_t get_raw;
|
||||
items_group_position_t put;
|
||||
items_group_position_t get;
|
||||
items_group_position_t free_items;
|
||||
items_group_index_t index = ITEMS_GROUP_INDEX_INVALID;
|
||||
/* Get current put position */
|
||||
put = items_group->positions.ind.put % items_group->number_plus_one;
|
||||
/* Get current get position and increase it */
|
||||
get_raw = __sync_fetch_and_add (&items_group->positions.ind.get, 1);
|
||||
get = get_raw % items_group->number_plus_one;
|
||||
|
||||
if(put == get) {
|
||||
/* No more item free, restore previous position */
|
||||
__sync_fetch_and_sub (&items_group->positions.ind.get, 1);
|
||||
} else {
|
||||
/* Get index at current get position */
|
||||
index = items_group->indexes[get];
|
||||
|
||||
if (index <= ITEMS_GROUP_INDEX_INVALID) {
|
||||
/* Index has not yet been completely freed, restore previous get position */
|
||||
__sync_fetch_and_sub (&items_group->positions.ind.get, 1);
|
||||
} else {
|
||||
if (get_raw == items_group->number_plus_one) {
|
||||
/* Wrap get position */
|
||||
__sync_fetch_and_sub (&items_group->positions.ind.get, items_group->number_plus_one);
|
||||
}
|
||||
|
||||
free_items = items_group_free_items(items_group);
|
||||
|
||||
/* Updates minimum free items if needed */
|
||||
while (items_group->minimum > free_items) {
|
||||
items_group->minimum = free_items;
|
||||
}
|
||||
|
||||
/* Clear index at current get position to indicate that item is free */
|
||||
items_group->indexes[get] = ITEMS_GROUP_INDEX_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return (index);
|
||||
}
|
||||
|
||||
static inline int items_group_put_free_item (items_group_t *items_group, items_group_index_t index) {
|
||||
items_group_position_t put_raw;
|
||||
items_group_position_t put;
|
||||
/* Get current put position and increase it */
|
||||
put_raw = __sync_fetch_and_add (&items_group->positions.ind.put, 1);
|
||||
put = put_raw % items_group->number_plus_one;
|
||||
|
||||
if (put_raw == items_group->number_plus_one) {
|
||||
/* Wrap position */
|
||||
__sync_fetch_and_sub (&items_group->positions.ind.put, items_group->number_plus_one);
|
||||
}
|
||||
|
||||
AssertError (items_group->indexes[put] <= ITEMS_GROUP_INDEX_INVALID, return (EXIT_FAILURE),
|
||||
"Index at current put position (%d) is not marked as free (%d)!\n", put, items_group->number_plus_one);
|
||||
/* Save freed item index at current put position */
|
||||
items_group->indexes[put] = index;
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static inline memory_pools_t *memory_pools_from_handler (memory_pools_handle_t memory_pools_handle) {
|
||||
memory_pools_t *memory_pools;
|
||||
/* Recover memory_pools */
|
||||
memory_pools = (memory_pools_t *) memory_pools_handle;
|
||||
/* Sanity check on passed handle */
|
||||
AssertError (memory_pools->start_mark == POOLS_START_MARK, memory_pools = NULL,
|
||||
"Handle %p is not a valid memory pools handle, start mark is missing!\n", memory_pools_handle);
|
||||
return (memory_pools);
|
||||
}
|
||||
|
||||
static inline memory_pool_item_t *memory_pool_item_from_handler (memory_pool_item_handle_t memory_pool_item_handle) {
|
||||
void *address;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
/* Recover memory_pools */
|
||||
address = memory_pool_item_handle - sizeof(memory_pool_item_start_t);
|
||||
memory_pool_item = (memory_pool_item_t *) address;
|
||||
/* Sanity check on passed handle */
|
||||
AssertError (memory_pool_item->start.start_mark == POOL_ITEM_START_MARK, memory_pool_item = NULL,
|
||||
"Handle %p is not a valid memory pool item handle, start mark is missing!\n", memory_pool_item);
|
||||
return (memory_pool_item);
|
||||
}
|
||||
|
||||
static inline memory_pool_item_t *memory_pool_item_from_index (memory_pool_t *memory_pool, items_group_index_t index) {
|
||||
void *address;
|
||||
address = (void *) memory_pool->items;
|
||||
address += index * memory_pool->pool_item_size;
|
||||
return (address);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
memory_pools_handle_t memory_pools_create (uint32_t pools_number) {
|
||||
memory_pools_t *memory_pools;
|
||||
pool_id_t pool;
|
||||
AssertFatal (pools_number <= MAX_POOLS_NUMBER, "Too many memory pools requested (%d/%d)!\n", pools_number, MAX_POOLS_NUMBER); /* Limit to a reasonable number of pools */
|
||||
/* Allocate memory_pools */
|
||||
memory_pools = malloc (sizeof(memory_pools_t));
|
||||
AssertFatal (memory_pools != NULL, "Memory pools structure allocation failed!\n");
|
||||
/* Initialize memory_pools */
|
||||
{
|
||||
memory_pools->start_mark = POOLS_START_MARK;
|
||||
memory_pools->pools_number = pools_number;
|
||||
memory_pools->pools_defined = 0;
|
||||
/* Allocate pools */
|
||||
memory_pools->pools = calloc (pools_number, sizeof(memory_pool_t));
|
||||
AssertFatal (memory_pools->pools != NULL, "Memory pools allocation failed!\n");
|
||||
|
||||
/* Initialize pools */
|
||||
for (pool = 0; pool < pools_number; pool++) {
|
||||
memory_pools->pools[pool].start_mark = POOL_START_MARK;
|
||||
}
|
||||
}
|
||||
return ((memory_pools_handle_t) memory_pools);
|
||||
}
|
||||
|
||||
char *memory_pools_statistics(memory_pools_handle_t memory_pools_handle) {
|
||||
memory_pools_t *memory_pools;
|
||||
pool_id_t pool;
|
||||
char *statistics;
|
||||
int printed_chars;
|
||||
uint32_t allocated_pool_memory;
|
||||
uint32_t allocated_pools_memory = 0;
|
||||
items_group_t *items_group;
|
||||
uint32_t pool_items_size;
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertFatal (memory_pools != NULL, "Failed to retrieve memory pool for handle %p!\n", memory_pools_handle);
|
||||
statistics = malloc(memory_pools->pools_defined * 200);
|
||||
printed_chars = sprintf (&statistics[0], "Pool: size, number, minimum, free, address space and memory used in Kbytes\n");
|
||||
|
||||
for (pool = 0; pool < memory_pools->pools_defined; pool++) {
|
||||
items_group = &memory_pools->pools[pool].items_group_free;
|
||||
allocated_pool_memory = items_group_number_items (items_group) * memory_pools->pools[pool].pool_item_size;
|
||||
allocated_pools_memory += allocated_pool_memory;
|
||||
pool_items_size = memory_pools->pools[pool].item_data_number * sizeof(memory_pool_data_t);
|
||||
printed_chars += sprintf (&statistics[printed_chars], " %2u: %6u, %6u, %6u, %6u, [%p-%p] %6u\n",
|
||||
pool, pool_items_size,
|
||||
items_group_number_items (items_group),
|
||||
items_group->minimum,
|
||||
items_group_free_items (items_group),
|
||||
memory_pools->pools[pool].items,
|
||||
((void *) memory_pools->pools[pool].items) + allocated_pool_memory,
|
||||
allocated_pool_memory / (1024));
|
||||
}
|
||||
|
||||
printed_chars = sprintf (&statistics[printed_chars], "Pools memory %u Kbytes\n", allocated_pools_memory / (1024));
|
||||
return (statistics);
|
||||
}
|
||||
|
||||
int memory_pools_add_pool (memory_pools_handle_t memory_pools_handle, uint32_t pool_items_number, uint32_t pool_item_size) {
|
||||
memory_pools_t *memory_pools;
|
||||
memory_pool_t *memory_pool;
|
||||
pool_id_t pool;
|
||||
items_group_index_t item_index;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
AssertFatal (pool_items_number <= MAX_POOL_ITEMS_NUMBER, "Too many items for a memory pool (%u/%d)!\n", pool_items_number, MAX_POOL_ITEMS_NUMBER); /* Limit to a reasonable number of items */
|
||||
AssertFatal (pool_item_size <= MAX_POOL_ITEM_SIZE, "Item size is too big for memory pool items (%u/%d)!\n", pool_item_size, MAX_POOL_ITEM_SIZE); /* Limit to a reasonable item size */
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertFatal (memory_pools != NULL, "Failed to retrieve memory pool for handle %p!\n", memory_pools_handle);
|
||||
/* Check number of already created pools */
|
||||
AssertFatal (memory_pools->pools_defined < memory_pools->pools_number, "Can not allocate more memory pool (%d)!\n", memory_pools->pools_number);
|
||||
/* Select pool */
|
||||
pool = memory_pools->pools_defined;
|
||||
memory_pool = &memory_pools->pools[pool];
|
||||
/* Initialize pool */
|
||||
{
|
||||
memory_pool->pool_id = pool;
|
||||
/* Item size in memory_pool_data_t items by excess */
|
||||
memory_pool->item_data_number = (pool_item_size + sizeof(memory_pool_data_t) - 1) / sizeof(memory_pool_data_t);
|
||||
memory_pool->pool_item_size = (memory_pool->item_data_number * sizeof(memory_pool_data_t)) + sizeof(memory_pool_item_t);
|
||||
memory_pool->items_group_free.number_plus_one = pool_items_number + 1;
|
||||
memory_pool->items_group_free.minimum = pool_items_number;
|
||||
memory_pool->items_group_free.positions.ind.put = pool_items_number;
|
||||
memory_pool->items_group_free.positions.ind.get = 0;
|
||||
/* Allocate free indexes */
|
||||
memory_pool->items_group_free.indexes = malloc(memory_pool->items_group_free.number_plus_one * sizeof(items_group_index_t));
|
||||
AssertFatal (memory_pool->items_group_free.indexes != NULL, "Memory pool indexes allocation failed!\n");
|
||||
|
||||
/* Initialize free indexes */
|
||||
for (item_index = 0; item_index < pool_items_number; item_index++) {
|
||||
memory_pool->items_group_free.indexes[item_index] = item_index;
|
||||
}
|
||||
|
||||
/* Last index is not allocated */
|
||||
memory_pool->items_group_free.indexes[item_index] = ITEMS_GROUP_INDEX_INVALID;
|
||||
/* Allocate items */
|
||||
memory_pool->items = calloc (pool_items_number, memory_pool->pool_item_size);
|
||||
AssertFatal (memory_pool->items != NULL, "Memory pool items allocation failed!\n");
|
||||
|
||||
/* Initialize items */
|
||||
for (item_index = 0; item_index < pool_items_number; item_index++) {
|
||||
memory_pool_item = memory_pool_item_from_index (memory_pool, item_index);
|
||||
memory_pool_item->start.start_mark = POOL_ITEM_START_MARK;
|
||||
memory_pool_item->start.pool_id = pool;
|
||||
memory_pool_item->start.item_status = ITEM_STATUS_FREE;
|
||||
memory_pool_item->data[memory_pool->item_data_number] = POOL_ITEM_END_MARK;
|
||||
}
|
||||
}
|
||||
memory_pools->pools_defined ++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
memory_pool_item_handle_t memory_pools_allocate (memory_pools_handle_t memory_pools_handle, uint32_t item_size, uint16_t info_0, uint16_t info_1) {
|
||||
memory_pools_t *memory_pools;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
memory_pool_item_handle_t memory_pool_item_handle = NULL;
|
||||
pool_id_t pool;
|
||||
items_group_index_t item_index = ITEMS_GROUP_INDEX_INVALID;
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertError (memory_pools != NULL, {}, "Failed to retrieve memory pool for handle %p!\n", memory_pools_handle);
|
||||
|
||||
for (pool = 0; pool < memory_pools->pools_defined; pool++) {
|
||||
if ((memory_pools->pools[pool].item_data_number * sizeof(memory_pool_data_t)) < item_size) {
|
||||
/* This memory pool has too small items, skip it */
|
||||
continue;
|
||||
}
|
||||
|
||||
item_index = items_group_get_free_item(&memory_pools->pools[pool].items_group_free);
|
||||
|
||||
if (item_index <= ITEMS_GROUP_INDEX_INVALID) {
|
||||
/* Allocation failed, skip this pool */
|
||||
continue;
|
||||
} else {
|
||||
/* Allocation succeed, exit searching loop */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (item_index > ITEMS_GROUP_INDEX_INVALID) {
|
||||
/* Convert item index into memory_pool_item address */
|
||||
memory_pool_item = memory_pool_item_from_index (&memory_pools->pools[pool], item_index);
|
||||
/* Sanity check on item status, must be free */
|
||||
AssertFatal (memory_pool_item->start.item_status == ITEM_STATUS_FREE, "Item status is not set to free (%d) in pool %u, item %d!\n",
|
||||
memory_pool_item->start.item_status, pool, item_index);
|
||||
memory_pool_item->start.item_status = ITEM_STATUS_ALLOCATED;
|
||||
memory_pool_item->start.info[0] = info_0;
|
||||
memory_pool_item->start.info[1] = info_1;
|
||||
memory_pool_item_handle = memory_pool_item->data;
|
||||
MP_DEBUG(" Alloc [%2u][%6d]{%6d}, %3u %3u, %6u, %p, %p, %p\n",
|
||||
pool, item_index,
|
||||
items_group_free_items (&memory_pools->pools[pool].items_group_free),
|
||||
info_0, info_1,
|
||||
item_size,
|
||||
memory_pools->pools[pool].items,
|
||||
memory_pool_item,
|
||||
memory_pool_item_handle);
|
||||
} else {
|
||||
MP_DEBUG(" Alloc [--][------]{------}, %3u %3u, %6u, failed!\n", info_0, info_1, item_size);
|
||||
}
|
||||
|
||||
return memory_pool_item_handle;
|
||||
}
|
||||
|
||||
int memory_pools_free (memory_pools_handle_t memory_pools_handle, memory_pool_item_handle_t memory_pool_item_handle, uint16_t info_0) {
|
||||
memory_pools_t *memory_pools;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
pool_id_t pool;
|
||||
items_group_index_t item_index;
|
||||
uint32_t item_size;
|
||||
uint32_t pool_item_size;
|
||||
uint16_t info_1;
|
||||
int result;
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertError (memory_pools != NULL, return (EXIT_FAILURE), "Failed to retrieve memory pools for handle %p!\n", memory_pools_handle);
|
||||
/* Recover memory pool item */
|
||||
memory_pool_item = memory_pool_item_from_handler (memory_pool_item_handle);
|
||||
AssertError (memory_pool_item != NULL, return (EXIT_FAILURE), "Failed to retrieve memory pool item for handle %p!\n", memory_pool_item_handle);
|
||||
info_1 = memory_pool_item->start.info[1];
|
||||
/* Recover pool index */
|
||||
pool = memory_pool_item->start.pool_id;
|
||||
AssertFatal (pool < memory_pools->pools_defined, "Pool index is invalid (%u/%u)!\n", pool, memory_pools->pools_defined);
|
||||
item_size = memory_pools->pools[pool].item_data_number;
|
||||
pool_item_size = memory_pools->pools[pool].pool_item_size;
|
||||
item_index = (((void *) memory_pool_item) - ((void *) memory_pools->pools[pool].items)) / pool_item_size;
|
||||
MP_DEBUG(" Free [%2u][%6d]{%6d}, %3u %3u, %p, %p, %p, %u\n",
|
||||
pool, item_index,
|
||||
items_group_free_items (&memory_pools->pools[pool].items_group_free),
|
||||
memory_pool_item->start.info[0], info_1,
|
||||
memory_pool_item_handle, memory_pool_item,
|
||||
memory_pools->pools[pool].items, ((uint32_t) (item_size * sizeof(memory_pool_data_t))));
|
||||
/* Sanity check on calculated item index */
|
||||
AssertFatal (memory_pool_item == memory_pool_item_from_index(&memory_pools->pools[pool], item_index),
|
||||
"Incorrect memory pool item address (%p, %p) for pool %u, item %d!\n",
|
||||
memory_pool_item,(void *)memory_pool_item_from_index(&memory_pools->pools[pool], item_index), pool, item_index);
|
||||
/* Sanity check on end marker, must still be present (no write overflow) */
|
||||
AssertFatal (memory_pool_item->data[item_size] == POOL_ITEM_END_MARK,
|
||||
"Memory pool item is corrupted, end mark is not present for pool %u, item %d!\n", pool, item_index);
|
||||
/* Sanity check on item status, must be allocated */
|
||||
AssertFatal (memory_pool_item->start.item_status == ITEM_STATUS_ALLOCATED,
|
||||
"Trying to free a non allocated (%x) memory pool item (pool %u, item %d)!\n",
|
||||
memory_pool_item->start.item_status, pool, item_index);
|
||||
memory_pool_item->start.item_status = ITEM_STATUS_FREE;
|
||||
result = items_group_put_free_item(&memory_pools->pools[pool].items_group_free, item_index);
|
||||
AssertError (result == EXIT_SUCCESS, {}, "Failed to free memory pool item (pool %u, item %d)!\n", pool, item_index);
|
||||
return (result);
|
||||
}
|
||||
|
||||
void memory_pools_set_info (memory_pools_handle_t memory_pools_handle, memory_pool_item_handle_t memory_pool_item_handle, int index, uint16_t info) {
|
||||
memory_pools_t *memory_pools;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
pool_id_t pool;
|
||||
items_group_index_t item_index;
|
||||
uint32_t item_size;
|
||||
uint32_t pool_item_size;
|
||||
AssertFatal (index < MEMORY_POOL_ITEM_INFO_NUMBER, "Incorrect info index (%d/%d)!\n", index, MEMORY_POOL_ITEM_INFO_NUMBER);
|
||||
/* Recover memory pool item */
|
||||
memory_pool_item = memory_pool_item_from_handler (memory_pool_item_handle);
|
||||
AssertFatal (memory_pool_item != NULL, "Failed to retrieve memory pool item for handle %p!\n", memory_pool_item_handle);
|
||||
/* Set info[1] */
|
||||
memory_pool_item->start.info[index] = info;
|
||||
|
||||
/* Check item validity and log (not mandatory) */
|
||||
if (1) {
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertFatal (memory_pools != NULL, "Failed to retrieve memory pool for handle %p!\n", memory_pools_handle);
|
||||
/* Recover pool index */
|
||||
pool = memory_pool_item->start.pool_id;
|
||||
AssertFatal (pool < memory_pools->pools_defined, "Pool index is invalid (%u/%u)!\n", pool, memory_pools->pools_defined);
|
||||
item_size = memory_pools->pools[pool].item_data_number;
|
||||
pool_item_size = memory_pools->pools[pool].pool_item_size;
|
||||
item_index = (((void *) memory_pool_item) - ((void *) memory_pools->pools[pool].items)) / pool_item_size;
|
||||
MP_DEBUG(" Info [%2u][%6d]{%6d}, %3u %3u, %p, %p, %p, %u\n",
|
||||
pool, item_index,
|
||||
items_group_free_items (&memory_pools->pools[pool].items_group_free),
|
||||
memory_pool_item->start.info[0], memory_pool_item->start.info[1],
|
||||
memory_pool_item_handle, memory_pool_item,
|
||||
memory_pools->pools[pool].items, ((uint32_t) (item_size * sizeof(memory_pool_data_t))));
|
||||
/* Sanity check on calculated item index */
|
||||
AssertFatal (memory_pool_item == memory_pool_item_from_index(&memory_pools->pools[pool], item_index),
|
||||
"Incorrect memory pool item address (%p, %p) for pool %u, item %d!\n",
|
||||
memory_pool_item, (void *)memory_pool_item_from_index(&memory_pools->pools[pool], item_index), pool, item_index);
|
||||
/* Sanity check on end marker, must still be present (no write overflow) */
|
||||
AssertFatal (memory_pool_item->data[item_size] == POOL_ITEM_END_MARK,
|
||||
"Memory pool item is corrupted, end mark is not present for pool %u, item %d!\n", pool, item_index);
|
||||
/* Sanity check on item status, must be allocated */
|
||||
AssertFatal (memory_pool_item->start.item_status == ITEM_STATUS_ALLOCATED,
|
||||
"Trying to free a non allocated (%x) memory pool item (pool %u, item %d)\n",
|
||||
memory_pool_item->start.item_status, pool, item_index);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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 MEMORY_POOLS_H_
|
||||
#define MEMORY_POOLS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void * memory_pools_handle_t;
|
||||
typedef void * memory_pool_item_handle_t;
|
||||
|
||||
memory_pools_handle_t memory_pools_create (uint32_t pools_number);
|
||||
|
||||
char *memory_pools_statistics(memory_pools_handle_t memory_pools_handle);
|
||||
|
||||
int memory_pools_add_pool (memory_pools_handle_t memory_pools_handle, uint32_t pool_items_number, uint32_t pool_item_size);
|
||||
|
||||
memory_pool_item_handle_t memory_pools_allocate (memory_pools_handle_t memory_pools_handle, uint32_t item_size, uint16_t info_0, uint16_t info_1);
|
||||
|
||||
int memory_pools_free (memory_pools_handle_t memory_pools_handle, memory_pool_item_handle_t memory_pool_item_handle, uint16_t info_0);
|
||||
|
||||
void memory_pools_set_info (memory_pools_handle_t memory_pools_handle, memory_pool_item_handle_t memory_pool_item_handle, int index, uint16_t info);
|
||||
|
||||
#endif /* MEMORY_POOLS_H_ */
|
||||
@@ -121,9 +121,11 @@ char toksep[2];
|
||||
case SCHED_RR:
|
||||
lptr+=sprintf(lptr,"%s ","rt: rr");
|
||||
break;
|
||||
#ifdef SCHED_DEADLINE
|
||||
case SCHED_DEADLINE:
|
||||
lptr+=sprintf(lptr,"%s ","rt: deadline");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
lptr+=sprintf(lptr,"%s ","????");
|
||||
break;
|
||||
|
||||
@@ -6,10 +6,9 @@ Each worker loop on pick from the same input queue jobs to do.
|
||||
|
||||
When a job is done, the worker sends a return if a return is defined.
|
||||
|
||||
A selective abort allows to cancel parallel jobs (usage: a client pushed jobs, but from a response of one job, the other linked jobs becomes useless).
|
||||
A selective abort allows to cancel parallel jobs (usage: a client pushed jobs, but from a response of one job, the other linked jobs becomes useless).
|
||||
|
||||
All the thread pool functions are thread safe, nevertheless the working functions are implemented by the thread pool client,
|
||||
so the client has to tackle the parallel execution of his functions called "processingFunc" hereafter.
|
||||
All the thread pool functions are thread safe, nevertheless the working functions are implemented by the thread pool client, so the client has to tackle the parallel execution of his functions called "processingFunc" hereafter.
|
||||
|
||||
## license
|
||||
Author:
|
||||
@@ -18,65 +17,187 @@ When a job is done, the worker sends a return if a return is defined.
|
||||
|
||||
# jobs
|
||||
|
||||
A job is a message (notifiedFIFO_elt_t):
|
||||
next:
|
||||
internal FIFO chain, do not set it
|
||||
key:
|
||||
a long int that the client can use to identify a message or a group of messages
|
||||
responseFifo:
|
||||
if the client defines a response FIFO, the message will be posted back after processing
|
||||
processingFunc:
|
||||
any funtion (type void processingFunc(void *)) that the worker will launch
|
||||
msgData:
|
||||
the data passed to processingFunc. It can be added automatically, or you can set it to a buffer you are managing
|
||||
malloced:
|
||||
a boolean that enable internal free in these cases:
|
||||
no return Fifo or Abort feature
|
||||
A job is a message (notifiedFIFO_elt_t):
|
||||
|
||||
The job messages can be created with newNotifiedFIFO_elt() and delNotifiedFIFO_elt() or managed by the client.
|
||||
* next:
|
||||
internal FIFO chain, do not set it
|
||||
* key:
|
||||
a long int that the client can use to identify a message or a group of messages
|
||||
* ResponseFifo:
|
||||
if the client defines a response FIFO, the message will be posted back after processing
|
||||
* processingFunc:
|
||||
any funtion (type void processingFunc(void *)) that the worker will launch
|
||||
* msgData:
|
||||
the data passed to processingFunc. It can be added automatically, or you can set it to a buffer you are managing
|
||||
* malloced:
|
||||
a boolean that enable internal free in these cases:
|
||||
no return Fifo or Abort feature
|
||||
|
||||
The job messages can be created with newNotifiedFIFO_elt() and delNotifiedFIFO_elt() or managed by the client.
|
||||
|
||||
# Queues of jobs
|
||||
|
||||
Queues are type of:
|
||||
notifiedFIFO_t that must be initialized by init_notifiedFIFO()
|
||||
No delete function is required, the creator has only to free the data of type notifiedFIFO_t
|
||||
Queues are type of:
|
||||
|
||||
push_notifiedFIFO() add a job in the queue
|
||||
pull_notifiedFIFO() is blocking, poll_notifiedFIFO() is non blocking
|
||||
* notifiedFIFO_t that must be initialized by init_notifiedFIFO()
|
||||
* No delete function is required, the creator has only to free the data of type notifiedFIFO_t
|
||||
* push_notifiedFIFO() add a job in the queue
|
||||
* pull_notifiedFIFO() is blocking, poll_notifiedFIFO() is non blocking
|
||||
* abort_notifiedFIFO() allows the customer to delete all waiting jobs that match with the key (see key in jobs definition)
|
||||
|
||||
abort_notifiedFIFO() allows the customer to delete all waiting jobs that match with the key (see key in jobs definition)
|
||||
These queues details hereafter
|
||||
|
||||
## Common
|
||||
|
||||
newNotifiedFIFO_elt()
|
||||
|
||||
creates a message, that will later be used in queues/FIFO
|
||||
|
||||
delNotifiedFIFO_elt()
|
||||
|
||||
deletes it
|
||||
|
||||
NotifiedFifoData()
|
||||
|
||||
gives a pointer to the beginning of free usage memory in a message (you can put any data there, up to 'size' parameter you passed to newNotifiedFIFO_elt()
|
||||
|
||||
These 3 calls are not mandatory, you can also use your own memory to save the malloc()/free() that are behind these calls
|
||||
iFirst level: non thread safe FIFO (or queues)
|
||||
|
||||
# low level: fast and simple
|
||||
|
||||
initNotifiedFIFO_nothreadSafe()
|
||||
|
||||
to create a queue
|
||||
|
||||
pushNotifiedFIFO_nothreadSafe()
|
||||
|
||||
Add a element in a queue
|
||||
|
||||
pullNotifiedFIFO_nothreadSafe()
|
||||
|
||||
pull a element from a queue
|
||||
|
||||
As these queues are not thread safe, there is NO blocking mechanism, neither pull() versus poll() calls
|
||||
|
||||
There is no delete for a message queue: you only have to abandon the memory you allocated to call iinitNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf)
|
||||
|
||||
So if you malloced the memory under 'nf' parameter you have to free it, if it is automatic variable (local variable) or global variable, nothing is to be done.
|
||||
|
||||
|
||||
## thread safe queues
|
||||
|
||||
These queues are built on not thread safe queues when we need thread to thread protection
|
||||
|
||||
initNotifiedFIFO()
|
||||
|
||||
to create a queue
|
||||
|
||||
pushNotifiedFIFO()
|
||||
|
||||
Add a element in a queue
|
||||
|
||||
pullNotifiedFIFO()
|
||||
|
||||
pull a element from a queue, this call is blocking until a message arrived
|
||||
|
||||
pollNotifiedFIFO()
|
||||
|
||||
pull a element from a queue, this call is not blocking, so it returns always very shortly
|
||||
|
||||
in 99.9% cases, pull() is better than poll()
|
||||
|
||||
No delete() call, same principle as not thread safe queues
|
||||
|
||||
# Thread pools
|
||||
|
||||
## initialization
|
||||
The clients can create one or more thread pools with init_tpool()
|
||||
the params string structure:
|
||||
describes a list of cores, separated by "," that run a worker thread
|
||||
The clients can create one or more thread pools with init_tpool()
|
||||
|
||||
If the core exists on the CPU, the thread pool initialization sets the affinity between this thread and
|
||||
the related code (use negative values is allowed, so the thread will never be mapped on a specific core).
|
||||
the params string structure: describes a list of cores, separated by "," that run a worker thread
|
||||
|
||||
The threads are all Linux real time scheduler, their name is set automatically is "Tpool_<core id>"
|
||||
If the core exists on the CPU, the thread pool initialization sets the affinity between this thread and the related code (use negative values is allowed, so the thread will never be mapped on a specific core).
|
||||
|
||||
The threads are all Linux real time scheduler, their name is set automatically is "Tpool_<core id>"
|
||||
|
||||
## adding jobs
|
||||
The client create their jobs messages as a notifiedFIFO_elt_t, then they push it with pushTpool() (that internally calls push_notifiedFIFO())
|
||||
The client create their jobs messages as a notifiedFIFO_elt_t, then they push it with pushTpool() (that internally calls push_notifiedFIFO())
|
||||
|
||||
If they need a return, they have to create response queues with init_notifiedFIFO() and set this FIFO pointer in the notifiedFIFO_elt_t before pushing the job.
|
||||
If they need a return, they have to create response queues with init_notifiedFIFO() and set this FIFO pointer in the notifiedFIFO_elt_t before pushing the job.
|
||||
|
||||
## abort
|
||||
|
||||
A abort service abortTpool() allows to abort all jobs that match a key (see jobs "key"). When the abort returns, it garanties no job (matching the key) response will be posted on response queues.
|
||||
A abort service abortTpool() allows to abort all jobs that match a key (see jobs "key"). When the abort returns, it garanties no job (matching the key) response will be posted on response queues.
|
||||
|
||||
Nevertheless, jobs already performed before the return of abortTpool() are pushed in the response Fifo queue.
|
||||
Nevertheless, jobs already performed before the return of abortTpool() are pushed in the response Fifo queue.
|
||||
|
||||
## API details
|
||||
Each thread pool (there can be several in the same process) should be initialized
|
||||
|
||||
### initTpool(char *params,tpool_t *pool, bool performanceMeas) is to be called oncepool
|
||||
|
||||
the configuration parameter is a string, elements separated by ",":
|
||||
|
||||
* N: if a N is in the parameter list, no threads are created
|
||||
The purpose is to keep the same API in any case
|
||||
* a CPU with a little number of cores,
|
||||
or in debugging sessions to simplify the human work
|
||||
* a number that represent a valid CPU core on the target CPU
|
||||
A thread is created and stick on the core (with set affinity)
|
||||
* a number that is not a valid CPU core
|
||||
a floating thread is created (Linux is responsible of the real time core allocation)
|
||||
|
||||
example: "-1,-1,-1"
|
||||
as there is no core number -1, the thread pool is made of 3 floating threads
|
||||
be careful with fix allocation: it is hard to be more clever than Linux kernel
|
||||
|
||||
pool is the memory you allocated before to store the thread pool internal state (same concept as above queues)
|
||||
|
||||
performanceMeas is a flag to enable measurements (well described in documentation)
|
||||
|
||||
### pushTpool(tpool_t *t, notifiedFIFO_elt_t *msg)
|
||||
|
||||
adds a job to do in the thread pool
|
||||
|
||||
The msg data you can set are:
|
||||
|
||||
* key:
|
||||
a value for you that you will find back in the response
|
||||
it is also the key for abortTpool()
|
||||
* reponseFifo
|
||||
if you set it, the message will be sent back on this queue when the job is done
|
||||
if you don't set it, no return is performed, the thread pool frees the message 'msg' when the job is done
|
||||
* processingFunc
|
||||
the function the job will run. the function prototype is void <func>(void *memory)
|
||||
the data part (the pointer returned by NotifiedFifoData(msg)) is passed to the function
|
||||
it is used to send data to the processing function and also to write back results
|
||||
of course, writing back results will lead you to use also a return queue (the parameter reponseFifo)
|
||||
|
||||
### pullTpool() collects job result in a return queue
|
||||
|
||||
you collect results in one result queue: the message you gave to pushTpool(), nevertheless it has been updated by processingFunc()
|
||||
|
||||
An example of multiple return queues, in eNB: I created one single thread pool (because it depends mainly on CPU hardware), but i use two return queues: one for turbo encode, one for turbo decode.
|
||||
|
||||
### tryPullTpool()
|
||||
|
||||
is the same, but not blocking (pollTpool() would have been a better name)
|
||||
|
||||
### abortTpool()
|
||||
|
||||
Is a facility to cancel work you pushed to a thread pool
|
||||
|
||||
I used it once: when eNB performs turbo decode, I push all segments in the thread pool.
|
||||
|
||||
But when I get back the decoding results, if one segment can't be decoded, I don't need the results of the other segments of the same UE.
|
||||
|
||||
## Performance measurements
|
||||
|
||||
A performance measurement is integrated:
|
||||
the pool will automacillay fill timestamps:
|
||||
|
||||
* creationTime:
|
||||
time the request is push to the pool;
|
||||
A performance measurement is integrated:
|
||||
the pool will automacillay fill timestamps:
|
||||
|
||||
* creationTime:
|
||||
time the request is push to the pool;
|
||||
* startProcessingTime:
|
||||
time a worker start to run on the job
|
||||
* endProcessingTime:
|
||||
|
||||
Reference in New Issue
Block a user