Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions otava/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,26 +104,6 @@ def change_point(
return ChangePoint.from_candidate(candidate, stats)


def fill_missing(data: Sequence[SupportsFloat]):
"""
Forward-fills None occurrences with nearest previous non-None values.
Initial None values are back-filled with the nearest future non-None value.

TODO: Remove this.
"""
prev = None
for i in range(len(data)):
if data[i] is None and prev is not None:
data[i] = prev
prev = data[i]

prev = None
for i in reversed(range(len(data))):
if data[i] is None and prev is not None:
data[i] = prev
prev = data[i]


def merge(
change_points: TtestCPList, series: Sequence[SupportsFloat], max_pvalue: float, min_magnitude: float
) -> TtestCPList:
Expand Down
4 changes: 0 additions & 4 deletions otava/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
TTestStats,
compute_change_points,
compute_change_points_orig,
fill_missing,
)
from otava.change_point_divisive.base import (
ChangePoint,
Expand Down Expand Up @@ -166,7 +165,6 @@ def __compute_change_points(
weak_change_points = ChangePointsByMetric()
for metric in series.data.keys():
values = series.data[metric].copy()
fill_missing(values)
if options.orig_edivisive:
change_points, _ = compute_change_points_orig(
values,
Expand Down Expand Up @@ -327,8 +325,6 @@ def append(self, time, new_data, attributes):
attributes=self.__series.attributes_at(cp.index),
)
)
# TODO: Remove this. It should not be a requirement that metrics have the same history.
fill_missing(self.__series.data[metric])

r = ChangePointsByMetric.from_dict(result)
w = ChangePointsByMetric.from_dict(weak_change_points)
Expand Down
13 changes: 0 additions & 13 deletions tests/analysis_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,10 @@
TTestSignificanceTester,
compute_change_points,
compute_change_points_orig,
fill_missing,
)
from otava.change_point_divisive.base import CandidateChangePoint


def test_fill_missing():
list1 = [None, None, 1.0, 1.2, 0.5]
list2 = [1.0, 1.2, None, None, 4.3]
list3 = [1.0, 1.2, 0.5, None, None]
fill_missing(list1)
fill_missing(list2)
fill_missing(list3)
assert list1 == [1.0, 1.0, 1.0, 1.2, 0.5]
assert list2 == [1.0, 1.2, 1.2, 1.2, 4.3]
assert list3 == [1.0, 1.2, 0.5, 0.5, 0.5]


def test_single_series():
series = [
1.02,
Expand Down
51 changes: 49 additions & 2 deletions tests/series_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,11 @@ def test_div_by_zero():


def test_change_point_detection_performance():
timestamps = range(0, 90) # 3 months of data
timestamps = range(90) # 3 months of data
series = [random() for x in timestamps]

start_time = time.process_time()
for run in range(0, 10): # 10 series
for run in range(10): # 10 series
test = Series(
"test",
branch=None,
Expand Down Expand Up @@ -360,3 +360,50 @@ def test_orig_edivisive():
# assert len(change_points) == 2
# assert change_points[0].index == 4
# assert change_points[1].index == 6


def test_series_sparse_commits():
"""Verify series processes sparse commit sequences without artificial padding."""
name = "sparse_commit_test"
branch = "main"
time_points = [1000, 1001, 1005, 1008]
metrics = {}
data = {"latency": [100.5, 101.0, 105.2, 98.7]}
# Match length of attributes list to len(time_points) == 4
attributes = {"env": ["ci", "ci", "ci", "ci"]}

series = Series(name, branch, time_points, metrics, data, attributes)

assert len(series.time) == 4
assert series.time == [1000, 1001, 1005, 1008]
assert series.data["latency"] == [100.5, 101.0, 105.2, 98.7]


def test_series_irregular_timestamps():
"""Verify change detection operates on unpadded time intervals."""
name = "irregular_ts_test"
branch = "main"
time_points = [1600000000, 1600000010, 1600000300, 1600003600]
metrics = {}
data = {"duration": [50.0, 51.0, 50.5, 95.0]}
attributes = {}

series = Series(name, branch, time_points, metrics, data, attributes)

assert len(series.time) == 4
assert series.data["duration"] == [50.0, 51.0, 50.5, 95.0]


def test_series_raw_initialization():
"""Verify Series initialization operates directly on raw unpadded input data."""
name = "raw_init_test"
branch = "main"
time_points = [1, 2, 3]
metrics = {}
data = {"throughput": [10.0, 12.0, 11.5]}
attributes = {}

series = Series(name, branch, time_points, metrics, data, attributes)

assert len(series.time) == 3
assert series.data["throughput"] == [10.0, 12.0, 11.5]
Loading