Commit b6d466d7 authored by Robert Schmidt's avatar Robert Schmidt

FlexRAN: reimplement timers without ITTI

The timer code used to trigger periodic statistics message sending used
ITTI. Together with a high frequency reporting (e.g. 1ms), this resulted
in high CPU usage. This commit reimplements this:
* using a thread that is synchronized to the RU (if there is no MAC, we
  assume there is no RU generating a tick so we create the tick source
  ourselves)
* no RB trees but plain arrays
* smaller interface for users
* slight user interface changes
* remove stopped timer state: such timer might be simply removed
* remove one-shot timers
parent 233affc9
......@@ -1562,11 +1562,10 @@ int flexran_agent_register_mac_xface(mid_t mod_id)
return -1;
}
//xface->agent_ctxt = &shared_ctxt[mod_id];
xface->flexran_agent_send_sr_info = flexran_agent_send_sr_info;
xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger;
//xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats;
xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config;
xface->flexran_agent_notify_tick = flexran_agent_timer_signal;
xface->dl_scheduler_loaded_lib = NULL;
xface->ul_scheduler_loaded_lib = NULL;
......@@ -1689,11 +1688,10 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id)
return -1;
}
AGENT_MAC_xface *xface = agent_mac_xface[mod_id];
//xface->agent_ctxt = NULL;
xface->flexran_agent_send_sr_info = NULL;
xface->flexran_agent_send_sf_trigger = NULL;
//xface->flexran_agent_send_update_mac_stats = NULL;
xface->flexran_agent_get_pending_dl_mac_config = NULL;
xface->flexran_agent_notify_tick = NULL;
xface->dl_scheduler_loaded_lib = NULL;
xface->ul_scheduler_loaded_lib = NULL;
......
......@@ -54,10 +54,9 @@ typedef struct {
void (*flexran_agent_get_pending_dl_mac_config)(mid_t mod_id,
Protocol__FlexranMessage **msg);
/// Notify the controller for a state change of a particular UE, by sending the proper
/// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER)
// int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti,
// uint8_t state_change);
/// Notify the controller of another (RU) tick, i.e. new subframe. Used to
/// synchronize the eNB and the agent.
void (*flexran_agent_notify_tick)(mid_t mod_id);
void *dl_scheduler_loaded_lib;
......
......@@ -33,27 +33,14 @@
#include <pthread.h>
#include <arpa/inet.h>
void *receive_thread(void *args);
Protocol__FlexranMessage *flexran_agent_timeout(void* args);
int agent_task_created = 0;
/*
* enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller
* and can interact with other itti tasks
*/
void *flexran_agent_task(void *args){
//flexran_agent_info_t *d = (flexran_agent_info_t *) args;
Protocol__FlexranMessage *msg;
void *data;
int size;
err_code_t err_code=0;
int priority = 0;
MessageDef *msg_p = NULL;
int result;
struct flexran_agent_timer_element_s * elem = NULL;
MessageDef *msg_p = NULL;
int result;
itti_mark_task_ready(TASK_FLEXRAN_AGENT);
......@@ -71,20 +58,6 @@ void *flexran_agent_task(void *args){
case MESSAGE_TEST:
LOG_I(FLEXRAN_AGENT, "Received %s\n", ITTI_MSG_NAME(msg_p));
break;
case TIMER_HAS_EXPIRED:
msg = flexran_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg);
if (msg != NULL){
data=flexran_agent_pack_message(msg,&size);
elem = get_timer_entry(msg_p->ittiMsg.timer_has_expired.timer_id);
if (flexran_agent_msg_send(elem->agent_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) {
err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING;
goto error;
}
LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size);
}
break;
default:
LOG_E(FLEXRAN_AGENT, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
......@@ -93,10 +66,6 @@ void *flexran_agent_task(void *args){
result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
continue;
error:
if (err_code != 0)
LOG_E(FLEXRAN_AGENT,"flexran_agent_task: error %d occured\n",err_code);
} while (1);
return NULL;
......@@ -245,7 +214,7 @@ int flexran_agent_start(mid_t mod_id)
* initilize a timer
*/
flexran_agent_init_timer();
flexran_agent_timer_init(mod_id);
/*
* start the enb agent task for tx and interaction with the underlying network function
......@@ -286,16 +255,3 @@ error:
return 1;
}
Protocol__FlexranMessage *flexran_agent_timeout(void* args){
// flexran_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args));
//memcpy (timer_args, args, sizeof(*timer_args));
flexran_agent_timer_args_t *timer_args = (flexran_agent_timer_args_t *) args;
LOG_UI(FLEXRAN_AGENT, "flexran_agent %d timeout\n", timer_args->mod_id);
//LOG_I(FLEXRAN_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags);
//LOG_I(FLEXRAN_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags);
return NULL;
}
......@@ -150,10 +150,15 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id,
uint32_t size);
/* Function to be used to send a message to a dispatcher once the appropriate event is triggered. */
Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args);
Protocol__FlexranMessage *flexran_agent_handle_timed_task(
mid_t mod_id,
Protocol__FlexranMessage *msg);
/*Top level Statistics hanlder*/
Protocol__FlexranMessage *flexran_agent_send_stats_reply(void *args);
Protocol__FlexranMessage *flexran_agent_send_stats_reply(
mid_t mod_id,
const Protocol__FlexranMessage *msg);
int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg);
/* Function to be used to handle reply message . */
......
......@@ -107,36 +107,6 @@ typedef uint8_t lcid_t;
typedef int32_t err_code_t;
/*---------Timer Enums --------- */
typedef enum {
/* oneshot timer: */
FLEXRAN_AGENT_TIMER_TYPE_ONESHOT = 0,
/* periodic timer */
FLEXRAN_AGENT_TIMER_TYPE_PERIODIC = 1,
/* Inactive state: initial state for any timer. */
FLEXRAN_AGENT_TIMER_TYPE_EVENT_DRIVEN = 2,
/* Max number of states available */
FLEXRAN_AGENT_TIMER_TYPE_MAX,
} flexran_agent_timer_type_t;
typedef enum {
/* Inactive state: initial state for any timer. */
FLEXRAN_AGENT_TIMER_STATE_INACTIVE = 0x0,
/* Inactive state: initial state for any timer. */
FLEXRAN_AGENT_TIMER_STATE_ACTIVE = 0x1,
/* Inactive state: initial state for any timer. */
FLEXRAN_AGENT_TIMER_STATE_STOPPED = 0x2,
/* Max number of states available */
FLEXRAN_AGENT_TIMER_STATE_MAX,
} flexran_agent_timer_state_t;
#define FLEXRAN_CAP_LOPHY(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOPHY)) > 0)
#define FLEXRAN_CAP_HIPHY(cApS) (((cApS) & (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY)) > 0)
......
......@@ -154,39 +154,20 @@ void * flexran_agent_pack_message(Protocol__FlexranMessage *msg,
return NULL;
}
Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args) {
Protocol__FlexranMessage *flexran_agent_handle_timed_task(
mid_t mod_id,
Protocol__FlexranMessage *msg) {
err_code_t err_code;
flexran_agent_timer_args_t *timer_args = (flexran_agent_timer_args_t *) args;
Protocol__FlexranMessage *timed_task, *reply_message;
timed_task = timer_args->msg;
err_code = ((*agent_messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message));
if ( err_code < 0 ){
goto error;
Protocol__FlexranMessage *reply_message;
err_code = ((*agent_messages_callback[msg->msg_case-1][msg->msg_dir-1])(
mod_id, msg, &reply_message));
if (err_code < 0) {
LOG_E(FLEXRAN_AGENT, "could not handle message: errno %d occured\n", err_code);
return NULL;
}
return reply_message;
error:
LOG_E(FLEXRAN_AGENT,"errno %d occured\n",err_code);
return NULL;
}
Protocol__FlexranMessage* flexran_agent_process_timeout(long timer_id, void* timer_args){
struct flexran_agent_timer_element_s *found = get_timer_entry(timer_id);
if (found == NULL ) goto error;
LOG_D(FLEXRAN_AGENT, "Found the entry (%p): timer_id is 0x%lx 0x%lx\n", found, timer_id, found->timer_id);
if (timer_args == NULL)
LOG_W(FLEXRAN_AGENT,"null timer args\n");
return found->cb(timer_args);
error:
LOG_E(FLEXRAN_AGENT, "can't get the timer element\n");
return NULL;
}
err_code_t flexran_agent_destroy_flexran_message(Protocol__FlexranMessage *msg) {
......@@ -209,24 +190,21 @@ int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr
return -1;
}
Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request;
flexran_agent_timer_args_t *timer_args = NULL;
switch (comp_req->report_frequency) {
case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF:
flexran_agent_destroy_timer_by_task_id(xid);
flexran_agent_destroy_timer(mod_id, xid);
return 0;
case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE:
LOG_E(FLEXRAN_AGENT, "one-shot timer not implemented yet\n");
return -1;
case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL:
/* Create a one off flexran message as an argument for the periodical task */
timer_args = calloc(1, sizeof(flexran_agent_timer_args_t));
AssertFatal(timer_args, "cannot allocate memory for timer\n");
timer_args->mod_id = mod_id;
timer_args->msg = input;
LOG_I(FLEXRAN_AGENT, "periodical timer xid %d cell_flags %d ue_flags %d\n",
xid, comp_req->cell_report_flags, comp_req->ue_report_flags);
flexran_agent_create_timer(mod_id, comp_req->sf,
FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid,
flexran_agent_send_stats_reply, timer_args);
flexran_agent_send_stats_reply, input);
/* return 1: do not dispose comp_req message we received, we still need it */
return 1;
case PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS:
......@@ -241,15 +219,14 @@ int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr
/*
Top level reply
*/
Protocol__FlexranMessage *flexran_agent_send_stats_reply(void *args) {
const flexran_agent_timer_args_t *timer_args = args;
const mid_t enb_id = timer_args->mod_id;
const Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)timer_args->msg;
const Protocol__FlexStatsRequest *stats_req = input->stats_request_msg;
Protocol__FlexranMessage *flexran_agent_send_stats_reply(
mid_t mod_id,
const Protocol__FlexranMessage *msg) {
const Protocol__FlexStatsRequest *stats_req = msg->stats_request_msg;
const xid_t xid = stats_req->header->xid;
Protocol__FlexranMessage *reply = NULL;
err_code_t rc = flexran_agent_stats_reply(enb_id, xid, stats_req, &reply);
err_code_t rc = flexran_agent_stats_reply(mod_id, xid, stats_req, &reply);
if (rc < 0) {
LOG_E(FLEXRAN_AGENT, "%s(): errno %d occured, cannot send stats_reply\n",
__func__, rc);
......
This diff is collapsed.
......@@ -26,100 +26,45 @@
* \version 0.1
*/
#include <stdio.h>
#include <time.h>
#ifndef _FLEXRAN_AGENT_TIMER_
#define _FLEXRAN_AGENT_TIMER_
#include "flexran_agent_common.h"
#include "flexran_agent_common_internal.h"
#include "flexran_agent_extern.h"
#include "flexran_agent_defs.h"
# include "tree.h"
# include "intertask_interface.h"
/*******************
* timer primitves
*******************/
#define TIMER_NULL -1
#define TIMER_TYPE_INVALIDE -2
#define TIMER_SETUP_FAILED -3
#define TIMER_REMOVED_FAILED -4
#define TIMER_ELEMENT_NOT_FOUND -5
typedef enum {
FLEXRAN_AGENT_TIMER_TYPE_ONESHOT,
FLEXRAN_AGENT_TIMER_TYPE_PERIODIC,
} flexran_agent_timer_type_t;
/* Type of the callback executed when the timer expired */
typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(void*);
typedef struct flexran_agent_timer_args_s{
mid_t mod_id;
Protocol__FlexranMessage *msg;
} flexran_agent_timer_args_t;
typedef struct flexran_agent_timer_element_s{
RB_ENTRY(flexran_agent_timer_element_s) entry;
agent_id_t agent_id;
instance_t instance;
flexran_agent_timer_type_t type;
flexran_agent_timer_state_t state;
typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(
mid_t mod_id, const Protocol__FlexranMessage *msg);
uint32_t interval_sec;
uint32_t interval_usec;
err_code_t flexran_agent_timer_init(mid_t mod_id);
void flexran_agent_timer_exit(mid_t mod_id);
long timer_id; /* Timer id returned by the timer API*/
xid_t xid; /*The id of the task as received by the controller
message*/
flexran_agent_timer_callback_t cb;
flexran_agent_timer_args_t *timer_args;
} flexran_agent_timer_element_t;
typedef struct flexran_agent_timer_instance_s{
RB_HEAD(flexran_agent_map, flexran_agent_timer_element_s) flexran_agent_head;
}flexran_agent_timer_instance_t;
err_code_t flexran_agent_init_timer(void);
/* Signals next subframe for FlexRAN timers */
void flexran_agent_timer_signal(mid_t mod_id);
/* Create a timer for some agent related event with id xid. */
err_code_t flexran_agent_create_timer(mid_t mod_id,
uint32_t sf,
uint32_t timer_type,
flexran_agent_timer_type_t timer_type,
xid_t xid,
flexran_agent_timer_callback_t cb,
void *timer_args);
Protocol__FlexranMessage *msg);
/* Destroy all existing timers */
err_code_t flexran_agent_destroy_timers(void);
/* Destroy the timer with the given timer_id */
err_code_t flexran_agent_destroy_timer(long timer_id);
err_code_t flexran_agent_destroy_timers(mid_t mod_id);
/* Destroy the timer for task with id xid */
err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid);
/* Stop a timer */
err_code_t flexran_agent_stop_timer(long timer_id);
/* Restart the given timer */
err_code_t flexran_agent_restart_timer(long *timer_id);
/* Find the timer with the given timer_id */
struct flexran_agent_timer_element_s * get_timer_entry(long timer_id);
/* Obtain the protocol message stored in the given expired timer */
Protocol__FlexranMessage * flexran_agent_process_timeout(long timer_id, void* timer_args);
/* Comparator function comparing two timers. Decides the ordering of the timers */
int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b);
err_code_t flexran_agent_destroy_timer(mid_t mod_id, xid_t xid);
/* RB_PROTOTYPE is for .h files */
RB_PROTOTYPE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer);
#endif /* _FLEXRAN_AGENT_TIMER_ */
......@@ -988,6 +988,8 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP,
if (flexran_agent_get_mac_xface(module_idP) && subframeP == 9) {
flexran_agent_slice_update(module_idP);
}
if (flexran_agent_get_mac_xface(module_idP))
flexran_agent_get_mac_xface(module_idP)->flexran_agent_notify_tick(module_idP);
stop_meas(&(eNB->eNB_scheduler));
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_OUT);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment