def baseline_metric()

in testsuite/driver/perf_notes.py [0:0]


def baseline_metric(commit, name, test_env, metric, way):
    # For performance reasons (in order to avoid calling commit_hash), we assert
    # commit is already a commit hash.
    assert is_commit_hash(commit)

    # Get all recent commit hashes.
    commit_hashes = baseline_commit_log(commit)
    def depth_to_commit(depth):
        return commit_hashes[depth]

    def has_expected_change(commit):
        return get_allowed_perf_changes(commit).get(name) \
                != None

    # Bool -> String
    def namespace(useCiNamespace):
        return CiNamespace if useCiNamespace else LocalNamespace

    ci_test_env = best_fit_ci_test_env()

    # gets the metric of a given commit
    # (Bool, Int) -> (float | None)
    def commit_metric(useCiNamespace, depth):
        global _commit_metric_cache
        currentCommit = depth_to_commit(depth)

        # Get test environment.
        effective_test_env = ci_test_env if useCiNamespace else test_env
        if effective_test_env == None:
            # This can happen when no best fit ci test is found.
            return None

        # Check for cached value.
        cacheKeyA = (useCiNamespace, currentCommit)
        cacheKeyB = (effective_test_env, name, metric, way)
        if cacheKeyA in _commit_metric_cache:
            return _commit_metric_cache[cacheKeyA].get(cacheKeyB)

        # Cache miss.
        # Calculate baselines from the current commit's git note.
        # Note that the git note may contain data for other tests. All tests'
        # baselines will be collected and cached for future use.
        allCommitMetrics = get_perf_stats(
                                currentCommit,
                                namespace(useCiNamespace))

        # Collect recorded values by cacheKeyB.
        values_by_cache_key_b = {}
        for perfStat in allCommitMetrics:
            currentCacheKey = (perfStat.test_env, perfStat.test, \
                               perfStat.metric, perfStat.way)
            currentValues = values_by_cache_key_b.setdefault(currentCacheKey, [])
            currentValues.append(float(perfStat.value))

        # Calculate and baseline (average of values) by cacheKeyB.
        baseline_by_cache_key_b = {}
        for currentCacheKey, currentValues in values_by_cache_key_b.items():
            baseline_by_cache_key_b[currentCacheKey] = Baseline( \
                PerfStat( \
                    currentCacheKey[0],
                    currentCacheKey[1],
                    currentCacheKey[3],
                    currentCacheKey[2],
                    sum(currentValues) / len(currentValues)),
                currentCommit,
                depth)

        # Save baselines to the cache.
        _commit_metric_cache[cacheKeyA] = baseline_by_cache_key_b
        return baseline_by_cache_key_b.get(cacheKeyB)

    # Searches through previous commits trying local then ci for each commit in.
    def search(useCiNamespace, depth):
        # Stop if reached the max search depth.
        if depth >= BaselineSearchDepth:
            return None

        # Check for a metric on this commit.
        current_metric = commit_metric(useCiNamespace, depth)
        if current_metric != None:
            return current_metric

        # Metric is not available.
        # If tried local, now try CI.
        if not useCiNamespace:
            return search(True, depth)

        # Stop if there is an expected change at this commit. In that case
        # metrics on ancestor commits will not be a valid baseline.
        if has_expected_change(depth_to_commit(depth)):
            return None

        # Move to the parent commit.
        return search(False, depth + 1)

    # Start search from parent commit using local name space.
    return search(False, 1)