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

feat: stacked bar worst-in-input and all #339

Merged
4 changes: 4 additions & 0 deletions src/caret_analyze/plot/stacked_bar/latency_stacked_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ def _get_response_time_record(
# include timestamp of response time (best, worst)
if self._case == 'best':
return response_time.to_best_case_stacked_bar()
if self._case == 'worst-in-input':
return response_time.to_worst_in_input_case_stacked_bar()
if self._case == 'all':
return response_time.to_all_stacked_bar()

return response_time.to_stacked_bar()

Expand Down
115 changes: 115 additions & 0 deletions src/caret_analyze/record/records_service/response_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,15 @@ def __init__(
if columns:
self._start_column = columns[0]
self._end_column = columns[-1]
self._columns = columns
else:
self._start_column = records.columns[0]
self._end_column = records.columns[-1]
self._columns = records.columns

self._start_timestamps: list[int] = []
self._end_timestamps: list[int] = []
self._records: list[RecordInterface] = []

for record in reversed(records.data):
if self._end_column in record.columns:
Expand All @@ -257,10 +260,12 @@ def __init__(
if start_ts not in self._start_timestamps:
self._start_timestamps.insert(0, start_ts)
self._end_timestamps.insert(0, end_ts)
self._records.insert(0, record)
else:
idx = self._start_timestamps.index(start_ts)
if end_ts < self._end_timestamps[idx]:
self._end_timestamps[idx] = end_ts
self._records[idx] = record

def to_all_records(self) -> RecordsInterface:
records = self._create_empty_records()
Expand Down Expand Up @@ -296,6 +301,80 @@ def to_worst_in_input_records(self) -> RecordsInterface:

return records

def to_all_stacked_bar(self) -> RecordsInterface:
end_column_record_dict: dict[int, list[RecordInterface]] = {}

# classify records which have same end timestamp
end_ts = None
for record in reversed(self._records):
if self._end_column in record.columns:
end_ts = record.get(self._end_column)
elif end_ts is None:
continue

if end_ts in end_column_record_dict.keys():
end_column_record_dict[end_ts].insert(0, record)
else:
end_column_record_dict[end_ts] = [record]

# fill empty data
filled_records_dict: dict[int, list[RecordInterface]] = {}
# for each records which have same end timestamp
for end_ts, record_list in end_column_record_dict.items():
filled_records_dict[end_ts] = []

for record in reversed(record_list):
# if record doesn't have some timestamps,
# record timestamps just after
for column in self._columns:
if column in record.columns:
continue
timestamps = [record.get(column) for record in filled_records_dict[end_ts]
if column in record.columns]
record.add(column, min(timestamps))
filled_records_dict[end_ts].append(record)

columns = [ColumnValue(c) for c in self._columns]
stacked_bar_records: RecordsInterface =\
RecordsFactory.create_instance(init=[_.data for _
in sum(filled_records_dict.values(), [])],
columns=columns)
stacked_bar_records.sort_column_order()
return stacked_bar_records

def to_worst_in_input_case_stacked_bar(self) -> RecordsInterface:
end_column_record_dict: dict[int, list[RecordInterface]] = {}

# classify records which have same end timestamp
end_ts = None
for record in reversed(self._records):
if self._end_column in record.columns:
end_ts = record.get(self._end_column)
elif end_ts is None:
continue

if end_ts in end_column_record_dict.keys():
end_column_record_dict[end_ts].append(record)
else:
end_column_record_dict[end_ts] = [record]

# generate worst-case work flow
filled_record_list: list[RecordInterface] = []
for record_list in end_column_record_dict.values():
worst_in_input_record = RecordFactory.create_instance()

for column in self._columns:
timestamps = [r.get(column) for r in record_list if column in r.columns]
worst_in_input_record.add(column, min(timestamps))
filled_record_list.append(worst_in_input_record)

columns = [ColumnValue(c) for c in self._columns]
stacked_bar_records: RecordsInterface =\
RecordsFactory.create_instance(init=[_.data for _ in filled_record_list],
columns=columns)
stacked_bar_records.sort_column_order()
return stacked_bar_records

def _create_empty_records(
self
) -> RecordsInterface:
Expand Down Expand Up @@ -413,6 +492,42 @@ def to_best_case_stacked_bar(self) -> RecordsInterface:
"""
return self._records.to_range_records('best')

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

Returns
-------
RecordsInterface
Records of the all response time.

Columns
- {columns[0]}
- {columns[1]}
- {...}
- {columns[n-1]}

"""
return self._response_map_all.to_all_stacked_bar()

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

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

Columns
- {columns[0]}
- {columns[1]}
- {...}
- {columns[n-1]}

"""
return self._response_map_all.to_worst_in_input_case_stacked_bar()

def to_worst_case_stacked_bar(self) -> RecordsInterface:
# NOTE:
# We think this function is unnecessary.
Expand Down
156 changes: 156 additions & 0 deletions src/test/record/records_service/test_response_time_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,159 @@ def test_drop_case(self):
]
result = to_dict(response_time.to_all_records())
assert result == expect_raw


class TestAllStackedBar:

@property
def columns(self) -> list[ColumnValue]:
return [ColumnValue('start'), ColumnValue('middle0'),
ColumnValue('middle1'), ColumnValue('end')]

@property
def column_names(self) -> list[str]:
return ['start', 'middle0', 'middle1', 'end']

def test_empty_case(self):
records_raw = []
records = create_records(records_raw, self.columns)

response_time = ResponseTime(records, columns=self.column_names)

expect_raw = []
result = to_dict(response_time.to_all_stacked_bar())
assert result == expect_raw

def test_single_case(self):
records_raw = [
{'start': 0, 'middle0': 1, 'middle1': 2, 'end': 3},
{'start': 4, 'middle0': 5, 'middle1': 7, 'end': 8},
{'start': 6, 'middle0': 7, 'middle1': 8, 'end': 9}
]
records = create_records(records_raw, self.columns)

response_time = ResponseTime(records, columns=self.column_names)

expect_raw = [
{'start': 0, 'middle0': 1, 'middle1': 2, 'end': 3},
{'start': 4, 'middle0': 5, 'middle1': 7, 'end': 8},
{'start': 6, 'middle0': 7, 'middle1': 8, 'end': 9}
]
result = to_dict(response_time.to_all_stacked_bar())
assert result == expect_raw

def test_multi_case(self):
records_raw = [
{'start': 0, 'middle0': 1, 'middle1': 3, 'end': 4},
{'start': 1, 'middle0': 2, 'middle1': 3, 'end': 4},
{'start': 2, 'middle0': 3, 'middle1': 5, 'end': 6},
{'start': 3, 'middle0': 4, 'middle1': 5, 'end': 6}
]
records = create_records(records_raw, self.columns)

response_time = ResponseTime(records, columns=self.column_names)

expect_raw = [
{'start': 0, 'middle0': 1, 'middle1': 3, 'end': 4},
{'start': 1, 'middle0': 2, 'middle1': 3, 'end': 4},
{'start': 2, 'middle0': 3, 'middle1': 5, 'end': 6},
{'start': 3, 'middle0': 4, 'middle1': 5, 'end': 6}
]
result = to_dict(response_time.to_all_stacked_bar())
assert result == expect_raw

def test_drop_case(self):
records_raw = [
{'start': 0, 'middle0': 1},
{'start': 1, 'middle0': 2, 'middle1': 3, 'end': 4},
{'start': 2, 'middle0': 3, 'middle1': 4},
{'start': 3, 'middle0': 4, 'middle1': 5, 'end': 6}
]
records = create_records(records_raw, self.columns)

response_time = ResponseTime(records, columns=self.column_names)

expect_raw = [
{'start': 0, 'middle0': 1, 'middle1': 3, 'end': 4},
{'start': 1, 'middle0': 2, 'middle1': 3, 'end': 4},
{'start': 2, 'middle0': 3, 'middle1': 4, 'end': 6},
{'start': 3, 'middle0': 4, 'middle1': 5, 'end': 6}
]
result = to_dict(response_time.to_all_stacked_bar())
assert result == expect_raw


class TestWorstInInputStackedBar:

@property
def columns(self) -> list[ColumnValue]:
return [ColumnValue('start'), ColumnValue('middle0'),
ColumnValue('middle1'), ColumnValue('end')]

@property
def column_names(self) -> list[str]:
return ['start', 'middle0', 'middle1', 'end']

def test_empty_case(self):
records_raw = []
records = create_records(records_raw, self.columns)

response_time = ResponseTime(records, columns=self.column_names)

expect_raw = []
result = to_dict(response_time.to_worst_in_input_case_stacked_bar())
assert result == expect_raw

def test_single_case(self):
records_raw = [
{'start': 0, 'middle0': 1, 'middle1': 2, 'end': 3},
{'start': 4, 'middle0': 5, 'middle1': 7, 'end': 8},
{'start': 6, 'middle0': 7, 'middle1': 8, 'end': 9}
]
records = create_records(records_raw, self.columns)

response_time = ResponseTime(records, columns=self.column_names)

expect_raw = [
{'start': 0, 'middle0': 1, 'middle1': 2, 'end': 3},
{'start': 4, 'middle0': 5, 'middle1': 7, 'end': 8},
{'start': 6, 'middle0': 7, 'middle1': 8, 'end': 9}
]
result = to_dict(response_time.to_worst_in_input_case_stacked_bar())
assert result == expect_raw

def test_multi_case(self):
records_raw = [
{'start': 0, 'middle0': 1, 'middle1': 3, 'end': 4},
{'start': 1, 'middle0': 2, 'middle1': 3, 'end': 4},
{'start': 2, 'middle0': 3, 'middle1': 5, 'end': 6},
{'start': 3, 'middle0': 4, 'middle1': 5, 'end': 6}
]
records = create_records(records_raw, self.columns)

response_time = ResponseTime(records, columns=self.column_names)

expect_raw = [
{'start': 0, 'middle0': 1, 'middle1': 3, 'end': 4},
{'start': 2, 'middle0': 3, 'middle1': 5, 'end': 6},
]
result = to_dict(response_time.to_worst_in_input_case_stacked_bar())
assert result == expect_raw

def test_drop_case(self):
records_raw = [
{'start': 0, 'middle0': 1},
{'start': 1, 'middle0': 2, 'middle1': 3, 'end': 4},
{'start': 2, 'middle0': 3, 'middle1': 4},
{'start': 3, 'middle0': 4, 'middle1': 5, 'end': 6}
]
records = create_records(records_raw, self.columns)

response_time = ResponseTime(records, columns=self.column_names)

expect_raw = [
{'start': 0, 'middle0': 1, 'middle1': 3, 'end': 4},
{'start': 2, 'middle0': 3, 'middle1': 4, 'end': 6},
]
result = to_dict(response_time.to_worst_in_input_case_stacked_bar())
assert result == expect_raw
Loading