blob: 0a16b1c3a7121c2432e90b533e56cd569488f688 [file]
# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""GPU-specific implementation of the unexpected passes' queries module."""
from typing import Iterable, Optional
from unexpected_passes_common import queries as queries_module
from gpu_tests import gpu_integration_test
# This query gets us the most recent |num_builds| CI builds from the past month
# for each builder.
CI_BUILDS_SUBQUERY = """\
builds AS (
WITH
all_builds AS (
SELECT
DISTINCT exported.id AS build_inv_id,
variant.*,
partition_time
FROM
`chrome-luci-data.{project}.gpu_ci_test_results` AS tr,
UNNEST(variant) AS variant
WHERE
DATE(partition_time) > DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
AND exported.realm = "{project}:ci"
AND key = "builder"
),
grouped_builds AS (
SELECT
build_inv_id,
value AS builder,
partition_time,
RANK() OVER (
PARTITION BY value ORDER BY partition_time DESC
) AS rank_idx,
FROM all_builds
)
SELECT
build_inv_id,
builder,
partition_time
FROM grouped_builds
WHERE rank_idx <= {num_builds}
)"""
# The same as CI_BUILDS_SUBQUERY, but takes into account submitted builds for
# tryjobs.
TRY_BUILDS_SUBQUERY = """\
builds AS (
WITH
all_builds AS (
SELECT
DISTINCT exported.id AS build_inv_id,
variant.*,
partition_time
FROM
`chrome-luci-data.{project}.gpu_try_test_results` AS tr,
UNNEST(variant) AS variant,
submitted_builds sb
WHERE
DATE(partition_time) > DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
AND exported.realm = "{project}:try"
AND key = "builder"
AND exported.id = sb.id
),
grouped_builds AS (
SELECT
build_inv_id,
value AS builder,
partition_time,
RANK() OVER (
PARTITION BY value ORDER BY partition_time DESC
) AS rank_idx,
FROM all_builds
)
SELECT
build_inv_id,
builder,
partition_time
FROM grouped_builds
WHERE rank_idx <= {num_builds}
)"""
# step_name can be either the step_name tag or test_suite variant because of the
# way Skylab builders work. In normal Chromium test tasks, the step name is
# reported to the task-level RDB invocation, which then gets applied to every
# result that task reports. Skylab test steps are actually separate
# Buildbucket builds that report results a bit differently. They do not report
# a step_name tag, but do put the same information in for the test_suite
# variant. So, we will look for step_name first to cover most builders and fall
# back to test_suite for Skylab builders.
RESULTS_SUBQUERY = """\
results AS (
SELECT
exported.id,
test_id,
test_metadata.name as test_name,
status,
(
SELECT value
FROM tr.variant
WHERE key = "builder"
) as builder_name,
IFNULL(
(
SELECT value
FROM tr.tags
WHERE key = "step_name"),
(
SELECT value
FROM tr.variant
WHERE key = "test_suite")) as step_name,
ARRAY(
SELECT value
FROM tr.tags
WHERE key = "typ_tag") as typ_tags,
ARRAY(
SELECT value
FROM tr.tags
WHERE key = "raw_typ_expectation") as typ_expectations
FROM
`chrome-luci-data.{project}.gpu_{ci_or_try}_test_results` tr,
builds b
WHERE
DATE(tr.partition_time) > DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
AND exported.id = build_inv_id
AND status != "SKIP"
AND STRUCT("gpu_test_class", "{suite_class}") IN UNNEST(tags)
)"""
# Selects the relevant columns from results that had either a Failure or a
# RetryOnFailure expectation when they were run, ordered by builder name.
FINAL_SELECTOR_QUERY = """\
SELECT id, test_id, test_name, builder_name, status, step_name, typ_tags
FROM results
WHERE
"Failure" IN UNNEST(typ_expectations)
OR "RetryOnFailure" IN UNNEST(typ_expectations)
ORDER BY builder_name DESC"""
def _PartitionedSubmittedBuildsFor(project_view: str) -> str:
return queries_module.PARTITIONED_SUBMITTED_BUILDS_TEMPLATE.format(
project_view=project_view
)
# Gets the Buildbucket IDs for all the public trybots that:
# 1. Run GPU tests
# 2. Were used for CL submission (i.e. weren't for intermediate patchsets)
PUBLIC_TRY_SUBMITTED_BUILDS_SUBQUERY = f"""\
submitted_builds AS (
{_PartitionedSubmittedBuildsFor('chromium')}
UNION ALL
{_PartitionedSubmittedBuildsFor('angle')}
)"""
# The same as PUBLIC_TRY_SUBMITTED_BUILDS_SUBQUERY, but for internal trybots.
# There are no internal ANGLE tryjobs, so no need to look for attempts there.
INTERNAL_TRY_SUBMITTED_BUILDS_SUBQUERY = f"""\
submitted_builds AS (
{_PartitionedSubmittedBuildsFor('chrome')}
)"""
class GpuBigQueryQuerier(queries_module.BigQueryQuerier):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
name_mapping = gpu_integration_test.GenerateTestNameMapping()
_suite_class = name_mapping[self._suite]
# __qualname__ returns the same value as __name__, so we need to manually
# construct the qualified name.
self._qualified_class_name = (
f'{_suite_class.__module__}.{_suite_class.__name__}'
)
def _CiBuildsFor(self, project: str) -> str:
"""Helper function to generate a CI builds subquery."""
return CI_BUILDS_SUBQUERY.format(
project=project, num_builds=self._num_samples
)
def _TryBuildsFor(self, project: str) -> str:
"""Helper function to generate a try builds subquery."""
return TRY_BUILDS_SUBQUERY.format(
project=project, num_builds=self._num_samples
)
def _ResultsFor(self, project: str, ci_or_try: str) -> str:
"""Helper function to generate a results subquery."""
return RESULTS_SUBQUERY.format(
project=project,
ci_or_try=ci_or_try,
suite_class=self._qualified_class_name,
)
def _GetPublicCiQuery(self) -> str:
return f"""\
WITH
{self._CiBuildsFor('chromium')},
{self._ResultsFor('chromium', 'ci')}
{FINAL_SELECTOR_QUERY}
"""
def _GetInternalCiQuery(self) -> str:
return f"""\
WITH
{self._CiBuildsFor('chrome')},
{self._ResultsFor('chrome', 'ci')}
{FINAL_SELECTOR_QUERY}
"""
def _GetPublicTryQuery(self) -> str:
return f"""\
WITH
{PUBLIC_TRY_SUBMITTED_BUILDS_SUBQUERY},
{self._TryBuildsFor('chromium')},
{self._ResultsFor('chromium', 'try')}
{FINAL_SELECTOR_QUERY}
"""
def _GetInternalTryQuery(self) -> str:
return f"""\
WITH
{INTERNAL_TRY_SUBMITTED_BUILDS_SUBQUERY},
{self._TryBuildsFor('chrome')},
{self._ResultsFor('chrome', 'try')}
{FINAL_SELECTOR_QUERY}
"""
def _GetRelevantExpectationFilesForQueryResult(
self, _: queries_module.QueryResult
) -> Optional[Iterable[str]]:
# Only one expectation file is ever used for the GPU tests, so just use
# whichever one we've read in.
return None