From 0dcbc076823fc23b3212df600903de0493a7cc8d Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Wed, 10 Nov 2021 19:09:10 +0100 Subject: [PATCH] bts: Add counter availablePDCHAllocatedTime We basically want to probe whether it's possible to allocate TBFs, or whether we know it will fail due to all main resources being already in use (TFI, USF). Having bts_all_pdch_allocated() return false doesn't mean though that an MS will be able to allocate a TBF for sure. That's because further restrictions are applied based on MS: whether it was already attached to a specific TRX, whether the ms_class allows for a certain multislot combination, etc. However, it should provide a general idea on whether for sure the PCU is unable to provide more allocations. More fine grained state about failures can still be followed by looking at tbf:alloc:failed:* rate counters. Related: SYS#4878 Depends: Iabb17a08e6e1a86f168cdb008fba05ecd4776bdd (libosmocore) Change-Id: Ie0f0c451558817bddc3fe1a0f0df531f14c9f1d3 --- src/bts.cpp | 44 +++++++++++++++++++++++++++++++++++++++ src/bts.h | 5 +++++ src/gprs_pcu.c | 16 ++++++++++++++ src/gprs_pcu.h | 3 +++ src/pdch.cpp | 10 +++++++++ src/pdch.h | 1 + tests/alloc/AllocTest.cpp | 4 ++++ 7 files changed, 83 insertions(+) diff --git a/src/bts.cpp b/src/bts.cpp index 6fabc90c..05a9cc04 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -83,6 +83,20 @@ static struct osmo_tdef T_defs_bts[] = { { .T=3191, .default_val=5, .unit=OSMO_TDEF_S, .desc="Reuse of TFI(s) after sending (1) last RLC Data Block on TBF(s), or (2) PACKET TBF RELEASE for an MBMS radio bearer", .val=0 }, { .T=3193, .default_val=100, .unit=OSMO_TDEF_MS, .desc="Reuse of TFI(s) after reception of final PACKET DOWNLINK ACK/NACK from MS for TBF", .val=0 }, { .T=3195, .default_val=5, .unit=OSMO_TDEF_S, .desc="Reuse of TFI(s) upon no response from the MS (radio failure or cell change) for TBF/MBMS radio bearer", .val=0 }, + { .T = -16, .default_val = 1000, .unit = OSMO_TDEF_MS, + .desc = "Granularity for *:all_allocated rate counters: amount of milliseconds that one counter increment" + " represents. See also X17, X18" }, + { .T = -17, .default_val = 0, .unit = OSMO_TDEF_MS, + .desc = "Rounding threshold for *:all_allocated rate counters: round up to the next counter increment" + " after this many milliseconds. If set to half of X16 (or 0), employ the usual round() behavior:" + " round up after half of a granularity period. If set to 1, behave like ceil(): already" + " increment the counter immediately when all channels are allocated. If set >= X16, behave like" + " floor(): only increment after a full X16 period of all channels being occupied." + " See also X16, X18" }, + { .T = -18, .default_val = 60000, .unit = OSMO_TDEF_MS, + .desc = "Forget-sum period for *:all_allocated rate counters:" + " after this amount of idle time, forget internally cumulated time remainders. Zero to always" + " keep remainders. See also X16, X17." }, { .T=0, .default_val=0, .unit=OSMO_TDEF_S, .desc=NULL, .val=0 } /* empty item at the end */ }; @@ -92,6 +106,7 @@ static struct osmo_tdef T_defs_bts[] = { * the code below. */ static const struct rate_ctr_desc bts_ctr_description[] = { + { "pdch:all_allocated", "Cumulative counter of seconds where all enabled PDCH resources were allocated"}, { "tbf:dl:alloc", "TBF DL Allocated "}, { "tbf:dl:freed", "TBF DL Freed "}, { "tbf:dl:aborted", "TBF DL Aborted "}, @@ -231,6 +246,8 @@ static int bts_talloc_destructor(struct gprs_rlcmac_bts* bts) bts->ms_store->cleanup(); delete bts->ms_store; + osmo_time_cc_cleanup(&bts->all_allocated_pdch); + if (bts->ratectrs) { rate_ctr_group_free(bts->ratectrs); bts->ratectrs = NULL; @@ -300,6 +317,16 @@ struct gprs_rlcmac_bts* bts_alloc(struct gprs_pcu *pcu, uint8_t bts_nr) bts->statg = osmo_stat_item_group_alloc(tall_pcu_ctx, &bts_statg_desc, 0); OSMO_ASSERT(bts->statg); + osmo_time_cc_init(&bts->all_allocated_pdch); + struct osmo_time_cc_cfg *cc_cfg = &bts->all_allocated_pdch.cfg; + cc_cfg->gran_usec = 1*1000000, + cc_cfg->forget_sum_usec = 60*1000000, + cc_cfg->rate_ctr = rate_ctr_group_get_ctr(bts->ratectrs, CTR_PDCH_ALL_ALLOCATED), + cc_cfg->T_gran = -16, + cc_cfg->T_round_threshold = -17, + cc_cfg->T_forget_sum = -18, + cc_cfg->T_defs = T_defs_bts, + llist_add_tail(&bts->list, &pcu->bts_list); INIT_LLIST_HEAD(&bts->pch_timer); @@ -1371,3 +1398,20 @@ uint8_t bts_get_ms_pwr_alpha(const struct gprs_rlcmac_bts *bts) * B.2 Closed loop control */ return 0; } + +/* Used by counter availablePDCHAllocatedTime, TS 52.402 B.2.1.45 "All available PDCH allocated time" */ +bool bts_all_pdch_allocated(const struct gprs_rlcmac_bts *bts) +{ + unsigned trx_no, ts_no; + for (trx_no = 0; trx_no < ARRAY_SIZE(bts->trx); trx_no++) { + const struct gprs_rlcmac_trx *trx = &bts->trx[trx_no]; + for (ts_no = 0; ts_no < ARRAY_SIZE(trx->pdch); ts_no++) { + const struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts_no]; + if (!pdch_is_enabled(pdch)) + continue; + if(!pdch_is_full(pdch)) + return false; + } + } + return true; +} diff --git a/src/bts.h b/src/bts.h index f947a558..6bf62c73 100644 --- a/src/bts.h +++ b/src/bts.h @@ -32,6 +32,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -84,6 +85,7 @@ void bts_update_tbf_ta(struct gprs_rlcmac_bts *bts, const char *p, uint32_t fn, enum { + CTR_PDCH_ALL_ALLOCATED, CTR_TBF_DL_ALLOCATED, CTR_TBF_DL_FREED, CTR_TBF_DL_ABORTED, @@ -278,6 +280,8 @@ struct gprs_rlcmac_bts { /* List of struct bts_pch_timer for active PCH pagings */ struct llist_head pch_timer; + + struct osmo_time_cc all_allocated_pdch; }; #ifdef __cplusplus @@ -381,6 +385,7 @@ void bts_set_max_mcs_ul(struct gprs_rlcmac_bts *bts, uint8_t mcs_ul); bool bts_cs_dl_is_supported(const struct gprs_rlcmac_bts *bts, enum CodingScheme cs); const struct llist_head* bts_ms_list(struct gprs_rlcmac_bts *bts); uint8_t bts_get_ms_pwr_alpha(const struct gprs_rlcmac_bts *bts); +bool bts_all_pdch_allocated(const struct gprs_rlcmac_bts *bts); #ifdef __cplusplus } #endif diff --git a/src/gprs_pcu.c b/src/gprs_pcu.c index 5ed9d7d6..8b8e46b1 100644 --- a/src/gprs_pcu.c +++ b/src/gprs_pcu.c @@ -47,8 +47,21 @@ static struct osmo_tdef T_defs_pcu[] = { { .T=0, .default_val=0, .unit=OSMO_TDEF_S, .desc=NULL, .val=0 } /* empty item at the end */ }; +static void _update_stats_timer_cb(void *data) +{ + struct gprs_pcu *pcu = (struct gprs_pcu *)data; + struct gprs_rlcmac_bts *bts; + + llist_for_each_entry(bts, &pcu->bts_list, list) + osmo_time_cc_set_flag(&bts->all_allocated_pdch, bts_all_pdch_allocated(bts)); + + osmo_timer_schedule(&pcu->update_stats_timer, 1, 0); +} + static int gprs_pcu_talloc_destructor(struct gprs_pcu *pcu) { + if (osmo_timer_pending(&pcu->update_stats_timer)) + osmo_timer_del(&pcu->update_stats_timer); neigh_cache_free(pcu->neigh_cache); si_cache_free(pcu->si_cache); return 0; @@ -125,6 +138,9 @@ struct gprs_pcu *gprs_pcu_alloc(void *ctx) pcu->neigh_cache = neigh_cache_alloc(pcu, osmo_tdef_get(pcu->T_defs, PCU_TDEF_NEIGH_CACHE_ALIVE, OSMO_TDEF_S, -1)); pcu->si_cache = si_cache_alloc(pcu, osmo_tdef_get(pcu->T_defs, PCU_TDEF_SI_CACHE_ALIVE, OSMO_TDEF_S, -1)); + osmo_timer_setup(&pcu->update_stats_timer, _update_stats_timer_cb, pcu); + osmo_timer_schedule(&pcu->update_stats_timer, 1, 0); + return pcu; } diff --git a/src/gprs_pcu.h b/src/gprs_pcu.h index ed002213..a9e40ea6 100644 --- a/src/gprs_pcu.h +++ b/src/gprs_pcu.h @@ -25,6 +25,7 @@ #include #include +#include #include "gprs_bssgp_pcu.h" #include "coding_scheme.h" @@ -131,6 +132,8 @@ struct gprs_pcu { struct neigh_cache *neigh_cache; /* ARFC+BSIC -> CGI PS cache */ struct si_cache *si_cache; /* ARFC+BSIC -> CGI PS cache */ + + struct osmo_timer_list update_stats_timer; /* Used to update some time_cc stats periodically */ }; diff --git a/src/pdch.cpp b/src/pdch.cpp index a942b012..a5eb0804 100644 --- a/src/pdch.cpp +++ b/src/pdch.cpp @@ -1286,3 +1286,13 @@ bool pdch_is_enabled(const struct gprs_rlcmac_pdch *pdch) { return pdch->is_enabled(); } + +/* To be called only on enabled PDCHs. Used to gather information on whether the + * PDCH is currently unable to allocate more TBFs due to any resource being + * full. Used by bts_all_pdch_allocated() for counting purposes. */ +bool pdch_is_full(const struct gprs_rlcmac_pdch *pdch) +{ + return pdch->assigned_tfi(GPRS_RLCMAC_UL_TBF) == NO_FREE_TFI || + pdch->assigned_tfi(GPRS_RLCMAC_DL_TBF) == NO_FREE_TFI || + find_free_usf(pdch->assigned_usf()) < 0; +} diff --git a/src/pdch.h b/src/pdch.h index 94056069..759d7f97 100644 --- a/src/pdch.h +++ b/src/pdch.h @@ -194,6 +194,7 @@ void pdch_init(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_trx *trx, uint8 void pdch_free_all_tbf(struct gprs_rlcmac_pdch *pdch); void pdch_disable(struct gprs_rlcmac_pdch *pdch); bool pdch_is_enabled(const struct gprs_rlcmac_pdch *pdch); +bool pdch_is_full(const struct gprs_rlcmac_pdch *pdch); #ifdef __cplusplus } #endif diff --git a/tests/alloc/AllocTest.cpp b/tests/alloc/AllocTest.cpp index 1f2bbdae..6f3de43d 100644 --- a/tests/alloc/AllocTest.cpp +++ b/tests/alloc/AllocTest.cpp @@ -152,6 +152,8 @@ static void test_alloc_a(gprs_rlcmac_tbf_direction dir, OSMO_ASSERT(i == count); + OSMO_ASSERT(bts_all_pdch_allocated(bts)); + for (i = 0; i < count; ++i) if (tbfs[i]) tbf_free(tbfs[i]); @@ -479,6 +481,7 @@ static GprsMs *alloc_tbfs(struct gprs_rlcmac_bts *bts, struct GprsMs *old_ms, en tbf_free(ms_ul_tbf(old_ms)); tbf = tbf_alloc_ul_tbf(bts, old_ms, trx_no, false); if (tbf == NULL) { + OSMO_ASSERT(trx_no != -1 || bts_all_pdch_allocated(bts)); ms_unref(old_ms); return NULL; } @@ -490,6 +493,7 @@ static GprsMs *alloc_tbfs(struct gprs_rlcmac_bts *bts, struct GprsMs *old_ms, en tbf_free(ms_dl_tbf(old_ms)); tbf = tbf_alloc_dl_tbf(bts, old_ms, trx_no, false); if (tbf == NULL) { + OSMO_ASSERT(trx_no != -1 || bts_all_pdch_allocated(bts)); ms_unref(old_ms); return NULL; }