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; }