project/analysis/analyzers/analyzer/locomotion.py

110 lines
3.3 KiB
Python

from analysis import util
from . import Analyzer, LogSettings, Result, ResultStore
log: logging.Logger = logging.getLogger(__name__)
ONE_DAY = 24 * 60 * 60 * 1000
MIN_DURATION = 5 * 60 * 1000
def init_filter(settings: LogSettings, state: str) -> callable:
# this implies OR for lists; AND for dicts
if type(settings.sequences[state]) in (str, list):
return lambda entry: entry[settings.type_field] in settings.sequences[state]
else:
return lambda entry: util.combinate(settings.sequences[state], entry)
class LocomotionActionAnalyzer(Analyzer):
"""
calculate locomotion/action times and ratio
Anything between LogEntryCache and CacheEnableAction
is counted as ActionTime, the rest as LocomotionTime.
"""
__name__ = "LocomotionAction"
limit = ONE_DAY
def process(self, entry: dict) -> bool:
self.last_timestamp = entry["timestamp"]
if self.instance_start is None:
self.instance_start = self.last_timestamp
self.last = self.last_timestamp
if self.cache_time is None:
self.cache_time = self.last_timestamp
offset = self.last_timestamp - self.cache_time
if self.current_cache is None and self.filter_start(entry):
if entry['cache'] is None:
return False
self.current_cache = entry['cache']['@id']
self.cache_time = self.last_timestamp
self.locomotion.append(offset)
self.last = None
elif self.current_cache and self.filter_end(entry):
self.actions.append(offset)
self.cache_time = self.last_timestamp
self.current_cache = None
self.last = None
def result(self, store: ResultStore) -> None:
if self.last is not None:
if self.current_cache is None:
self.locomotion.append(self.last - self.cache_time)
else:
self.actions.append(self.last - self.cache_time)
self.last = None
locomotion = sum(self.locomotion)
action = sum(self.actions)
if not action > 0:
action = 1
total = locomotion + action
if total > self.limit:
log.error("total duration over limit, skip")
elif total < MIN_DURATION:
log.error("total duration too short, skip")
elif action < MIN_DURATION:
log.error("action time too short, skip")
else:
store.add(Result(type(self), {
'locomotion_sum': locomotion/1000,
'action_sum': action/1000,
'locomotion': self.locomotion,
'action': self.actions,
'duration': (self.last_timestamp - self.instance_start)/1000,
'locomotion_relative': locomotion / total,
'action_relative': action / total,
'locomotion_action_ratio': locomotion / action,
}))
def __init__(self, settings: LogSettings):
super().__init__(settings)
self.filter_start = init_filter(settings, "start")
self.filter_end = init_filter(settings, "end")
self.current_cache = None
self.cache_time = None
self.locomotion = []
self.actions = []
self.instance_start = None
self.last_timestamp = None
self.last = None
class CacheSequenceAnalyzer(Analyzer):
__name__ = "CacheSequence"
def process(self, entry: dict) -> bool:
if self.filter(entry):
if entry['cache']:
self.store.append((entry['timestamp'], entry['cache']['@id']))
else:
self.store.append((entry['timestamp'], entry['cache']))
return False
def result(self, store: ResultStore) -> None:
store.add(Result(type(self), list(self.store)))
def __init__(self, settings: LogSettings):
super().__init__(settings)
self.store = []
self.filter = init_filter(settings, "start")