Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: response time class api #313

Merged
merged 15 commits into from
Aug 30, 2023
4 changes: 2 additions & 2 deletions src/caret_analyze/plot/stacked_bar/latency_stacked_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ def _get_response_time_record(
columns=target_object.column_names)
# include timestamp of response time (best, worst)
if self._case == 'best':
return response_time.to_best_case_response_records()
return response_time.to_best_case_stacked_bar()

return response_time.to_response_records()
return response_time.to_stacked_bar()

@property
def target_objects(self) -> Path:
Expand Down
163 changes: 92 additions & 71 deletions src/caret_analyze/record/records_service/response_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import numpy as np

from warnings import warn

from ..column import ColumnValue
from ..interface import RecordInterface, RecordsInterface
from ..record_factory import RecordFactory, RecordsFactory
Expand Down Expand Up @@ -241,14 +243,14 @@ class ResponseTime:
>>> # Calculate response time
>>> records = callback.to_records()
>>> response = ResponseTime(records)
>>> response_records = response.to_response_records()
>>> response_df = response_records.to_dataframe()
>>> response_time_records = response.to_best_case_records()
>>> response_df = response_time_records.to_dataframe()

>>> path = app.get_path('path_name')
>>> records = path.to_records()
>>> response = ResponseTime(records)
>>> response_records = response.to_response_records()
>>> response_df = response_records.to_dataframe()
>>> response_time_records = response.to_best_case_records()
>>> response_df = response_time_records.to_dataframe()

"""

Expand Down Expand Up @@ -276,32 +278,9 @@ def __init__(
self._timeseries = ResponseTimeseries(self._records)
self._histogram = ResponseHistogram(self._records, self._timeseries)

def to_records(self, *, all_pattern=False) -> RecordsInterface:
def to_stacked_bar(self) -> RecordsInterface:
"""
Calculate response time records.

Parameters
----------
all_pattern : bool, optional
If True, get response times with time overlap, by default False. [for debug]

Returns
-------
RecordsInterface
response time records.
The best and worst cases alternate line by line.
Columns
- {columns[0]}
- {columns[1]}
- {...}
- {columns[n-1]}

"""
return self._records.to_records(all_pattern)

def to_response_records(self) -> RecordsInterface:
"""
Calculate response records.
Calculate records for stacked bar.

Returns
-------
Expand All @@ -318,9 +297,9 @@ def to_response_records(self) -> RecordsInterface:
"""
return self._records.to_range_records()

def to_best_case_response_records(self) -> RecordsInterface:
def to_best_case_stacked_bar(self) -> RecordsInterface:
"""
Calculate response records.
Calculate records for stacked bar.

Returns
-------
Expand All @@ -336,13 +315,51 @@ def to_best_case_response_records(self) -> RecordsInterface:
"""
return self._records.to_range_records('best')

def to_worst_case_response_records(self) -> RecordsInterface:
def to_worst_case_stacked_bar(self) -> RecordsInterface:
# NOTE:
# We think this function is unnecessary.
# If necessary, please contact us.
raise NotImplementedError()

def to_best_case_records(self) -> RecordsInterface:
"""
Calculate the best-case records data for response time.

The best case for response time are included message flow latency.

Returns
-------
RecordsInterface
Records of the best cases response time.

Columns
- {columns[0]}
- {'response_time'}

"""
return self._timeseries.to_best_case_records()

def to_worst_case_records(self) -> RecordsInterface:
"""
Calculate the worst-case records data for response time.

The worst case in response time includes message flow latencies
as well as delays caused by various factors such as lost messages.

Returns
-------
RecordsInterface
Records of the worst cases response time.

Columns
- {columns[0]}
- {'response_time'}

"""
return self._timeseries.to_worst_case_records()

def to_best_case_timeseries(self) -> tuple[np.ndarray, np.ndarray]:
warn('This API will be moved to the Plot package in the near future.', DeprecationWarning)
"""
Calculate the best-case time series data for response time.

Expand All @@ -357,6 +374,7 @@ def to_best_case_timeseries(self) -> tuple[np.ndarray, np.ndarray]:
return self._timeseries.to_best_case_timeseries()

