Commit 6fb3b11b authored by Paul Graydon's avatar Paul Graydon

amari.kpi: Add support for DRB.UEActive measurement

parent 3a35162b
...@@ -205,9 +205,9 @@ def _read(logm): ...@@ -205,9 +205,9 @@ def _read(logm):
# _handle_stats handles next stats xlog entry upon _read request. # _handle_stats handles next stats xlog entry upon _read request.
@func(LogMeasure) @func(LogMeasure)
def _handle_stats(logm, stats: xlog.Message, m_prev: kpi.Measurement): def _handle_stats(logm, stats: xlog.Message, m_prev: kpi.Measurement):
# build Measurement from stats' counters. # build Measurement from stats' statistical profiles and counters.
# #
# we take δ(stats_prev, stat) and process it mapping Amarisoft counters to # we take δ(stats_prev, stat) and process it, mapping Amarisoft counters to
# 3GPP ones specified by kpi.Measurement. This approach has following limitations: # 3GPP ones specified by kpi.Measurement. This approach has following limitations:
# #
# - for most of the counters there is no direct mapping in between # - for most of the counters there is no direct mapping in between
...@@ -260,6 +260,13 @@ def _handle_stats(logm, stats: xlog.Message, m_prev: kpi.Measurement): ...@@ -260,6 +260,13 @@ def _handle_stats(logm, stats: xlog.Message, m_prev: kpi.Measurement):
# do init/fini correction if there was also third preceding stats message. # do init/fini correction if there was also third preceding stats message.
m = logm._m.copy() # [stats_prev, stats) m = logm._m.copy() # [stats_prev, stats)
# cell_statt_profile returns the StatT statistical profile value triplet in stats
def cell_statt_profile(cell, statt_profile):
return tuple(
_stats_cell_sp_el(stats, cell, statt_profile + '_' + el)
for el in ['min', 'avg', 'max']
)
# δcc(counter) tells how specified global cumulative counter changed since last stats result. # δcc(counter) tells how specified global cumulative counter changed since last stats result.
def δcc(counter): def δcc(counter):
old = _stats_cc(stats_prev, counter) old = _stats_cc(stats_prev, counter)
...@@ -305,6 +312,30 @@ def _handle_stats(logm, stats: xlog.Message, m_prev: kpi.Measurement): ...@@ -305,6 +312,30 @@ def _handle_stats(logm, stats: xlog.Message, m_prev: kpi.Measurement):
# compute δ for counters. # compute δ for counters.
# any logic error in data will be reported via LogError. # any logic error in data will be reported via LogError.
try: try:
cells = set(stats['cells'].keys()) # NOTE cells are taken only from stats, not from stat_prev
# DRB: number of active UEs
#
# Aggregate statistical profile for all cells.
# While summing the averages is correct, it is impossible to compute
# an accurate value of the aggregate minimum and maximum across all cells.
# Summing them is the best approximation that will produce
# a wider interval containing the correct values, i.e.:
# Σ(minimums) <= min(Σ) and max(Σ) <= Σ(maximums)
# [ min, avg, max]
Σue_active_count = [None, None, None]
for cell in cells:
cell_ue_active_count = cell_statt_profile(cell, 'ue_active_count')
for i, el in enumerate(cell_ue_active_count):
if el is not None:
Σue_active_count[i] = Σue_active_count[i] or 0
Σue_active_count[i] += el
# any None here will map to kpi.NA
m['DRB.UEActive'] = kpi.StatT(*Σue_active_count)
# RRC: connection establishment # RRC: connection establishment
# #
# Aggregate statistics for all cells because in E-RAB Accessibility we need # Aggregate statistics for all cells because in E-RAB Accessibility we need
...@@ -315,7 +346,6 @@ def _handle_stats(logm, stats: xlog.Message, m_prev: kpi.Measurement): ...@@ -315,7 +346,6 @@ def _handle_stats(logm, stats: xlog.Message, m_prev: kpi.Measurement):
# same whether we do aggregation here or in kpi.Calc.erab_accessibility(). # same whether we do aggregation here or in kpi.Calc.erab_accessibility().
# #
# TODO rework to emit per-cell measurements when/if we need per-cell KPIs # TODO rework to emit per-cell measurements when/if we need per-cell KPIs
cells = set(stats['cells'].keys()) # NOTE cells are taken only from stats, not from stat_prev
δΣcell_rrc_connection_request = 0 # (if a cell disappears its counters stop to be accounted) δΣcell_rrc_connection_request = 0 # (if a cell disappears its counters stop to be accounted)
δΣcell_rrc_connection_setup_complete = 0 δΣcell_rrc_connection_setup_complete = 0
for cell in cells: for cell in cells:
...@@ -368,6 +398,15 @@ def _stats_check(stats: xlog.Message): ...@@ -368,6 +398,15 @@ def _stats_check(stats: xlog.Message):
raise LogError(stats.timestamp, "stats: %s" % e) from None raise LogError(stats.timestamp, "stats: %s" % e) from None
return return
# _stats_cell_sp_el returns specified per-cell element of a statistical profile.
#
# stats is assumed to be already verified by _stats_check.
def _stats_cell_sp_el(stats: xlog.Message, cell: str, stat_profile_el: str):
_ = stats['cells'].get(cell)
if _ is None:
return None # cell is absent in this stats
return _.get(stat_profile_el, None)
# _stats_cc returns specified global cumulative counter from stats result. # _stats_cc returns specified global cumulative counter from stats result.
# #
# stats is assumed to be already verified by _stats_check. # stats is assumed to be already verified by _stats_check.
...@@ -378,7 +417,7 @@ def _stats_cc(stats: xlog.Message, counter: str): ...@@ -378,7 +417,7 @@ def _stats_cc(stats: xlog.Message, counter: str):
def _stats_cell_cc(stats: xlog.Message, cell: str, counter: str): def _stats_cell_cc(stats: xlog.Message, cell: str, counter: str):
_ = stats['cells'].get(cell) _ = stats['cells'].get(cell)
if _ is None: if _ is None:
return 0 # cell is absent in this stats return 0 # cell is absent in this stats
return _['counters']['messages'].get(counter, 0) return _['counters']['messages'].get(counter, 0)
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment