'''
:mod:`sim_trace` -- Simulator Tracing
========================================
.. module:: sim_trace
:synopsis: Moddy Simulator Tracing Support
.. moduleauthor:: Klaus Popp <klauspopp@gmx.de>
'''
import os
import sys
import inspect
from collections import deque
from .sim_base import time_unit_to_factor
class SimTraceEvent:
'''
simTraceEvents are the objects that are added to the simulators trace
buffer
'''
# pylint: disable=too-few-public-methods
def __init__(self, part, sub_obj, tv, act):
self.trace_time = -1 # when the event occurred
self.part = part # generating part
self.sub_obj = sub_obj # timer or port
self.trans_val = tv # Transport value (e.g. message)
self.action = act # action string
def __repr__(self):
trace_str = "%-8s" % (self.action)
if self.sub_obj is not None:
trace_str += self.sub_obj.hierarchy_name_with_type()
if self.trans_val is not None:
trace_str += " // %s" % self.trans_val.__str__()
return trace_str
[docs]class SimTracing:
'''
Simulator Tracing and logging
'''
def __init__(self, time_func):
# list of all traced events during execution
self._list_traced_events = deque()
self._dis_time_scale = 1 # time scale factor
self._dis_time_scale_str = "s" # time scale string
self._enable_trace_prints = False
self._time_func = time_func
self._num_assertion_failures = 0
def enable_trace_prints(self, enable_prints):
''' enable/disable trace prints '''
self._enable_trace_prints = enable_prints
def add_trace_event(self, trace_ev):
''' Add new event to Trace list, timestamp it, print it'''
trace_ev.trace_time = self._time_func()
self._list_traced_events.append(trace_ev)
if self._enable_trace_prints:
trace_str = "TRC: %10s %s" % (self.time_str(trace_ev.trace_time),
trace_ev)
print(trace_str)
def traced_events(self):
''' return list of traced events'''
return self._list_traced_events
def annotation(self, part, text):
'''
User routine to add an annotation to a life line at the
current simulation time
'''
trace_ev = SimTraceEvent(part, part, text, 'ANN')
self.add_trace_event(trace_ev)
class StateIndTransVal:
'''
class to hold the text and appearance of a state indicator
'''
# pylint: disable=too-few-public-methods
def __init__(self, text, appearance):
self.text = text
self.appearance = appearance
def __str__(self):
return self.text
def set_state_indicator(self, part, text, appearance=None):
'''
User routine to indicate the current state of a part.
Can be also used to indicate
UML execution specification to a life line
at the current simulation time.
An empty text flags 'no state' which removes the indication from the
life line
:param SimPart part: affected part
:param str text: text to display (Empty string to clear indicator)
:param dict appearance: (default: {}) colors for indicator
'''
trace_ev = SimTraceEvent(
part, part, self.StateIndTransVal(text, appearance), 'STA')
self.add_trace_event(trace_ev)
[docs] def set_display_time_unit(self, unit):
'''
Define how the simulator prints/displays time units
:param str unit: can be "s", "ms", "us", "ns"
'''
self._dis_time_scale_str = unit
self._dis_time_scale = time_unit_to_factor(unit)
def time_str(self, time):
'''
return a formatted time string of *time* based on the display scale
'''
tmfmt = "%.1f" % (time / self._dis_time_scale)
return tmfmt + self._dis_time_scale_str
#
# Model Assertions
#
def assertion_failed(self, part, assertion_str, frame_idx=1):
'''
Add an assertion failure trace event.
Increment global assertion failure counter.
Stop simulator if configured so.
:param simPart part: the related simPart. None if global assertion
:param string assertion_str: error message to display
:param int frame_idx: traceback frame index \
(1 if caller's frame, 2 if caller-caller's frame...)
'''
_, file_name, line_number, function_name, _, _ = \
inspect.stack()[frame_idx]
te_str = "%s: in %s, (%s::%d)" % (assertion_str, function_name,
os.path.basename(file_name),
line_number)
trace_ev = SimTraceEvent(part, part, te_str, 'ASSFAIL')
self.add_trace_event(trace_ev)
self._num_assertion_failures += 1
def assertion_failures(self):
''' Return number of assertion failures '''
return self._num_assertion_failures
def print_assertion_failures(self):
'''Print all traced assertion failures to stderr'''
if self._num_assertion_failures > 0:
print("%d Assertion failures during simulation" %
self._num_assertion_failures, file=sys.stderr)
for trace_ev in self.traced_events():
if trace_ev.action == "ASSFAIL":
print("%10s: %s: %s" % (self.time_str(
trace_ev.trace_time),
trace_ev.part,
trace_ev.trans_val.__str__()),
file=sys.stderr)