mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-10 17:41:54 +00:00
This CL provides the tool to calculate statistics for sweetberry readings and present them in a clear & easy to read format. It also provides the flag to store raw data and statistics summary, should the need arise. There are also some code cleanup for powerlog.py. BRANCH=None BUG=b:35578707 TEST=./powerlog.py -b xxx.board -c xxx.scenario --print_stats \ --save_stats --save_raw_data python -m unittest -v stats_manager_unittest Change-Id: I4aa732756fe6512f37acfcb59b11d950101887d7 Signed-off-by: Mengqi Guo <mqg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/667241 Reviewed-by: Nick Sanders <nsanders@chromium.org>
138 lines
4.2 KiB
Python
138 lines
4.2 KiB
Python
# Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""Calculates statistics for lists of data and pretty print them."""
|
|
|
|
from __future__ import print_function
|
|
import collections
|
|
import numpy
|
|
import os
|
|
|
|
STATS_PREFIX = '@@'
|
|
KEY_PREFIX = '__'
|
|
# This prefix is used for keys that should not be shown in the summary tab, such
|
|
# as timeline keys.
|
|
NOSHOW_PREFIX = '!!'
|
|
|
|
class StatsManager(object):
|
|
"""Calculates statistics for several lists of data(float)."""
|
|
|
|
def __init__(self):
|
|
"""Initialize infrastructure for data and their statistics."""
|
|
self._data = collections.defaultdict(list)
|
|
self._summary = {}
|
|
|
|
def AddValue(self, domain, value):
|
|
"""Add one value for a domain.
|
|
|
|
Args:
|
|
domain: the domain name for the value.
|
|
value: one time reading for domain, expect type float.
|
|
"""
|
|
if isinstance(value, int):
|
|
value = float(value)
|
|
if isinstance(value, float):
|
|
self._data[domain].append(value)
|
|
return
|
|
print('Warning: value %s for domain %s is not a number, thus ignored.' %
|
|
(value, domain))
|
|
|
|
def CalculateStats(self):
|
|
"""Calculate stats for all domain-data pairs.
|
|
|
|
First erases all previous stats, then calculate stats for all data.
|
|
"""
|
|
self._summary = {}
|
|
for domain, data in self._data.iteritems():
|
|
data_np = numpy.array(data)
|
|
self._summary[domain] = {
|
|
'mean' : data_np.mean(),
|
|
'min' : data_np.min(),
|
|
'max' : data_np.max(),
|
|
'stddev' : data_np.std(),
|
|
'count' : data_np.size,
|
|
}
|
|
|
|
def _SummaryToString(self, prefix=STATS_PREFIX):
|
|
"""Format summary into a string, ready for pretty print.
|
|
|
|
Args:
|
|
prefix: start every row in summary string with prefix, for easier reading.
|
|
"""
|
|
headers = ('NAME', 'COUNT', 'MEAN', 'STDDEV', 'MAX', 'MIN')
|
|
table = [headers]
|
|
for domain in sorted(self._summary.keys()):
|
|
if domain.startswith(NOSHOW_PREFIX):
|
|
continue
|
|
stats = self._summary[domain]
|
|
row = [domain.lstrip(KEY_PREFIX)]
|
|
row.append(str(stats['count']))
|
|
for entry in headers[2:]:
|
|
row.append('%.2f' % stats[entry.lower()])
|
|
table.append(row)
|
|
|
|
max_col_width = []
|
|
for col_idx in range(len(table[0])):
|
|
col_item_widths = [len(row[col_idx]) for row in table]
|
|
max_col_width.append(max(col_item_widths))
|
|
|
|
formatted_table = []
|
|
for row in table:
|
|
formatted_row = prefix + ' '
|
|
for i in range(len(row)):
|
|
formatted_row += row[i].rjust(max_col_width[i] + 2)
|
|
formatted_table.append(formatted_row)
|
|
return '\n'.join(formatted_table)
|
|
|
|
def PrintSummary(self, prefix=STATS_PREFIX):
|
|
"""Print the formatted summary.
|
|
|
|
Args:
|
|
prefix: start every row in summary string with prefix, for easier reading.
|
|
"""
|
|
summary_str = self._SummaryToString(prefix=prefix)
|
|
print(summary_str)
|
|
|
|
def GetSummary(self):
|
|
"""Getter for summary."""
|
|
return self._summary
|
|
|
|
def SaveSummary(self, directory, fname='summary.txt', prefix=STATS_PREFIX):
|
|
"""Save summary to file.
|
|
|
|
Args:
|
|
directory: directory to save the summary in.
|
|
fname: filename to save summary under.
|
|
prefix: start every row in summary string with prefix, for easier reading.
|
|
"""
|
|
summary_str = self._SummaryToString(prefix=prefix) + '\n'
|
|
|
|
if not os.path.exists(directory):
|
|
os.makedirs(directory)
|
|
fname = os.path.join(directory, fname)
|
|
with open(fname, 'w') as f:
|
|
f.write(summary_str)
|
|
|
|
def GetRawData(self):
|
|
"""Getter for all raw_data."""
|
|
return self._data
|
|
|
|
def SaveRawData(self, directory, dirname='raw_data'):
|
|
"""Save raw data to file.
|
|
|
|
Args:
|
|
directory: directory to create the raw data folder in.
|
|
dirname: folder in which raw data live.
|
|
"""
|
|
if not os.path.exists(directory):
|
|
os.makedirs(directory)
|
|
dirname = os.path.join(directory, dirname)
|
|
if not os.path.exists(dirname):
|
|
os.makedirs(dirname)
|
|
for domain, data in self._data.iteritems():
|
|
fname = domain + '.txt'
|
|
fname = os.path.join(dirname, fname)
|
|
with open(fname, 'w') as f:
|
|
f.write('\n'.join('%.2f' % value for value in data) + '\n')
|