Skip to content

Commit

Permalink
Add support sim_time to histogram APIs.
Browse files Browse the repository at this point in the history
Signed-off-by: ISP akm <[email protected]>
  • Loading branch information
xygyo77 committed Nov 16, 2023
1 parent 97fcbc4 commit dc28432
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 30 deletions.
26 changes: 25 additions & 1 deletion src/caret_analyze/plot/histogram/histogram_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from ..visualize_lib import VisualizeLibInterface
from ...exceptions import UnsupportedTypeError
from ...runtime import CallbackBase, Communication, Path
from ...record import Range
from ...common import ClockConverter

MetricsTypes = Frequency | Latency | Period | ResponseTime
HistTypes = CallbackBase | Communication | Path
Expand Down Expand Up @@ -106,11 +108,33 @@ def figure(
# Validate
self._validate_xaxis_type(xaxis_type)

# get converter
converter: ClockConverter | None = None
if xaxis_type == 'sim_time':
records_range = Range([to.to_records() for to in self._target_objects])
frame_min, frame_max = records_range.get_range()
if isinstance(self._target_objects[0], Communication):
for comm in self._target_objects:
assert isinstance(comm, Communication)
if comm._callback_subscription:
converter_cb = comm._callback_subscription
break
provider = converter_cb._provider
converter = provider.get_sim_time_converter(frame_min, frame_max)
elif isinstance(self._target_objects[0], Path):
assert len(self._target_objects[0].child) > 0
provider = self._target_objects[0].child[0]._provider
converter = provider.get_sim_time_converter(frame_min, frame_max)
else:
provider = self._target_objects[0]._provider
converter = provider.get_sim_time_converter(frame_min, frame_max)

return self._visualize_lib.histogram(
self._metrics,
self._target_objects,
self._data_type,
self._case
self._case,
converter
)

def _validate_xaxis_type(self, xaxis_type: str) -> None:
Expand Down
21 changes: 14 additions & 7 deletions src/caret_analyze/plot/visualize_lib/bokeh/bokeh.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
from .util import ColorSelectorFactory, LegendManager
from ..visualize_lib_interface import VisualizeLibInterface
from ...metrics_base import MetricsBase
from ....record import ColumnValue, Range, RecordFactory, RecordsFactory, RecordsInterface
from ....runtime import CallbackBase, CallbackGroup, Communication, Path, Publisher, Subscription
from ....common import ClockConverter

TimeSeriesTypes = CallbackBase | Communication | (Publisher | Subscription) | Path
MetricsTypes = Frequency | Latency | Period | ResponseTime
Expand Down Expand Up @@ -181,7 +183,8 @@ def histogram(
metrics: list[MetricsTypes],
target_objects: Sequence[HistTypes],
data_type: str,
case: str | None = None
case: str | None = None,
converter: ClockConverter | None = None,
) -> Figure:
"""
Get a histogram figure.
Expand All @@ -192,6 +195,8 @@ def histogram(
Data array to be visualized.
target_objects : list[CallbackBase | Communication | Path]
Object array to be visualized.
converter: ClockConverter
Time conversion function at sim_time.
data_type : str
Name of metrics.
"frequency", "latency", "period" or "response_time" can be specified.
Expand All @@ -213,7 +218,9 @@ def histogram(
x_label = data_type + ' [ms]'
else:
raise NotImplementedError()

label_str = ' - simulation time -' if converter else ' - system time -'
x_label = x_label + label_str

plot: Figure = Figure(
title=data_type if case is None else f'{data_type} --- {case} case ---',
x_axis_label=x_label, y_axis_label='Probability', width=800
Expand All @@ -223,26 +230,26 @@ def histogram(
if data_type == 'response_time':
if case == 'all':
data_list = [
[_ for _ in m.to_all_records().get_column_series(data_type)
[_ for _ in m.to_all_records(converter=converter).get_column_series(data_type)
if _ is not None]
for m in metrics if isinstance(m, ResponseTime)
]
elif case == 'best':
data_list = [
[_ for _ in m.to_best_case_records().get_column_series(data_type)
[_ for _ in m.to_best_case_records(converter=converter).get_column_series(data_type)
if _ is not None]
for m in metrics if isinstance(m, ResponseTime)
]
elif case == 'worst':
data_list = [
[_ for _ in m.to_worst_case_records().get_column_series(data_type)
[_ for _ in m.to_worst_case_records(converter=converter).get_column_series(data_type)
if _ is not None]
for m in metrics if isinstance(m, ResponseTime)
]
elif case == 'worst-with-external-latency':
data_list = [
[_ for _ in
m.to_worst_with_external_latency_case_records().get_column_series(data_type)
m.to_worst_with_external_latency_case_records(converter=converter).get_column_series(data_type)
if _ is not None]
for m in metrics if isinstance(m, ResponseTime)
]
Expand All @@ -251,7 +258,7 @@ def histogram(
"all", "best", "worst", "worst-with-external-latency".')
else:
data_list = [
[_ for _ in m.to_records().get_column_series(data_type) if _ is not None]
[_ for _ in m.to_records(converter=converter).get_column_series(data_type) if _ is not None]
for m in metrics if not isinstance(m, ResponseTime)
]

Expand Down
4 changes: 3 additions & 1 deletion src/caret_analyze/plot/visualize_lib/bokeh/timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ def create_figure(self) -> Figure:
converter = provider.get_sim_time_converter(frame_min, frame_max)
break
elif isinstance(target_objects[0], Path):
converter = None
assert len(target_objects[0].child) > 0
provider = target_objects[0].child[0]._provider
converter = provider.get_sim_time_converter(frame_min, frame_max)
else:
provider = target_objects[0]._provider
converter = provider.get_sim_time_converter(frame_min, frame_max)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from ..metrics_base import MetricsBase
from ...record import Frequency, Latency, Period, ResponseTime
from ...runtime import CallbackBase, CallbackGroup, Communication, Path, Publisher, Subscription
from ...common import ClockConverter

TimeSeriesTypes = CallbackBase | Communication | (Publisher | Subscription)
MetricsTypes = Frequency | Latency | Period | ResponseTime
Expand Down Expand Up @@ -96,6 +97,7 @@ def histogram(
metrics: list[MetricsTypes],
target_objects: Sequence[HistTypes],
data_type: str,
case: str | None = None
case: str | None = None,
converter: ClockConverter | None = None,
) -> Figure:
raise NotImplementedError()
15 changes: 13 additions & 2 deletions src/caret_analyze/record/records_service/frequency.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from ..column import ColumnValue
from ..interface import RecordsInterface
from ..record_factory import RecordsFactory
from ...common import ClockConverter


class Frequency:
Expand Down Expand Up @@ -68,6 +69,7 @@ def to_records(
interval_ns: int = 1000000000,
base_timestamp: int | None = None,
until_timestamp: int | None = None,
converter: ClockConverter | None = None
) -> RecordsInterface:
"""
Calculate frequency records.
Expand All @@ -83,6 +85,8 @@ def to_records(
until_timestamp : int | None, optional
End time of measurement.
If None, oldest timestamp is used.
converter : ClockConverter | None, optional
Converter to simulation time.
Returns
-------
Expand All @@ -100,7 +104,8 @@ def to_records(
timestamp_list, frequency_list = self._get_frequency_with_timestamp(
interval_ns,
base_timestamp or self._target_timestamps[0],
until_timestamp or self._target_timestamps[-1]
until_timestamp or self._target_timestamps[-1],
converter
)
for ts, freq in zip(timestamp_list, frequency_list):
record = {
Expand All @@ -122,13 +127,19 @@ def _get_frequency_with_timestamp(
self,
interval_ns: int,
base_timestamp: int,
until_timestamp: int
until_timestamp: int,
converter: ClockConverter | None = None
) -> tuple[list[int], list[int]]:
if converter:
base_timestamp = round(converter.convert(base_timestamp))
until_timestamp = round(converter.convert(until_timestamp))
timestamp_list: list[int] = [base_timestamp]
frequency_list: list[int] = [0]
interval_start_time = base_timestamp

for timestamp in self._target_timestamps:
if converter:
timestamp = round(converter.convert(timestamp))
if timestamp < base_timestamp:
continue
while not (interval_start_time <= timestamp < interval_start_time + interval_ns):
Expand Down
14 changes: 13 additions & 1 deletion src/caret_analyze/record/records_service/latency.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ..column import ColumnValue
from ..interface import RecordsInterface
from ..record_factory import RecordsFactory
from ...common import ClockConverter


class Latency:
Expand Down Expand Up @@ -56,10 +57,18 @@ def __init__(
end_ts = record.get(self._end_column)
self._end_timestamps.append(end_ts)

def to_records(self) -> RecordsInterface:
def to_records(
self,
converter: ClockConverter | None = None
) -> RecordsInterface:
"""
Calculate latency records.
Parameters
----------
converter : ClockConverter | None, optional
Converter to simulation time.
Returns
-------
RecordsInterface
Expand All @@ -72,6 +81,9 @@ def to_records(self) -> RecordsInterface:
records = self._create_empty_records()

for start_ts, end_ts in zip(self._start_timestamps, self._end_timestamps):
if converter:
start_ts = round(converter.convert(start_ts))
end_ts = round(converter.convert(end_ts))
record = {
self._start_column: start_ts,
'latency': end_ts - start_ts
Expand Down
25 changes: 20 additions & 5 deletions src/caret_analyze/record/records_service/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from ..column import ColumnValue
from ..interface import RecordsInterface
from ..record_factory import RecordsFactory
from ...common import ClockConverter


class Period:
Expand Down Expand Up @@ -63,10 +64,18 @@ def row_filter(record: RecordInterface) -> bool:
timestamp = record.get(self._target_column)
self._target_timestamps.append(timestamp)

def to_records(self) -> RecordsInterface:
def to_records(
self,
converter: ClockConverter | None = None
) -> RecordsInterface:
"""
Calculate period records.
Parameters
----------
converter : ClockConverter | None, optional
Converter to simulation time.
Returns
-------
RecordsInterface
Expand All @@ -79,10 +88,16 @@ def to_records(self) -> RecordsInterface:
records = self._create_empty_records()

for i in range(1, len(self._target_timestamps)):
record = {
self._target_column: self._target_timestamps[i-1],
'period': self._target_timestamps[i] - self._target_timestamps[i-1]
}
if converter:
record = {
self._target_column: round(converter.convert(self._target_timestamps[i-1])),
'period': round(converter.convert(self._target_timestamps[i]) - converter.convert(self._target_timestamps[i-1]))
}
else:
record = {
self._target_column: self._target_timestamps[i-1],
'period': self._target_timestamps[i] - self._target_timestamps[i-1]
}
records.append(record)

return records
Expand Down
Loading

0 comments on commit dc28432

Please sign in to comment.