blob: 6e65888a1c744a181af4c1c052ecc1f2664ade20 [file] [log] [blame]
import argparse
import re
from common import download_reports, get_testcases, key, open_test_results, skipped_test
from passrate import compute_pass_rate
"""
python failures_histogram.py commit_sha
Analyzes skip reasons for Dynamo tests and prints a histogram with repro
commands. You'll need to provide the commit_sha for a commit on the main branch,
from which we will pull CI test results.
This script requires the `gh` cli. You'll need to install it and then
authenticate with it via `gh auth login` before using this script.
https://docs.github.com/en/github-cli/github-cli/quickstart
"""
def skip_reason(testcase):
for child in testcase.iter():
if child.tag != "skipped":
continue
return child.attrib["message"]
raise AssertionError("no message?")
def skip_reason_normalized(testcase):
for child in testcase.iter():
if child.tag != "skipped":
continue
result = child.attrib["message"].split("\n")[0]
result = result.split(">")[0]
result = re.sub(r"0x\w+", "0xDEADBEEF", result)
result = re.sub(r"MagicMock id='\d+'", "MagicMock id='0000000000'", result)
result = re.sub(r"issues/\d+", "issues/XXX", result)
result = re.sub(r"torch.Size\(\[.*\]\)", "torch.Size([...])", result)
result = re.sub(
r"Could not get qualified name for class '.*'",
"Could not get qualified name for class",
result,
)
return result
raise AssertionError("no message?")
def get_failures(testcases):
skipped = [t for t in testcases if skipped_test(t)]
skipped_dict = {}
for s in skipped:
reason = skip_reason_normalized(s)
if reason not in skipped_dict:
skipped_dict[reason] = []
skipped_dict[reason].append(s)
result = []
for s, v in skipped_dict.items():
result.append((len(v), s, v))
result.sort(reverse=True)
return result
def repro(testcase):
return f"PYTORCH_TEST_WITH_DYNAMO=1 pytest {testcase.attrib['file']} -v -k {testcase.attrib['name']}"
def all_tests(testcase):
return f"{testcase.attrib['file']}::{testcase.attrib['classname']}.{testcase.attrib['name']}"
# e.g. "17c5f69852/eager", "17c5f69852/dynamo"
def failures_histogram(eager_dir, dynamo_dir, verbose=False, format_issues=False):
fail_keys = compute_pass_rate(eager_dir, dynamo_dir)
xmls = open_test_results(dynamo_dir)
testcases = get_testcases(xmls)
testcases = [t for t in testcases if key(t) in fail_keys]
dct = get_failures(testcases)
result = []
for count, reason, testcases in dct:
if verbose:
row = (
count,
reason,
repro(testcases[0]),
[all_tests(t) for t in testcases],
)
else:
row = (count, reason, repro(testcases[0]))
result.append(row)
header = (
"(num_failed_tests, error_msg, sample_test, all_tests)"
if verbose
else "(num_failed_tests, error_msg, sample_test)"
)
print(header)
sum_counts = sum(r[0] for r in result)
for row in result:
if format_issues:
print(as_issue(*row))
else:
print(row)
print("[counts]", sum_counts)
def as_issue(count, msg, repro, tests):
tests = "\n".join(tests)
result = f"""
{'-' * 50}
{count} Dynamo test are failing with \"{msg}\".
## Repro
`{repro}`
You will need to remove the skip or expectedFailure before running the repro command.
This may be just removing a sentinel file from in
[dynamo_expected_failures](https://github.com/pytorch/pytorch/blob/main/test/dynamo_expected_failures)
or [dynamo_skips](https://github.com/pytorch/pytorch/blob/main/test/dynamo_skips).
## Failing tests
Here's a comprehensive list of tests that fail (as of this issue) with the above message:
<details>
<summary>Click me</summary>
```
{tests}
```
</details>
"""
return result
if __name__ == "__main__":
parser = argparse.ArgumentParser(
prog="failures_histogram",
description="See statistics about skipped Dynamo tests",
)
parser.add_argument(
"commit",
help=(
"The commit sha for the latest commit on a PR from which we will "
"pull CI test results, e.g. 7e5f597aeeba30c390c05f7d316829b3798064a5"
),
)
parser.add_argument(
"-v", "--verbose", help="Prints all failing test names", action="store_true"
)
parser.add_argument(
"--format-issues",
help="Prints histogram in a way that they can be copy-pasted as a github issues",
action="store_true",
)
args = parser.parse_args()
# args.format_issues implies verbose=True
verbose = args.verbose
if args.format_issues:
verbose = True
dynamo311, eager311 = download_reports(args.commit, ("dynamo311", "eager311"))
failures_histogram(eager311, dynamo311, verbose, args.format_issues)