<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bsc/+/22085">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">hodec2: to balance congestion, use overload percent<br><br>For balancing load across congested cells and across congested TCH/*<br>kinds, instead of comparing the number of lchans above the configured<br>congestion threshold, compare the percent of lchans of overload.<br><br>In short, using a percentage prevents cells with less min-free-slots to<br>fill up 100% while neighbor cells still may have several free lchans<br>available.<br><br>An obvious example of why this is desirable is illustrated by<br>test_balance_congestion_by_percentage.ho_vty:<br><br>Cell A has min-free-slots 2, and has all slots occupied.<br>Cell B has min-free-slots 4, and has 2 slots remaining free.<br><br>If we count congested lchans as in current master: cell A has a<br>congestion count of 2: two more lchans in use than "allowed". If we move<br>one lchan over to cell B, it ends up with a congestion count of 3, which<br>is worse than 2. So when counting lchans, we decide that cell A should<br>remain full.<br><br>Instead, when comparing percentage of remaining lchans, we would see<br>that cell A is loaded 100% above congestion (2 of 2 remaining lchans in<br>use), but when moving one lchan to cell B, that would only be 75% loaded<br>above its treshold (3 of 4 remaining lchans in use). So a percentage<br>comparison would cause a handover to cell B.<br><br>Change-Id: I55234c6c99eb02ceee52be0d7388bea14304930f<br>---<br>M src/osmo-bsc/handover_decision_2.c<br>M tests/handover/handover_tests.ok<br>M tests/handover/test_balance_congestion_by_percentage.ho_vty<br>M tests/handover/test_balance_congestion_tchf_tchh.ho_vty<br>4 files changed, 52 insertions(+), 19 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/85/22085/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c</span><br><span>index c265f5f..d29f762 100644</span><br><span>--- a/src/osmo-bsc/handover_decision_2.c</span><br><span>+++ b/src/osmo-bsc/handover_decision_2.c</span><br><span>@@ -25,6 +25,7 @@</span><br><span> #include <stdbool.h></span><br><span> #include <errno.h></span><br><span> #include <limits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <math.h></span><br><span> </span><br><span> #include <osmocom/bsc/debug.h></span><br><span> #include <osmocom/bsc/gsm_data.h></span><br><span>@@ -387,6 +388,27 @@</span><br><span>       return false;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define LOAD_PRECISION 6</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Return a number representing overload, i.e. the fraction of lchans used above the congestion threshold.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Think of it as a percentage of used lchans above congestion, just represented in a fixed-point fraction with N</span><br><span style="color: hsl(120, 100%, 40%);">+ * decimal digits of fractional part. If there is no congestion (free_tch > min_free_tch), return 0.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int32_t load_above_congestion(int free_tch, int min_free_tch)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int32_t v;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Avoid division by zero, and return zero overload when there is no congestion threshold. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!min_free_tch</span><br><span style="color: hsl(120, 100%, 40%);">+         || free_tch >= min_free_tch)</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* There can be no negative amount of free TCH/x, clamp to a minimum of zero available slots. This could</span><br><span style="color: hsl(120, 100%, 40%);">+       * theoretically happen when a caller subtracts one from free_tch to regard the slots after a handover. */</span><br><span style="color: hsl(120, 100%, 40%);">+    v = min_free_tch - OSMO_MAX(0, free_tch);</span><br><span style="color: hsl(120, 100%, 40%);">+     v *= pow(10, LOAD_PRECISION);</span><br><span style="color: hsl(120, 100%, 40%);">+ v /= min_free_tch;</span><br><span style="color: hsl(120, 100%, 40%);">+    return v;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*</span><br><span>  * Check what requirements the given cell fulfills.</span><br><span>  * A bit mask of fulfilled requirements is returned.</span><br><span>@@ -443,7 +465,7 @@</span><br><span> {</span><br><span>       uint8_t requirement = 0;</span><br><span>     unsigned int penalty_time;</span><br><span style="color: hsl(0, 100%, 40%);">-      int current_overbooked;</span><br><span style="color: hsl(120, 100%, 40%);">+       int32_t current_overbooked;</span><br><span>  c->requirements = 0;</span><br><span> </span><br><span>  /* Requirement A */</span><br><span>@@ -626,17 +648,25 @@</span><br><span> </span><br><span>      /* Requirement C */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* the nr of lchans surpassing congestion on the target cell must be <= the lchans surpassing congestion on the</span><br><span style="color: hsl(0, 100%, 40%);">-       * current cell _after_ handover/assignment */</span><br><span style="color: hsl(0, 100%, 40%);">-  current_overbooked = c->current.min_free_tch - c->current.free_tch;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* the load percentage above congestion on the target cell *after* HO must be < the load percentage above</span><br><span style="color: hsl(120, 100%, 40%);">+   * congestion on the current cell, hence the - 1 on the target. */</span><br><span style="color: hsl(120, 100%, 40%);">+    current_overbooked = load_above_congestion(c->current.free_tch, c->current.min_free_tch);</span><br><span>      if (requirement & REQUIREMENT_A_TCHF) {</span><br><span style="color: hsl(0, 100%, 40%);">-             int target_overbooked = c->target.min_free_tchf - c->target.free_tchf;</span><br><span style="color: hsl(0, 100%, 40%);">-            if (target_overbooked + 1 <= current_overbooked - 1)</span><br><span style="color: hsl(120, 100%, 40%);">+               int32_t target_overbooked = load_above_congestion(c->target.free_tchf - 1, c->target.min_free_tchf);</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGPHOLCHANTOBTS(c->current.lchan, c->target.bts, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "current overbooked = %s%%, TCH/F target overbooked after HO = %s%%\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             osmo_int_to_float_str_c(OTC_SELECT, current_overbooked, LOAD_PRECISION - 2),</span><br><span style="color: hsl(120, 100%, 40%);">+                          osmo_int_to_float_str_c(OTC_SELECT, target_overbooked, LOAD_PRECISION - 2));</span><br><span style="color: hsl(120, 100%, 40%);">+         if (target_overbooked < current_overbooked)</span><br><span>                       requirement |= REQUIREMENT_C_TCHF;</span><br><span>   }</span><br><span>    if (requirement & REQUIREMENT_A_TCHH) {</span><br><span style="color: hsl(0, 100%, 40%);">-             int target_overbooked = c->target.min_free_tchh - c->target.free_tchh;</span><br><span style="color: hsl(0, 100%, 40%);">-            if (target_overbooked + 1 <= current_overbooked - 1)</span><br><span style="color: hsl(120, 100%, 40%);">+               int32_t target_overbooked = load_above_congestion(c->target.free_tchh - 1, c->target.min_free_tchh);</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGPHOLCHANTOBTS(c->current.lchan, c->target.bts, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "current overbooked = %s%%, TCH/H target overbooked after HO = %s%%\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             osmo_int_to_float_str_c(OTC_SELECT, current_overbooked, LOAD_PRECISION - 2),</span><br><span style="color: hsl(120, 100%, 40%);">+                          osmo_int_to_float_str_c(OTC_SELECT, target_overbooked, LOAD_PRECISION - 2));</span><br><span style="color: hsl(120, 100%, 40%);">+         if (target_overbooked < current_overbooked)</span><br><span>                       requirement |= REQUIREMENT_C_TCHH;</span><br><span>   }</span><br><span> </span><br><span>diff --git a/tests/handover/handover_tests.ok b/tests/handover/handover_tests.ok</span><br><span>index 95442a3..d0c1c00 100644</span><br><span>--- a/tests/handover/handover_tests.ok</span><br><span>+++ b/tests/handover/handover_tests.ok</span><br><span>@@ -8,6 +8,7 @@</span><br><span> pass test_amr_tch_h_to_f_congestion_two_cells.ho_vty</span><br><span> pass test_balance_congestion.ho_vty</span><br><span> pass test_balance_congestion_2.ho_vty</span><br><span style="color: hsl(120, 100%, 40%);">+pass test_balance_congestion_by_percentage.ho_vty</span><br><span> pass test_balance_congestion_tchf_tchh.ho_vty</span><br><span> pass test_congestion.ho_vty</span><br><span> pass test_congestion_favor_best_target_rxlev.ho_vty</span><br><span>diff --git a/tests/handover/test_balance_congestion_by_percentage.ho_vty b/tests/handover/test_balance_congestion_by_percentage.ho_vty</span><br><span>index e00636e..0d8071d 100644</span><br><span>--- a/tests/handover/test_balance_congestion_by_percentage.ho_vty</span><br><span>+++ b/tests/handover/test_balance_congestion_by_percentage.ho_vty</span><br><span>@@ -31,4 +31,4 @@</span><br><span> </span><br><span> # bts 0 is full, but by counting lchans above congestion, it should remain full.</span><br><span> congestion-check</span><br><span style="color: hsl(0, 100%, 40%);">-expect-no-chan</span><br><span style="color: hsl(120, 100%, 40%);">+expect-ho from lchan 0 0 1 0 to lchan 1 0 5 0</span><br><span>diff --git a/tests/handover/test_balance_congestion_tchf_tchh.ho_vty b/tests/handover/test_balance_congestion_tchf_tchh.ho_vty</span><br><span>index 7f9039f..62f07bf 100644</span><br><span>--- a/tests/handover/test_balance_congestion_tchf_tchh.ho_vty</span><br><span>+++ b/tests/handover/test_balance_congestion_tchf_tchh.ho_vty</span><br><span>@@ -6,46 +6,48 @@</span><br><span> </span><br><span> create-bts trx-count 1 timeslots       c+s4    TCH/F   TCH/F   TCH/F   TCH/F   TCH/H   TCH/H   TCH/H</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-# both TCH/H and TCH/F have one lchan above congestion, nothing happens</span><br><span style="color: hsl(120, 100%, 40%);">+# both TCH/H and TCH/F have one lchan = 33% above congestion, nothing happens</span><br><span> set-ts-use trx 0 0 states            *       TCH/F   TCH/F   -       -       TCH/HH  TCH/HH  -</span><br><span> meas-rep lchan * * * * rxlev 10 rxqual 0 ta 0</span><br><span> congestion-check</span><br><span> expect-no-chan</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-# TCH/F = +1, TCH/H = +2 above congestion. Moving a TCH/H to TCH/F would just reverse the situation to F=+2 H=+1. Nothing happens.</span><br><span style="color: hsl(120, 100%, 40%);">+# TCH/F = +1 = 33%, TCH/H = +2 = 66% above congestion.</span><br><span style="color: hsl(120, 100%, 40%);">+# Moving a TCH/H to TCH/F would just reverse the situation to F=+2=66%. Nothing happens.</span><br><span> set-ts-use trx 0 0 states           *       TCH/F   TCH/F   -       -       TCH/HH  TCH/HH  TCH/H-</span><br><span> meas-rep lchan * * * * rxlev 10 rxqual 0 ta 0</span><br><span> congestion-check</span><br><span> expect-no-chan</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-# F=+1 H=+3. Balance to F=+2 H=+2</span><br><span style="color: hsl(120, 100%, 40%);">+# F=+1=33% H=+3=100%. Balance to F=+2=66% (which is < 100%) and H=+2=66%</span><br><span> set-ts-use trx 0 0 states            *       TCH/F   TCH/F   -       -       TCH/HH  TCH/HH  TCH/HH</span><br><span> meas-rep lchan * * * * rxlev 10 rxqual 0 ta 0</span><br><span> congestion-check</span><br><span> expect-ho from lchan 0 0 5 0 to lchan 0 0 3 0</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-# Now the exact same thing, just with different min-free-slots settings for</span><br><span style="color: hsl(0, 100%, 40%);">-# tch/f vs tch/h</span><br><span style="color: hsl(120, 100%, 40%);">+# Now similar load percentages, just with different min-free-slots settings for tch/f vs tch/h.</span><br><span> </span><br><span> network</span><br><span>  handover2 min-free-slots tch/f 3</span><br><span>  handover2 min-free-slots tch/h 5</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-# both TCH/H and TCH/F have one lchan above congestion, nothing happens</span><br><span style="color: hsl(120, 100%, 40%);">+# TCH/F has 1/3 = 33%, TCH/H has 1/5 = 20% overload.</span><br><span style="color: hsl(120, 100%, 40%);">+# Moving one to TCH/H would mean 40% overload on TCH/H, which is above the current TCH/F of 33%.</span><br><span style="color: hsl(120, 100%, 40%);">+# Nothing happens.</span><br><span> set-ts-use trx 0 0 states               *       TCH/F   TCH/F   -       -       TCH/HH  -       -</span><br><span> meas-rep lchan * * * * rxlev 20 rxqual 0 ta 0</span><br><span> congestion-check</span><br><span> expect-no-chan</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-# TCH/F = +1, TCH/H = +2 above congestion. Moving a TCH/H to TCH/F would just</span><br><span style="color: hsl(0, 100%, 40%);">-# reverse the situation to F=+2 H=+1. Nothing happens.</span><br><span style="color: hsl(120, 100%, 40%);">+# TCH/F = +1 = 33%, TCH/H = +2 = 40% above congestion. Moving a TCH/H to TCH/F would result</span><br><span style="color: hsl(120, 100%, 40%);">+# in F=+2=66%>40%. Nothing happens.</span><br><span> set-ts-use trx 0 0 states               *       TCH/F   TCH/F   -       -       TCH/HH  TCH/H-  -</span><br><span> meas-rep lchan * * * * rxlev 20 rxqual 0 ta 0</span><br><span> congestion-check</span><br><span> expect-no-chan</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-# F=+1 H=+3. Balance to F=+2 H=+2</span><br><span style="color: hsl(0, 100%, 40%);">-set-ts-use trx 0 0 states          *       TCH/F   TCH/F   -       -       TCH/HH  TCH/HH  -</span><br><span style="color: hsl(120, 100%, 40%);">+# F=+1=33% H=+4=80%. Balance to F=+2=66%<80% and H=+3=60%</span><br><span style="color: hsl(120, 100%, 40%);">+set-ts-use trx 0 0 states              *       TCH/F   TCH/F   -       -       TCH/HH  TCH/HH  TCH/H-</span><br><span> meas-rep lchan * * * * rxlev 20 rxqual 0 ta 0</span><br><span> congestion-check</span><br><span> expect-ho from lchan 0 0 5 0 to lchan 0 0 3 0</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bsc/+/22085">change 22085</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-bsc/+/22085"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I55234c6c99eb02ceee52be0d7388bea14304930f </div>
<div style="display:none"> Gerrit-Change-Number: 22085 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>