| Index: dashboard/dashboard/pinpoint/models/job.py
|
| diff --git a/dashboard/dashboard/pinpoint/models/job.py b/dashboard/dashboard/pinpoint/models/job.py
|
| index a2bf223084ee3787ffaf551eec2d48e5847920e5..bc95bfcd8dd3eb1ef2bf11d61812b9e40ed1366c 100644
|
| --- a/dashboard/dashboard/pinpoint/models/job.py
|
| +++ b/dashboard/dashboard/pinpoint/models/job.py
|
| @@ -213,6 +213,9 @@ class _JobState(object):
|
| # _changes can be in arbitrary order. Client should not assume that the
|
| # list of Changes is sorted in any particular order.
|
| self._changes = []
|
| + # _change_distances[i] contains the distance, in commits, between
|
| + # _changes[i-1] and _changes[i]. _change_distances[0] is always 0.
|
| + self._change_distances = []
|
|
|
| # A mapping from a Change to a list of Attempts on that Change.
|
| self._attempts = {}
|
| @@ -223,12 +226,24 @@ class _JobState(object):
|
| assert change in self._attempts
|
| self._attempts[change].append(attempt_module.Attempt(self._quests, change))
|
|
|
| - def AddChange(self, change, index=None):
|
| - if index:
|
| - self._changes.insert(index, change)
|
| - else:
|
| - self._changes.append(change)
|
| + def AddChange(self, change, index=None, distances=(None, None)):
|
| + if index is None:
|
| + index = len(self._changes)
|
|
|
| + # Compute distances, if needed.
|
| + left, right = distances
|
| + if left is None:
|
| + left = _ChangeDistance(self._changes[index - 1], change) if index else 0
|
| + if right is None and index < len(self._changes):
|
| + right = _ChangeDistance(change, self._changes[index])
|
| +
|
| + # Insert into _changes and _change_distances.
|
| + if right is not None:
|
| + self._change_distances[index] = right
|
| + self._change_distances.insert(index, left)
|
| + self._changes.insert(index, change)
|
| +
|
| + # Add Attempts.
|
| self._attempts[change] = []
|
| for _ in xrange(self._repeat_count):
|
| self.AddAttempt(change)
|
| @@ -257,11 +272,16 @@ class _JobState(object):
|
| if comparison_result == _DIFFERENT:
|
| # Different: Bisect and add an additional Change to the job.
|
| try:
|
| - midpoint = change_module.Change.Midpoint(change_a, change_b)
|
| + midpoint, distances = change_module.Change.Midpoint(change_a,
|
| + change_b)
|
| except change_module.NonLinearError:
|
| continue
|
| + left, right = distances
|
| + if not (left and right):
|
| + continue
|
| +
|
| logging.info('Adding Change %s.', midpoint)
|
| - self.AddChange(midpoint, index)
|
| + self.AddChange(midpoint, index, distances)
|
| elif comparison_result == _SAME:
|
| # The same: Do nothing.
|
| continue
|
| @@ -315,6 +335,7 @@ class _JobState(object):
|
| return {
|
| 'quests': map(str, self._quests),
|
| 'changes': [change.AsDict() for change in self._changes],
|
| + 'change_distances': self._change_distances,
|
| # TODO: Use JobState.Differences().
|
| 'comparisons': comparisons,
|
| 'result_values': result_values,
|
| @@ -353,6 +374,14 @@ class _JobState(object):
|
| return _UNKNOWN
|
|
|
|
|
| +def _ChangeDistance(change_a, change_b):
|
| + try:
|
| + _, distances = change_module.Change.Midpoint(change_a, change_b)
|
| + return sum(distances)
|
| + except change_module.NonLinearError:
|
| + return 1
|
| +
|
| +
|
| def _CombineResultsPerQuest(attempts):
|
| aggregate_results = collections.defaultdict(list)
|
| for attempt in attempts:
|
|
|