aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-05-06 14:24:36 +0200
committerJacob Erlbeck <jerlbeck@sysmocom.de>2015-05-06 15:22:57 +0200
commit6e4ccec6c4b69681e94e4d3b27ef022e4aab81a9 (patch)
treedbfbcea95d3551f141406ae576545a36aa7629d9
parent0288cdb0a8d4011905da55a5b74319e38e27e70d (diff)
bssgp: Compute and transmit queue delay
The specification 28.018, allows to transmit the average LLC downlink queueing delay in FLOW CONTROL BVC messages (BVC Measurement IE, see GSM 28.018, 10.4.4 and 11.3.7). This commit extends gprs_bssgp_pcu.cpp to compute the average delay time between two subsequent FLOW CONTROL BVC messages. The average is implemented as an arithmetic average without any weighting. Ticket: OW#1432 Sponsored-by: On-Waves ehf
-rw-r--r--src/gprs_bssgp_pcu.cpp41
-rw-r--r--src/gprs_bssgp_pcu.h7
-rw-r--r--src/tbf_dl.cpp16
3 files changed, 54 insertions, 10 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index bb6f7c53..b0e17f0d 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -553,6 +553,23 @@ static uint32_t compute_bucket_size(struct gprs_rlcmac_bts *bts,
return bucket_size;
}
+static uint32_t get_and_reset_avg_queue_delay(void)
+{
+ struct timeval *delay_sum = &the_pcu.queue_delay_sum;
+ uint64_t delay_sum_ms = delay_sum->tv_sec * 1000 +
+ delay_sum->tv_usec / 1000000;
+ uint32_t avg_delay_ms = 0;
+
+ if (the_pcu.queue_delay_count > 0)
+ avg_delay_ms = delay_sum_ms / the_pcu.queue_delay_count;
+
+ /* Reset accumulator */
+ delay_sum->tv_sec = delay_sum->tv_usec = 0;
+ the_pcu.queue_delay_count = 0;
+
+ return avg_delay_ms;
+}
+
int gprs_bssgp_tx_fc_bvc(void)
{
struct gprs_rlcmac_bts *bts;
@@ -560,6 +577,7 @@ int gprs_bssgp_tx_fc_bvc(void)
uint32_t ms_bucket_size; /* oct */
uint32_t leak_rate; /* oct/s */
uint32_t ms_leak_rate; /* oct/s */
+ uint32_t avg_delay_ms;
int num_pdch = -1;
if (!the_pcu.bctx) {
@@ -621,16 +639,19 @@ int gprs_bssgp_tx_fc_bvc(void)
if (ms_leak_rate > FC_MAX_BUCKET_LEAK_RATE)
ms_leak_rate = FC_MAX_BUCKET_LEAK_RATE;
- /* TODO: Implement avg queue delay monitoring */
+ /* Avg queue delay monitoring */
+ avg_delay_ms = get_and_reset_avg_queue_delay();
LOGP(DBSSGP, LOGL_DEBUG,
- "Sending FLOW CONTROL BVC, Bmax = %d, R = %d, Bmax_MS = %d, R_MS = %d\n",
- bucket_size, leak_rate, ms_bucket_size, ms_leak_rate);
+ "Sending FLOW CONTROL BVC, Bmax = %d, R = %d, Bmax_MS = %d, "
+ "R_MS = %d, avg_dly = %d\n",
+ bucket_size, leak_rate, ms_bucket_size, ms_leak_rate,
+ avg_delay_ms);
return bssgp_tx_fc_bvc(the_pcu.bctx, 1,
bucket_size, leak_rate,
ms_bucket_size, ms_leak_rate,
- NULL, NULL);
+ NULL, &avg_delay_ms);
}
static void bvc_timeout(void *_priv)
@@ -763,3 +784,15 @@ struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void)
{
return the_pcu.bctx;
}
+
+void gprs_bssgp_update_queue_delay(struct timeval *tv_recv,
+ struct timeval *tv_now)
+{
+ struct timeval *delay_sum = &the_pcu.queue_delay_sum;
+ struct timeval tv_delay;
+
+ timersub(tv_now, tv_recv, &tv_delay);
+ timeradd(delay_sum, &tv_delay, delay_sum);
+
+ the_pcu.queue_delay_count += 1;
+}
diff --git a/src/gprs_bssgp_pcu.h b/src/gprs_bssgp_pcu.h
index 32b6728d..aaaff7f9 100644
--- a/src/gprs_bssgp_pcu.h
+++ b/src/gprs_bssgp_pcu.h
@@ -58,6 +58,10 @@ struct gprs_bssgp_pcu {
int bvc_reset;
int bvc_unblocked;
+ /* Flow control */
+ struct timeval queue_delay_sum;
+ unsigned queue_delay_count;
+
/** callbacks below */
/* The BSSGP has been unblocked */
@@ -78,4 +82,7 @@ void gprs_bssgp_destroy(void);
struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void);
+void gprs_bssgp_update_queue_delay(struct timeval *tv_recv,
+ struct timeval *tv_now);
+
#endif // GPRS_BSSGP_PCU_H
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index 45c463c7..0aa22f90 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -242,7 +242,8 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
{
struct msgb *msg;
- struct timeval *tv, tv_now, tv_now2;
+ struct timeval *tv_recv, *tv_disc;
+ struct timeval tv_now, tv_now2;
uint32_t octets = 0, frames = 0;
struct timeval hyst_delta = {0, 0};
const unsigned keep_small_thresh = 60;
@@ -254,16 +255,19 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
timeradd(&tv_now, &hyst_delta, &tv_now2);
while ((msg = m_llc.dequeue())) {
- tv = (struct timeval *)msg->data;
- msgb_pull(msg, sizeof(*tv));
- msgb_pull(msg, sizeof(*tv));
+ tv_disc = (struct timeval *)msg->data;
+ msgb_pull(msg, sizeof(*tv_disc));
+ tv_recv = (struct timeval *)msg->data;
+ msgb_pull(msg, sizeof(*tv_recv));
+
+ gprs_bssgp_update_queue_delay(tv_recv, &tv_now);
/* Is the age below the low water mark? */
- if (!gprs_llc::is_frame_expired(&tv_now2, tv))
+ if (!gprs_llc::is_frame_expired(&tv_now2, tv_disc))
break;
/* Is the age below the high water mark */
- if (!gprs_llc::is_frame_expired(&tv_now, tv)) {
+ if (!gprs_llc::is_frame_expired(&tv_now, tv_disc)) {
/* Has the previous message not been dropped? */
if (frames == 0)
break;