From 70b96aa232bd9784a94247bf7b193cb2147ada9d Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 12 Jun 2015 10:52:34 +0200 Subject: [PATCH] ms: Reduce DL CS level if only a few LLC bytes are left If just a few bytes are left to send to the MS, it makes sense to reduce the coding scheme level to increase the throughput. This has been shown by Chen and Goodman in their paper "Theoretical Analysis of GPRS Throughput and Delay". See their throughput over C/I measurement graphs (figures 4 and 5 in the paper) for details. This commit implements a simplified CS downgrade feature for the downlink. The coding scheme will be downgraded if there are only a few octets are left to be send over the TBF (see the downgrade-threshold command below) and the NACK rate is not low (the CS will not get degraded on a high quality RF link). As an exception, CS-3 will be degraded to CS-1, since CS-2 does not improve the throughput in general when a few small packets are sent and the signal fades slowly (see Chen/Goodman). The following VTY command is added to the config-pcu node: - cs downgrade-threshold <1-10000> - cs no downgrade-threshold to set the threshold of the number of remaining bytes to be RLC/MAC encoded. The CS will only be reduced, if the number is below the threshold. The 'no' command disables this feature completely. The default value is 200 octets. Sponsored-by: On-Waves ehf --- src/bts.h | 1 + src/gprs_ms.cpp | 33 +++++++++++++++++++++++++++++++++ src/gprs_ms.h | 5 ----- src/pcu_main.cpp | 1 + src/pcu_vty.c | 34 ++++++++++++++++++++++++++++++++++ tests/ms/MsTest.cpp | 38 ++++++++++++++++++++++++++++++++++++++ tests/ms/MsTest.err | 2 ++ tests/ms/MsTest.ok | 2 ++ 8 files changed, 111 insertions(+), 5 deletions(-) diff --git a/src/bts.h b/src/bts.h index 0c5b47a0..2ed50307 100644 --- a/src/bts.h +++ b/src/bts.h @@ -149,6 +149,7 @@ struct gprs_rlcmac_bts { uint8_t cs_adj_upper_limit; uint8_t cs_adj_lower_limit; struct {int16_t low; int16_t high;} cs_lqual_ranges[4]; + uint16_t cs_downgrade_threshold; /* downgrade if less packets left (DL) */ /* TBF handling, make private or move into TBFController */ /* list of uplink TBFs */ diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp index b40e1eac..2cfedc3b 100644 --- a/src/gprs_ms.cpp +++ b/src/gprs_ms.cpp @@ -485,3 +485,36 @@ void GprsMs::update_l1_meas(const pcu_l1_meas *meas) } } } + +uint8_t GprsMs::current_cs_dl() const +{ + uint8_t cs = m_current_cs_dl; + size_t unencoded_octets; + + if (!m_bts) + return cs; + + unencoded_octets = m_llc_queue.octets(); + + /* If the DL TBF is active, add number of unencoded chunk octets */ + if (m_dl_tbf) + unencoded_octets = m_dl_tbf->m_llc.chunk_size(); + + /* There are many unencoded octets, don't reduce */ + if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold) + return cs; + + /* RF conditions are good, don't reduce */ + if (m_nack_rate_dl < m_bts->bts_data()->cs_adj_lower_limit) + return cs; + + /* The throughput would probably be better if the CS level was reduced */ + cs -= 1; + + /* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */ + if (cs == 2) + cs -= 1; + + return cs; +} + diff --git a/src/gprs_ms.h b/src/gprs_ms.h index 05387239..3d0195ce 100644 --- a/src/gprs_ms.h +++ b/src/gprs_ms.h @@ -170,11 +170,6 @@ inline uint8_t GprsMs::ms_class() const return m_ms_class; } -inline uint8_t GprsMs::current_cs_dl() const -{ - return m_current_cs_dl; -} - inline uint8_t GprsMs::current_cs_ul() const { return m_current_cs_ul; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 416e48f3..3efdd843 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -187,6 +187,7 @@ int main(int argc, char *argv[]) bts->cs_lqual_ranges[2].high = 13; bts->cs_lqual_ranges[3].low = 12; bts->cs_lqual_ranges[3].high = 256; + bts->cs_downgrade_threshold = 200; msgb_set_talloc_ctx(tall_pcu_ctx); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 8db025e6..05c4b7a1 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -90,6 +90,12 @@ static int config_write_pcu(struct vty *vty) else vty_out(vty, " no cs threshold%s", VTY_NEWLINE); + if (bts->cs_downgrade_threshold) + vty_out(vty, " cs downgrade-threshold %d%s", + bts->cs_downgrade_threshold, VTY_NEWLINE); + else + vty_out(vty, " no cs downgrade-threshold%s", VTY_NEWLINE); + vty_out(vty, " cs link-quality-ranges cs1 %d cs2 %d %d cs3 %d %d cs4 %d%s", bts->cs_lqual_ranges[0].high, bts->cs_lqual_ranges[1].low, @@ -609,6 +615,32 @@ DEFUN(cfg_pcu_no_cs_err_limits, return CMD_SUCCESS; } +#define CS_DOWNGRADE_STR "set threshold for data size based CS downgrade\n" +DEFUN(cfg_pcu_cs_downgrade_thrsh, + cfg_pcu_cs_downgrade_thrsh_cmd, + "cs downgrade-threshold <1-10000>", + CS_STR CS_DOWNGRADE_STR "downgrade if less octets left\n") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + bts->cs_downgrade_threshold = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_no_cs_downgrade_thrsh, + cfg_pcu_no_cs_downgrade_thrsh_cmd, + "no cs downgrade-threshold", + CS_STR CS_DOWNGRADE_STR) +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + bts->cs_downgrade_threshold = 0; + + return CMD_SUCCESS; +} + + DEFUN(cfg_pcu_cs_lqual_ranges, cfg_pcu_cs_lqual_ranges_cmd, "cs link-quality-ranges cs1 <0-35> cs2 <0-35> <0-35> cs3 <0-35> <0-35> cs4 <0-35>", @@ -729,6 +761,8 @@ int pcu_vty_init(const struct log_info *cat) install_element(PCU_NODE, &cfg_pcu_no_cs_max_cmd); install_element(PCU_NODE, &cfg_pcu_cs_err_limits_cmd); install_element(PCU_NODE, &cfg_pcu_no_cs_err_limits_cmd); + install_element(PCU_NODE, &cfg_pcu_cs_downgrade_thrsh_cmd); + install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_queue_lifetime_cmd); install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd); diff --git a/tests/ms/MsTest.cpp b/tests/ms/MsTest.cpp index 403de439..f2faefc3 100644 --- a/tests/ms/MsTest.cpp +++ b/tests/ms/MsTest.cpp @@ -24,6 +24,7 @@ #include "gprs_debug.h" #include "gprs_ms.h" #include "gprs_ms_storage.h" +#include "bts.h" extern "C" { #include "pcu_vty.h" @@ -468,6 +469,42 @@ static void test_ms_timeout() printf("=== end %s ===\n", __func__); } +static void test_ms_cs_selection() +{ + BTS the_bts; + gprs_rlcmac_bts *bts = the_bts.bts_data(); + uint32_t tlli = 0xffeeddbb; + + gprs_rlcmac_dl_tbf *dl_tbf; + GprsMs *ms; + + printf("=== start %s ===\n", __func__); + + bts->initial_cs_dl = 4; + bts->initial_cs_ul = 1; + bts->cs_downgrade_threshold = 0; + + ms = new GprsMs(&the_bts, tlli); + + OSMO_ASSERT(ms->is_idle()); + + dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf); + dl_tbf->direction = GPRS_RLCMAC_DL_TBF; + + dl_tbf->set_ms(ms); + OSMO_ASSERT(!ms->is_idle()); + + OSMO_ASSERT(ms->current_cs_dl() == 4); + + bts->cs_downgrade_threshold = 200; + + OSMO_ASSERT(ms->current_cs_dl() == 3); + + talloc_free(dl_tbf); + + printf("=== end %s ===\n", __func__); +} + static const struct log_info_cat default_categories[] = { {"DPCU", "", "GPRS Packet Control Unit (PCU)", LOGL_INFO, 1}, }; @@ -507,6 +544,7 @@ int main(int argc, char **argv) test_ms_change_tlli(); test_ms_storage(); test_ms_timeout(); + test_ms_cs_selection(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); diff --git a/tests/ms/MsTest.err b/tests/ms/MsTest.err index 9e9df557..ed53f482 100644 --- a/tests/ms/MsTest.err +++ b/tests/ms/MsTest.err @@ -54,3 +54,5 @@ Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) Timeout for MS object, TLLI = 0xffeeddbb Destroying MS object, TLLI = 0xffeeddbb +Creating MS object, TLLI = 0xffeeddbb +Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0xffeeddbb DIR=DL STATE=NULL) diff --git a/tests/ms/MsTest.ok b/tests/ms/MsTest.ok index c49e840a..f14cceb6 100644 --- a/tests/ms/MsTest.ok +++ b/tests/ms/MsTest.ok @@ -16,3 +16,5 @@ ms_active() was called ms_idle() was called === end test_ms_timeout === +=== start test_ms_cs_selection === +=== end test_ms_cs_selection ===