aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2020-11-13 02:14:37 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2020-11-16 17:02:06 +0100
commitb1243ee432953623389ffb7269e82263463ccb7e (patch)
tree23d0069b4e38ef520c75cf33578af3493e3b97ac
parent1061dcceba05c91316b84519ff062d66fc54a022 (diff)
hodec 2: favor moving dyn TS
-rw-r--r--src/osmo-bsc/handover_decision_2.c161
-rw-r--r--tests/handover/handover_test.c9
2 files changed, 105 insertions, 65 deletions
diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c
index c818dbbde..68ead6730 100644
--- a/src/osmo-bsc/handover_decision_2.c
+++ b/src/osmo-bsc/handover_decision_2.c
@@ -1362,6 +1362,100 @@ static void on_measurement_report(struct gsm_meas_rep *mr)
}
}
+static void collect_candidates_on_ts(struct gsm_bts_trx_ts *ts, struct ho_candidate *clist, unsigned int *candidates,
+ int tchf_congestion, int tchh_congestion,
+ bool only_dyn_ts)
+{
+ int j;
+ struct gsm_lchan *lc;
+
+ if (!ts_is_usable(ts))
+ return;
+
+ switch (ts->pchan_on_init) {
+ case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_TCH_F_PDCH:
+ if (!only_dyn_ts)
+ return;
+ break;
+ default:
+ if (only_dyn_ts)
+ return;
+ break;
+ }
+
+ /* (Do not consider dynamic TS that are in PDCH mode) */
+ switch (ts->pchan_is) {
+ case GSM_PCHAN_TCH_F:
+ /* No need to collect TCH/F candidates if no TCH/F needs to be moved. */
+ if (tchf_congestion == 0)
+ return;
+
+ lc = &ts->lchan[0];
+ /* omit if channel not active */
+ if (lc->type != GSM_LCHAN_TCH_F
+ || !lchan_state_is(lc, LCHAN_ST_ESTABLISHED))
+ break;
+ /* omit if there is an ongoing ho/as */
+ if (!lc->conn || lc->conn->assignment.new_lchan
+ || lc->conn->ho.fi)
+ break;
+ /* We desperately want to resolve congestion, ignore rxlev when
+ * collecting candidates by passing include_weaker_rxlev=true. */
+ collect_candidates_for_lchan(lc, clist, candidates, NULL, true);
+ break;
+
+ case GSM_PCHAN_TCH_H:
+ /* No need to collect TCH/H candidates if no TCH/H needs to be moved. */
+ if (tchh_congestion == 0)
+ return;
+
+ for (j = 0; j < 2; j++) {
+ lc = &ts->lchan[j];
+ /* omit if channel not active */
+ if (lc->type != GSM_LCHAN_TCH_H
+ || !lchan_state_is(lc, LCHAN_ST_ESTABLISHED))
+ return;
+ /* omit of there is an ongoing ho/as */
+ if (!lc->conn
+ || lc->conn->assignment.new_lchan
+ || lc->conn->ho.fi)
+ return;
+ /* We desperately want to resolve congestion, ignore rxlev when
+ * collecting candidates by passing include_weaker_rxlev=true. */
+ collect_candidates_for_lchan(lc, clist, candidates, NULL, true);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* loop through all active lchan and collect candidates */
+static void collect_candidates_on_bts(struct gsm_bts *bts, struct ho_candidate *clist, unsigned int *candidates,
+ int tchf_congestion, int tchh_congestion,
+ bool only_dyn_ts)
+{
+ struct gsm_bts_trx *trx;
+ int i;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (!trx_is_usable(trx))
+ continue;
+
+ if (only_dyn_ts) {
+ /* iterate dyn TS in reverse, to favor moving "later" timeslots */
+ for (i = 7; i >= 0; i--)
+ collect_candidates_on_ts(&trx->ts[i], clist, candidates, tchf_congestion,
+ tchh_congestion, only_dyn_ts);
+ } else {
+ for (i = 0; i < 8; i++)
+ collect_candidates_on_ts(&trx->ts[i], clist, candidates, tchf_congestion,
+ tchh_congestion, only_dyn_ts);
+ }
+ }
+}
+
/*
* Handover/assignment check after timer timeout:
*
@@ -1413,10 +1507,7 @@ static void on_measurement_report(struct gsm_meas_rep *mr)
*/
static int bts_resolve_congestion(struct gsm_bts *bts, int tchf_congestion, int tchh_congestion)
{
- struct gsm_lchan *lc;
- struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- int i, j;
+ int i;
struct ho_candidate *clist;
unsigned int candidates;
struct ho_candidate *best_cand = NULL, *worst_cand = NULL;
@@ -1437,68 +1528,18 @@ static int bts_resolve_congestion(struct gsm_bts *bts, int tchf_congestion, int
/* allocate array of all bts */
clist = talloc_zero_array(tall_bsc_ctx, struct ho_candidate,
- bts->num_trx * 8 * 2 * (1 + ARRAY_SIZE(lc->neigh_meas)));
+ bts->num_trx * 8 * 2 * (1 + ARRAY_SIZE(((struct gsm_lchan*)0)->neigh_meas)));
if (!clist)
return 0;
candidates = 0;
- /* loop through all active lchan and collect candidates */
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (!trx_is_usable(trx))
- continue;
-
- for (i = 0; i < 8; i++) {
- ts = &trx->ts[i];
- if (!ts_is_usable(ts))
- continue;
+ /* First collect candidates for dyn TS, to favor freeing PDCH. This specifically makes a difference when
+ * rxlev for a target cell are equal, particularly when considering re-assignment within the same cell. */
+ collect_candidates_on_bts(bts, clist, &candidates, tchf_congestion, tchh_congestion, true);
- /* (Do not consider dynamic TS that are in PDCH mode) */
- switch (ts->pchan_is) {
- case GSM_PCHAN_TCH_F:
- /* No need to collect TCH/F candidates if no TCH/F needs to be moved. */
- if (tchf_congestion == 0)
- continue;
-
- lc = &ts->lchan[0];
- /* omit if channel not active */
- if (lc->type != GSM_LCHAN_TCH_F
- || !lchan_state_is(lc, LCHAN_ST_ESTABLISHED))
- break;
- /* omit if there is an ongoing ho/as */
- if (!lc->conn || lc->conn->assignment.new_lchan
- || lc->conn->ho.fi)
- break;
- /* We desperately want to resolve congestion, ignore rxlev when
- * collecting candidates by passing include_weaker_rxlev=true. */
- collect_candidates_for_lchan(lc, clist, &candidates, NULL, true);
- break;
- case GSM_PCHAN_TCH_H:
- /* No need to collect TCH/H candidates if no TCH/H needs to be moved. */
- if (tchh_congestion == 0)
- continue;
-
- for (j = 0; j < 2; j++) {
- lc = &ts->lchan[j];
- /* omit if channel not active */
- if (lc->type != GSM_LCHAN_TCH_H
- || !lchan_state_is(lc, LCHAN_ST_ESTABLISHED))
- continue;
- /* omit of there is an ongoing ho/as */
- if (!lc->conn
- || lc->conn->assignment.new_lchan
- || lc->conn->ho.fi)
- continue;
- /* We desperately want to resolve congestion, ignore rxlev when
- * collecting candidates by passing include_weaker_rxlev=true. */
- collect_candidates_for_lchan(lc, clist, &candidates, NULL, true);
- }
- break;
- default:
- break;
- }
- }
- }
+ /* Then collect candidates for non-dyn TS */
+ collect_candidates_on_bts(bts, clist, &candidates, tchf_congestion, tchh_congestion, false);
if (!candidates) {
LOGPHOBTS(bts, LOGL_DEBUG, "No neighbor cells qualify to solve congestion\n");
diff --git a/tests/handover/handover_test.c b/tests/handover/handover_test.c
index bd7004ffe..7d217599b 100644
--- a/tests/handover/handover_test.c
+++ b/tests/handover/handover_test.c
@@ -1584,16 +1584,15 @@ static char *test_case_30[] = {
"congestion-check",
"expect-chan", "0", "6",
"ack-chan",
- /* Not so good: rather than moving static TCH/F, we should favor freeing dyn TS, for more PDCH */
- "expect-ho", "0", "1",
+ "expect-ho", "0", "5",
"ho-complete",
- "expect-ts-use", "0", "0", "*", "-", "TCH/F", "TCH/F", "TCH/F", "TCH/F", "TCH/H-", "PDCH",
+ "expect-ts-use", "0", "0", "*", "TCH/F", "TCH/F", "TCH/F", "TCH/F", "PDCH", "TCH/H-", "PDCH",
"congestion-check",
"expect-chan", "0", "6",
"ack-chan",
- "expect-ho", "0", "2",
+ "expect-ho", "0", "4",
"ho-complete",
- "expect-ts-use", "0", "0", "*", "-", "-", "TCH/F", "TCH/F", "TCH/F", "TCH/HH", "PDCH",
+ "expect-ts-use", "0", "0", "*", "TCH/F", "TCH/F", "TCH/F", "PDCH", "PDCH", "TCH/HH", "PDCH",
"congestion-check",
"expect-no-chan",
NULL