mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
Pull Request resolved: https://github.com/pytorch/pytorch/pull/129375 Approved by: https://github.com/malfet
237 lines
7.0 KiB
Python
237 lines
7.0 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess
|
|
from typing import IO, Tuple
|
|
|
|
from ..oss.utils import get_pytorch_folder
|
|
from ..util.setting import SUMMARY_FOLDER_DIR, TestList, TestStatusType
|
|
|
|
|
|
CoverageItem = Tuple[str, float, int, int]
|
|
|
|
|
|
def key_by_percentage(x: CoverageItem) -> float:
|
|
return x[1]
|
|
|
|
|
|
def key_by_name(x: CoverageItem) -> str:
|
|
return x[0]
|
|
|
|
|
|
def is_intrested_file(file_path: str, interested_folders: list[str]) -> bool:
|
|
if "cuda" in file_path:
|
|
return False
|
|
if "aten/gen_aten" in file_path or "aten/aten_" in file_path:
|
|
return False
|
|
for folder in interested_folders:
|
|
if folder in file_path:
|
|
return True
|
|
return False
|
|
|
|
|
|
def is_this_type_of_tests(target_name: str, test_set_by_type: set[str]) -> bool:
|
|
# tests are divided into three types: success / partial success / fail to collect coverage
|
|
for test in test_set_by_type:
|
|
if target_name in test:
|
|
return True
|
|
return False
|
|
|
|
|
|
def print_test_by_type(
|
|
tests: TestList, test_set_by_type: set[str], type_name: str, summary_file: IO[str]
|
|
) -> None:
|
|
print("Tests " + type_name + " to collect coverage:", file=summary_file)
|
|
for test in tests:
|
|
if is_this_type_of_tests(test.name, test_set_by_type):
|
|
print(test.target_pattern, file=summary_file)
|
|
print(file=summary_file)
|
|
|
|
|
|
def print_test_condition(
|
|
tests: TestList,
|
|
tests_type: TestStatusType,
|
|
interested_folders: list[str],
|
|
coverage_only: list[str],
|
|
summary_file: IO[str],
|
|
summary_type: str,
|
|
) -> None:
|
|
print_test_by_type(tests, tests_type["success"], "fully success", summary_file)
|
|
print_test_by_type(tests, tests_type["partial"], "partially success", summary_file)
|
|
print_test_by_type(tests, tests_type["fail"], "failed", summary_file)
|
|
print(
|
|
"\n\nCoverage Collected Over Interested Folders:\n",
|
|
interested_folders,
|
|
file=summary_file,
|
|
)
|
|
print(
|
|
"\n\nCoverage Compilation Flags Only Apply To: \n",
|
|
coverage_only,
|
|
file=summary_file,
|
|
)
|
|
print(
|
|
"\n\n---------------------------------- "
|
|
+ summary_type
|
|
+ " ----------------------------------",
|
|
file=summary_file,
|
|
)
|
|
|
|
|
|
def line_oriented_report(
|
|
tests: TestList,
|
|
tests_type: TestStatusType,
|
|
interested_folders: list[str],
|
|
coverage_only: list[str],
|
|
covered_lines: dict[str, set[int]],
|
|
uncovered_lines: dict[str, set[int]],
|
|
) -> None:
|
|
with open(os.path.join(SUMMARY_FOLDER_DIR, "line_summary"), "w+") as report_file:
|
|
print_test_condition(
|
|
tests,
|
|
tests_type,
|
|
interested_folders,
|
|
coverage_only,
|
|
report_file,
|
|
"LINE SUMMARY",
|
|
)
|
|
for file_name in covered_lines:
|
|
covered = covered_lines[file_name]
|
|
uncovered = uncovered_lines[file_name]
|
|
print(
|
|
f"{file_name}\n covered lines: {sorted(covered)}\n unconvered lines:{sorted(uncovered)}",
|
|
file=report_file,
|
|
)
|
|
|
|
|
|
def print_file_summary(
|
|
covered_summary: int, total_summary: int, summary_file: IO[str]
|
|
) -> float:
|
|
# print summary first
|
|
try:
|
|
coverage_percentage = 100.0 * covered_summary / total_summary
|
|
except ZeroDivisionError:
|
|
coverage_percentage = 0
|
|
print(
|
|
f"SUMMARY\ncovered: {covered_summary}\nuncovered: {total_summary}\npercentage: {coverage_percentage:.2f}%\n\n",
|
|
file=summary_file,
|
|
)
|
|
if coverage_percentage == 0:
|
|
print("Coverage is 0, Please check if json profiles are valid")
|
|
return coverage_percentage
|
|
|
|
|
|
def print_file_oriented_report(
|
|
tests_type: TestStatusType,
|
|
coverage: list[CoverageItem],
|
|
covered_summary: int,
|
|
total_summary: int,
|
|
summary_file: IO[str],
|
|
tests: TestList,
|
|
interested_folders: list[str],
|
|
coverage_only: list[str],
|
|
) -> None:
|
|
coverage_percentage = print_file_summary(
|
|
covered_summary, total_summary, summary_file
|
|
)
|
|
# print test condition (interested folder / tests that are successsful or failed)
|
|
print_test_condition(
|
|
tests,
|
|
tests_type,
|
|
interested_folders,
|
|
coverage_only,
|
|
summary_file,
|
|
"FILE SUMMARY",
|
|
)
|
|
# print each file's information
|
|
for item in coverage:
|
|
print(
|
|
item[0].ljust(75),
|
|
(str(item[1]) + "%").rjust(10),
|
|
str(item[2]).rjust(10),
|
|
str(item[3]).rjust(10),
|
|
file=summary_file,
|
|
)
|
|
|
|
print(f"summary percentage:{coverage_percentage:.2f}%")
|
|
|
|
|
|
def file_oriented_report(
|
|
tests: TestList,
|
|
tests_type: TestStatusType,
|
|
interested_folders: list[str],
|
|
coverage_only: list[str],
|
|
covered_lines: dict[str, set[int]],
|
|
uncovered_lines: dict[str, set[int]],
|
|
) -> None:
|
|
with open(os.path.join(SUMMARY_FOLDER_DIR, "file_summary"), "w+") as summary_file:
|
|
covered_summary = 0
|
|
total_summary = 0
|
|
coverage = []
|
|
for file_name in covered_lines:
|
|
# get coverage number for this file
|
|
covered_count = len(covered_lines[file_name])
|
|
total_count = covered_count + len(uncovered_lines[file_name])
|
|
try:
|
|
percentage = round(covered_count / total_count * 100, 2)
|
|
except ZeroDivisionError:
|
|
percentage = 0
|
|
# store information in a list to be sorted
|
|
coverage.append((file_name, percentage, covered_count, total_count))
|
|
# update summary
|
|
covered_summary = covered_summary + covered_count
|
|
total_summary = total_summary + total_count
|
|
# sort
|
|
coverage.sort(key=key_by_name)
|
|
coverage.sort(key=key_by_percentage)
|
|
# print
|
|
print_file_oriented_report(
|
|
tests_type,
|
|
coverage,
|
|
covered_summary,
|
|
total_summary,
|
|
summary_file,
|
|
tests,
|
|
interested_folders,
|
|
coverage_only,
|
|
)
|
|
|
|
|
|
def get_html_ignored_pattern() -> list[str]:
|
|
return ["/usr/*", "*anaconda3/*", "*third_party/*"]
|
|
|
|
|
|
def html_oriented_report() -> None:
|
|
# use lcov to generate the coverage report
|
|
build_folder = os.path.join(get_pytorch_folder(), "build")
|
|
coverage_info_file = os.path.join(SUMMARY_FOLDER_DIR, "coverage.info")
|
|
# generage coverage report -- coverage.info in build folder
|
|
subprocess.check_call(
|
|
[
|
|
"lcov",
|
|
"--capture",
|
|
"--directory",
|
|
build_folder,
|
|
"--output-file",
|
|
coverage_info_file,
|
|
]
|
|
)
|
|
# remove files that are unrelated
|
|
cmd_array = (
|
|
["lcov", "--remove", coverage_info_file]
|
|
+ get_html_ignored_pattern()
|
|
+ ["--output-file", coverage_info_file]
|
|
)
|
|
subprocess.check_call(
|
|
# ["lcov", "--remove", coverage_info_file, "--output-file", coverage_info_file]
|
|
cmd_array
|
|
)
|
|
# generate beautiful html page
|
|
subprocess.check_call(
|
|
[
|
|
"genhtml",
|
|
coverage_info_file,
|
|
"--output-directory",
|
|
os.path.join(SUMMARY_FOLDER_DIR, "html_report"),
|
|
]
|
|
)
|