def to_worst_case_timeseries(self) -> tuple[np.ndarray, np.ndarray]:
warn('This API will be moved to the Plot package in the near future.', DeprecationWarning)
"""
Calculate the worst-case time series data for response time.

Expand Down Expand Up @@ -456,38 +474,6 @@ def __init__(
"""
self._response_map = response_map

def to_records(
self,
all_pattern: bool
) -> RecordsInterface:
"""
Calculate records.

Parameters
----------
all_pattern : bool
Calculate response times with time overlap, by default False. [for debug]

Returns
-------
RecordsInterface
response time.
The best and worst cases alternate line by line.
Columns
- {columns[0]}
- {columns[1]}
- {...}
- {columns[n-1]}

"""
if len(self._response_map) == 0:
return self._create_empty_records()

if all_pattern:
return self._create_all_pattern_records()

return self._create_response_records()

def to_range_records(
self,
case: str = 'worst',
Expand Down Expand Up @@ -541,9 +527,9 @@ def add_records(

return records

def to_best_case_records(self) -> RecordsInterface:
def to_best_case_stacked_bar(self) -> RecordsInterface:
"""
Calculate best case response time records.
Calculate best case response time records for stacked bar.

Returns
-------
Expand All @@ -570,9 +556,9 @@ def add_records(

return records

def to_worst_case_records(self) -> RecordsInterface:
def to_worst_case_stacked_bar(self) -> RecordsInterface:
"""
Calculate worst case response records.
Calculate worst case response time records for stacked bar.

Returns
-------
Expand Down Expand Up @@ -759,6 +745,42 @@ def _to_timeseries(self, input_column, output_column):

return t_in, latency

def to_best_case_records(self) -> RecordsInterface:
records = self._records.to_range_records()
input_column = records.columns[1]
output_column = records.columns[-1]
return self._to_records(input_column, output_column)

def to_worst_case_records(self) -> RecordsInterface:
records = self._records.to_range_records()
input_column = records.columns[0]
output_column = records.columns[-1]
return self._to_records(input_column, output_column)
Comment on lines +821 to +831
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although it is also used in the function from line 743, I think that using to_range_records is not best way just for column name.
Although there is no way to get column names in ResponseTime class, it is better that, for example, create a new variable self._input_records = records in the ResponseTime class and then write as input_column = f'{self._input_records.columns[0]}_min or max'.
However, it is a little more complicated to write than before.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR will not be changed in this PR as it is written in accordance with existing code.


def _to_records(self, input_column, output_column) -> RecordsInterface:
records: RecordsInterface = self._create_empty_records(input_column)

range_records = self._records.to_range_records()
t_in = range_records.get_column_series(input_column)
t_out = range_records.get_column_series(output_column)
Comment on lines +837 to +838
Copy link
Contributor

@taro-yu taro-yu Aug 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although it is also used in the function _to_timeseries(), it's better to change t_in/out to timestamps_in/out or somethings more comprehensible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR will not be changed in this PR as it is written in accordance with existing code.


for start_ts, end_ts in zip(t_in, t_out):
record = {
input_column: start_ts,
'response_time': end_ts - start_ts
}
records.append(record)

return records

def _create_empty_records(
self,
input_column: str
) -> RecordsInterface:
return RecordsFactory.create_instance(columns=[
ColumnValue(input_column), ColumnValue('response_time')
])


class ResponseHistogram:
"""Class that calculates response time histogram."""
Expand Down Expand Up @@ -873,7 +895,7 @@ def to_best_case_histogram(
Occurs when the number of response latencies is insufficient.

"""
_, latency_ns = self._timeseries.to_best_case_timeseries()
latency_ns = self._timeseries.to_best_case_records().get_column_series('response_time')
return self._to_histogram(latency_ns, binsize_ns, density)

def to_worst_case_histogram(
Expand Down Expand Up @@ -908,8 +930,7 @@ def to_worst_case_histogram(
Occurs when the number of response latencies is insufficient.

"""
_, latency_ns = self._timeseries.to_worst_case_timeseries()

latency_ns = self._timeseries.to_worst_case_records().get_column_series('response_time')
return self._to_histogram(latency_ns, binsize_ns, density)

@staticmethod
Expand Down
Loading
Loading