diff --git a/easybuild/easyblocks/p/pytorch.py b/easybuild/easyblocks/p/pytorch.py index fdc787155c6..8a73b611c5e 100755 --- a/easybuild/easyblocks/p/pytorch.py +++ b/easybuild/easyblocks/p/pytorch.py @@ -39,7 +39,7 @@ from itertools import chain, groupby from operator import attrgetter from pathlib import Path -from typing import Dict, Iterable, List +from typing import Dict, Iterable, List, Optional import easybuild.tools.environment as env from easybuild.easyblocks.generic.pythonpackage import PythonPackage @@ -332,12 +332,17 @@ def is_version_ok(version_range): available_libs = ( # Format: (PyTorch flag to enable, EB name, ':') # Use `None` for the EB name if no known EC exists - ('USE_FFMPEG=1', 'FFmpeg', '1.0.0:'), + # Check the comment on top of setup.y + ('USE_FFMPEG=1', 'FFmpeg', '1.0.0:2.4.0'), ('USE_GFLAGS=1', 'gflags', '1.0.0:'), ('USE_GLOG=1', 'glog', '1.0.0:'), + ('USE_CUDSS=1', 'cuDSS', '1.0.0:'), + ('USE_CUSPARSELT=1', 'cuSPARSELt', '2.7:'), + ('USE_UCC=1', 'UCC-CUDA', '1.13.0:'), + ('USE_SYSTEM_UCC=1', 'UCC-CUDA', '1.13.0:'), # For system libs check CMakeLists.txt, below `if(USE_SYSTEM_LIBS)`, order kept here - # NCCL handled specially as other env variables are requires for it + # NCCL handled specially as other env variables are required for it ('USE_SYSTEM_CPUINFO=1', None, '1.6.0:'), ('USE_SYSTEM_SLEEF=1', None, '1.6.0:'), ('USE_SYSTEM_GLOO=1', None, '1.6.0:'), @@ -395,18 +400,19 @@ def configure_step(self): [(r'(default=_get_test_report_path\(\) if) IS(_IN)?_CI else None', fr'\1 os.getenv("{self.GENERATE_TEST_REPORT_VAR_NAME}") else None')], backup=False, on_missing_match=ERROR) - if pytorch_version >= '2.1.0': - run_test_subs = [(r'if IS_CI:\n\s+# Add the option to generate XML test report.*', - 'if TEST_SAVE_XML:\n')] - else: - run_test_subs = [ - (r'from torch.testing._internal.common_utils import\s+\(\n\s+', - r'\g<0>get_report_path, '), - (r'# If using pytest.*\n\s+if options.pytest:\n\s+unittest_args = \[', - r'\g<0>"--junit-xml-reruns", get_report_path(pytest=True)] + ['), - ] - apply_regex_substitutions('test/run_test.py', run_test_subs, backup=False, on_missing_match=ERROR, - single_line=False) + if pytorch_version < '2.8.0': + if pytorch_version >= '2.1.0': + run_test_subs = [(r'if IS_CI:\n\s+# Add the option to generate XML test report.*', + 'if TEST_SAVE_XML:\n')] + else: + run_test_subs = [ + (r'from torch.testing._internal.common_utils import\s+\(\n\s+', + r'\g<0>get_report_path, '), + (r'# If using pytest.*\n\s+if options.pytest:\n\s+unittest_args = \[', + r'\g<0>"--junit-xml-reruns", get_report_path(pytest=True)] + ['), + ] + apply_regex_substitutions('test/run_test.py', run_test_subs, backup=False, on_missing_match=ERROR, + single_line=False) self.has_xml_test_reports = True # Gather default options. Will be checked against (and can be overwritten by) custom_opts @@ -448,7 +454,7 @@ def add_enable_option(name, enabled): raise EasyBuildError("Did not find a supported BLAS in dependencies. Don't know which BLAS lib to use") available_dependency_options = EB_PyTorch.get_dependency_options_for_version(self.version) - dependency_names = {dep['name'] for dep in self.cfg.dependencies()} + dependency_names = self.cfg.dependency_names() not_used_dep_names = [] for enable_opt, dep_name in available_dependency_options: if dep_name is None: @@ -457,6 +463,9 @@ def add_enable_option(name, enabled): options.append(enable_opt) else: not_used_dep_names.append(dep_name) + # Explicitely toggle to avoid picking up system libs, restricted to 2.7+ to avoid retesting older ECs + if pytorch_version >= '2.7' and enable_opt[-1] in ('0', '1'): + options.append(enable_opt[:-1] + ('0' if enable_opt[-1] == '1' else '1')) self.log.info('Did not enable options for the following dependencies as they are not used in the EC: %s', not_used_dep_names) @@ -510,7 +519,8 @@ def add_enable_option(name, enabled): options.append('USE_FBGEMM=0') # Metal only supported on IOS which likely doesn't work with EB, so disabled - options.append('USE_METAL=0') + if pytorch_version < '2.4': # Removed in 2.4 + options.append('USE_METAL=0') build_type = self.cfg.get('build_type') if build_type is None: @@ -538,15 +548,18 @@ def add_enable_option(name, enabled): self.cfg.update('prebuildopts', ' '.join(unique_options) + ' ') self.cfg.update('preinstallopts', ' '.join(unique_options) + ' ') - def _set_cache_dir(self): - """Set $XDG_CACHE_HOME and $TRITON_HOME to avoid PyTorch defaulting to $HOME""" + def _set_cache_dirs(self): + """Set $XDG_CACHE_HOME and $TRITON_HOME to avoid PyTorch defaulting to $HOME + and similar variables to ensure clean build/test environment + """ cache_dir = os.path.join(self.tmpdir, '.cache') # The path must exist! mkdir(cache_dir, parents=True) env.setvar('XDG_CACHE_HOME', cache_dir) # Triton also uses a path defaulting to $HOME - # Isolate against user-set variables - env.unset_env_vars(('TRITON_DUMP_DIR', 'TRITON_OVERRIDE_DIR', 'TRITON_CACHE_DIR')) + # Isolate against user-set variables which could lead to reusing caches that may fail test + env.unset_env_vars(('TRITON_DUMP_DIR', 'TRITON_OVERRIDE_DIR', 'TRITON_CACHE_DIR', + 'TORCH_HOME', 'TORCHINDUCTOR_CACHE_DIR', 'PYTORCH_KERNEL_CACHE_PATH')) triton_home = os.path.join(self.tmpdir, '.triton_home') env.setvar('TRITON_HOME', triton_home) @@ -599,7 +612,7 @@ def get_test_name_diff(lst_should, lst_is): def test_step(self): """Run unit tests""" - self._set_cache_dir() + self._set_cache_dirs() # Pretend to be on FB CI which disables some tests, especially those which download stuff env.setvar('SANDCASTLE', '1') # Skip this test(s) which is very flaky @@ -637,7 +650,7 @@ def test_step(self): try: xml_results = get_test_results(test_reports_path) except ValueError as e: - raise EasyBuildError(f"Failed to parse test results at {test_reports_path}: {e}") + raise EasyBuildError(f"Failed to parse test results at {test_reports_path}: {e}") from e if not xml_results: files = [file for file in test_reports_path.rglob('*.*') if file.is_file()] if files: @@ -645,8 +658,17 @@ def test_step(self): else: msg = f'Failed to find any test report files at {test_reports_path}' raise EasyBuildError(msg) + + def suite_is_in_xml_results(suite_name): + """Check if the suite is in the XML results""" + if suite_name in xml_results: + return True + # Handle variants like dist-nccl/test_c10d_nccl + return any(xml_suite_name.split(os.path.sep, maxsplit=1)[-1] == suite_name + for xml_suite_name in xml_results if xml_suite_name.startswith('dist-')) + missing_suites = [suite.name for suite in parsed_test_result.failed_suites - if suite.name not in xml_results] + if not suite_is_in_xml_results(suite.name)] if missing_suites: raise EasyBuildError('Parsing the test result files missed the following failed suites: %s', ', '.join(sorted(missing_suites))) @@ -771,7 +793,7 @@ def test_step(self): raise EasyBuildError("Test command had non-zero exit code (%s), but no failed tests found?!", tests_ec) def test_cases_step(self): - self._set_cache_dir() + self._set_cache_dirs() super().test_cases_step() def sanity_check_step(self, *args, **kwargs): @@ -897,7 +919,12 @@ def parse_test_cases(test_suite_el: ET.Element) -> List[TestCase]: """Extract all test cases from the testsuite XML element""" test_cases: List[TestCase] = [] for testcase in test_suite_el.iterfind("testcase"): - classname = testcase.attrib["classname"] + try: + classname = testcase.attrib["classname"] + except KeyError as e: + if any(tag in testcase.attrib for tag in ('name', 'file')): + raise ValueError(f"Missing 'classname' attribute in testcase (Attributes: '{testcase.attrib}')") from e + continue # Skip invalid testcase entries without classname test_name = f'{classname}.{testcase.attrib["name"]}' # Note: It is possible that a test has (the same?) element multiple times, likely when using variants. # Ignore that and only check if it has one of the failure tags at least once. @@ -905,8 +932,8 @@ def parse_test_cases(test_suite_el: ET.Element) -> List[TestCase]: num_reruns = len(testcase.findall("rerun")) if skipped: - if num_reruns > 0 or failed or errored: - raise ValueError(f"Invalid state for testcase '{test_name}'") + if failed or errored: + raise ValueError(f"Invalid state for testcase '{test_name}': Both skipped and failed/errored") state = TestState.SKIPPED else: state = TestState.FAILURE if failed else TestState.ERROR if errored else TestState.SUCCESS @@ -915,20 +942,27 @@ def parse_test_cases(test_suite_el: ET.Element) -> List[TestCase]: return test_cases -def determine_suite_name(xml_file: Path, test_suite_xml: List[ET.Element]) -> str: +def determine_suite_name(xml_file: Path, test_suite_xml: List[ET.Element]) -> Optional[str]: """Determine main test suite name from path(s) to match against run_test.py output""" # Gather all file attributes from the test cases if set test_cases = [testcase for suite in test_suite_xml for testcase in suite.iterfind("testcase")] - file_attribute = {testcase.attrib.get("file") for testcase in test_cases} - file_attribute.discard(None) suite_name = xml_file.parent.name.replace('.', os.path.sep) # Usually the suite name is the folder name + if xml_file.name.startswith('TEST-'): + # A unittest test could be run directly (`python -c 'code...'`) in which case there is no name + if suite_name == '-c': + return None # Python unittest reports have 1 file per test class: # test-reports/python-unittest/test_package/TEST-test_repackage.TestRepackage-20250217120914.xml # -> test_repackage.py ran TestRepackage # test-reports/dist-gloo/distributed.algorithms.test_quantization/TEST-DistQuantizationTests-20250123170925.xml # -> distributed/algorithms/test_quantization ran DistQuantizationTests in dist-gloo variant # Just do a sanity check + file_attribute = {testcase.attrib.get("file") for testcase in test_cases} + file_attribute.discard(None) + if not file_attribute: # Fallback to checking the tags + file_attribute = {suite.attrib.get("file") for suite in test_suite_xml} + file_attribute.discard(None) if len(file_attribute) > 1: raise ValueError(f"Found multiple reported files in unittest report of '{xml_file}': {file_attribute}") reported_file = os.path.basename(file_attribute.pop()) @@ -936,11 +970,12 @@ def determine_suite_name(xml_file: Path, test_suite_xml: List[ET.Element]) -> st name_parts = xml_file.name[len('TEST-'):].rsplit('-', 1)[0].rsplit('.', 2) # If there is only one part it is the class -> filename is in the suite name if len(name_parts) == 1: - test_file_name = os.path.basename(suite_name) + '.py' + test_file_name = os.path.basename(suite_name) else: # Note that multiple parts are possible for sub-test files: # TEST-jit.test_builtins.TestBuiltins (jit/test_builtins.py) - test_file_name = name_parts[-2] + '.py' + test_file_name = name_parts[-2] + test_file_name += '.py' if test_file_name != reported_file: raise ValueError(f"Unexpected file attributes in test cases of '{xml_file}'. " f"Expected {test_file_name}, got {file_attribute}") @@ -964,7 +999,7 @@ def extract_path(classname: str) -> str: # We can remove possible class names by only using the common part suite_name = os.path.commonpath(possible_paths) # Strip of common prefix to all classes, but keep the last part for uniqueness - non_classname_prefix = os.path.dirname(suite_name).replace(os.path.sep, '.') + '.' + non_classname_prefix = 'test.' + os.path.dirname(suite_name).replace(os.path.sep, '.') + '.' for testcase in test_cases: classname = testcase.attrib["classname"] if classname.startswith(non_classname_prefix): @@ -992,7 +1027,12 @@ def parse_test_result_file(xml_file: Path) -> List[TestSuite]: :return: A list of TestSuite objects representing the parsed structure. """ try: - root = ET.parse(xml_file).getroot() + try: + root = ET.parse(xml_file).getroot() + except ET.ParseError: + if ' List[TestSuite]: # Suite name to correctly deduplicate tests and match against run_test.py output suite_name = determine_suite_name(xml_file, test_suite_xml) + if suite_name is None: + return [] test_suites: List[TestSuite] = [] @@ -1017,9 +1059,10 @@ def parse_test_result_file(xml_file: Path) -> List[TestSuite]: # when unittest's `subTest` is used: https://github.com/xmlrunner/unittest-xml-reporting/issues/292 num_tests = int(test_suite.attrib["tests"]) # But it needs to be at least consistent with the "non-passing" test numbers - if num_tests < failures + skipped + errors: + # A test that failed AND errored might not be counted twice, so don't add failures and errors + if num_tests < max(failures, errors) + skipped: raise ValueError(f"Invalid test count: " - f"{num_tests} tests, {failures} failures, {skipped} skipped, {errors} errors") + f"{num_tests} tests vs {failures} failures, {skipped} skipped, {errors} errors") parsed_test_cases = parse_test_cases(test_suite) if not parsed_test_cases: @@ -1030,9 +1073,15 @@ def parse_test_result_file(xml_file: Path) -> List[TestSuite]: test_cases: Dict[str, TestCase] = {} for test_case in parsed_test_cases: - if test_case.name in test_cases: - raise ValueError(f"Duplicate test case '{test_case}' in test suite {suite_name}") - test_cases[test_case.name] = test_case + try: + old_test_case = test_cases[test_case.name] + except KeyError: + # No test with that name yet, so add it + test_cases[test_case.name] = test_case + else: + # Ignore the case where a test failed and errored which might happen if teardown fails + if {old_test_case.state, test_case.state} != {TestState.ERROR, TestState.FAILURE}: + raise ValueError(f"Duplicate test case '{test_case}' in test suite {suite_name}") test_suites.append( TestSuite(name=suite_name, test_cases=test_cases, @@ -1040,7 +1089,7 @@ def parse_test_result_file(xml_file: Path) -> List[TestSuite]: ) ) except Exception as e: - raise ValueError(f"Failed to parse test result file '{xml_file}': {e}") + raise ValueError(f"Failed to parse test result file '{xml_file}': {e}") from e return test_suites @@ -1058,11 +1107,11 @@ def merge_test_suites(test_suites: Iterable[TestSuite]) -> TestSuite: except KeyError: result_suite.add_test(current_test) else: - if (existing_test.state == TestState.SKIPPED) != (current_test.state == TestState.SKIPPED): - raise ValueError(f"Mismatch in whether test was skipped or not in suite {result_suite.name}: " - f"{existing_test} vs. {current_test}") - # If test was rerun and succeeded use that if current_test.state == TestState.SUCCESS and existing_test.state != TestState.SUCCESS: + # If test was rerun and succeeded use that + result_suite.replace_test(current_test) + elif existing_test.state == TestState.SKIPPED and current_test.state != TestState.SKIPPED: + # If test was skipped but later run use that result_suite.replace_test(current_test) return result_suite @@ -1084,6 +1133,13 @@ def get_test_results(folder: Path) -> Dict[str, TestSuite]: def main(arg: Path): + # Get attribute on which to sort suites + try: + sort_key = sys.argv[sys.argv.index('--sort') + 1] + except ValueError: + sort_key = next((arg.split('=', 1)[1] for arg in sys.argv if arg.startswith('--sort=')), None) + if not sort_key: + sort_key = 'name' if arg.is_file(): content = arg.read_text() m = re.search(r'cmd .*python[^ ]* run_test\.py .* exited with exit code.*output', content) @@ -1103,15 +1159,17 @@ def main(arg: Path): raise RuntimeError(msg) else: results = get_test_results(Path(arg)) - print(f"Found {len(results)} test suites:") - for suite in results.values(): - print(f"Suite {suite.name} {suite.num_tests}:\t{suite.summary}") + print(f"Found {len(results)} test suites (sorted by {sort_key}):") + sorted_suites = sorted(results.values(), key=lambda suite: getattr(suite, sort_key)) + for suite in sorted_suites: + print(f"Suite {suite.name}:\t{suite.num_tests} tests, {suite.summary}") print("Total tests:", sum(suite.num_tests for suite in results.values())) print("Total failures:", sum(suite.failures for suite in results.values())) print("Total skipped:", sum(suite.skipped for suite in results.values())) print("Total errors:", sum(suite.errors for suite in results.values())) - failed_suites = [suite.name for suite in results.values() if suite.failures + suite.errors > 0] - print(f"Failed suites ({len(failed_suites)}):\n\t" + '\n\t'.join(sorted(failed_suites))) + failed_suites = [suite for suite in sorted_suites if suite.failures + suite.errors > 0] + print(f"Failed suites ({len(failed_suites)}):\n\t" + '\n\t'.join( + f'{suite.name} ({suite.failures + suite.errors}/{suite.num_tests})' for suite in failed_suites)) failed_tests = sum((suite.get_failed_tests() for suite in results.values()), []) print(f"Failed tests ({len(failed_tests)}):\n\t" + '\n\t'.join(sorted(failed_tests))) errored_tests = sum((suite.get_errored_tests() for suite in results.values()), []) diff --git a/test/easyblocks/easyblock_specific.py b/test/easyblocks/easyblock_specific.py index 6c5a76aa0c6..d5004c1ae87 100644 --- a/test/easyblocks/easyblock_specific.py +++ b/test/easyblocks/easyblock_specific.py @@ -35,6 +35,7 @@ import tempfile import textwrap from io import StringIO +from pathlib import Path from unittest import TestLoader, TextTestRunner from test.easyblocks.module import cleanup @@ -42,6 +43,7 @@ import easybuild.easyblocks.generic.pythonpackage as pythonpackage import easybuild.easyblocks.l.lammps as lammps import easybuild.easyblocks.p.python as python +import easybuild.easyblocks.p.pytorch as pytorch from easybuild.base.testing import TestCase from easybuild.easyblocks.generic.cmakemake import det_cmake_version from easybuild.easyblocks.generic.toolchain import Toolchain @@ -495,8 +497,8 @@ def test_translate_lammps_version(self): '29Aug2024_update2': '2024.08.29.2', '28Oct2024': '2024.10.28', } - for key in lammps_versions: - self.assertEqual(lammps.translate_lammps_version(key), lammps_versions[key]) + for key, expected_version in lammps_versions.items(): + self.assertEqual(lammps.translate_lammps_version(key), expected_version) version_file = os.path.join(self.tmpdir, 'src', 'version.h') version_txt = '\n'.join([ @@ -517,6 +519,166 @@ def test_translate_lammps_version(self): self.assertEqual(lammps.translate_lammps_version('d3adb33f', path=self.tmpdir), '2025.04.02.3') + def test_pytorch_test_log_parsing(self): + """Verify parsing of XML files produced by PyTorch tests.""" + TestState = pytorch.TestState + + test_log_dir = Path(__file__).parent.parent / 'pytorch_test_logs' + + results = pytorch.get_test_results(test_log_dir / 'test-reports') + results2 = pytorch.get_test_results(test_log_dir) + self.assertEqual(results.keys(), results2.keys()) + for name, suite in results.items(): + self.assertEqual((name, suite.summary), (name, results2[name].summary)) + del results2 + + self.assertEqual(len(results), 15) + + # 2 small test suites used as a smoke test using a most features + self.assertIn('backends/xeon/test_launch', results) + suite = results['backends/xeon/test_launch'] + self.assertEqual((suite.errors, suite.failures, suite.num_tests, suite.skipped), (1, 2, 8, 3)) + # Failure in one file, success in the other --> Success + self.assertEqual(suite['TestTorchrun.test_cpu_info'].state, TestState.SUCCESS) + # New in 2nd file + self.assertEqual(suite['TestTorchrun.test_multi_threads'].state, TestState.SUCCESS) + self.assertEqual(suite['TestTorchrun.test_reshape_cpu_float64'].state, TestState.FAILURE) + self.assertEqual(suite['TestTorchrun.test_foo'].state, TestState.SKIPPED) + self.assertEqual(suite['TestTorchrun.test_bar'].state, TestState.ERROR) + self.assertEqual(suite.get_errored_tests(), ['TestTorchrun.test_bar']) + self.assertEqual(suite.get_failed_tests(), ['TestTorchrun.test_reshape_cpu_float64', 'TestTorchrun.test_baz']) + self.assertIn('test_autoload', results) + suite = results['test_autoload'] + self.assertEqual((suite.errors, suite.failures, suite.num_tests, suite.skipped), (0, 0, 2, 1)) + self.assertEqual(suite['TestBackendAutoload.test_autoload'].state, TestState.SUCCESS) + self.assertEqual(suite['TestBackendAutoload.test_unload'].state, TestState.SKIPPED) + + # Verify summaries which should be enough to catch most issues + report = '\n'.join(sorted(f'{suite.name}: {suite.summary}' for suite in results.values())) + self.assertEqual(report, textwrap.dedent(""" + backends/xeon/test_launch: 2 failed, 2 passed, 3 skipped, 1 errors + dist-gloo-init-env/distr/algorithms/quantization/test_quantization: 0 failed, 1 passed, 0 skipped, 0 errors + dist-gloo-init-file/distr/algorithms/quantization/test_quantization: 0 failed, 1 passed, 0 skipped, 0 errors + dist-nccl-init-env/distr/algorithms/quantization/test_quantization: 0 failed, 1 passed, 0 skipped, 0 errors + dist-nccl-init-file/distr/algorithms/quantization/test_quantization: 0 failed, 1 passed, 0 skipped, 0 errors + dist/foo/bar: 0 failed, 4 passed, 0 skipped, 0 errors + distributed/tensor/test_dtensor_ops: 0 failed, 2 passed, 2 skipped, 0 errors + dynamo/test_dynamic_shapes: 3 failed, 14 passed, 0 skipped, 0 errors + dynamo/test_misc: 1 failed, 9 passed, 0 skipped, 0 errors + inductor/test_aot_inductor_arrayref: 2 failed, 0 passed, 0 skipped, 0 errors + inductor/test_cudagraph_trees: 1 failed, 0 passed, 0 skipped, 0 errors + jit/test_builtins: 0 failed, 1 passed, 0 skipped, 0 errors + test_autoload: 0 failed, 1 passed, 1 skipped, 0 errors + test_nestedtensor: 3 failed, 2 passed, 3 skipped, 1 errors + test_quantization: 0 failed, 12 passed, 5 skipped, 0 errors + """).strip()) + tests = '\n'.join(sorted(f'{test.name}: {test.state.value}' + for suite in results.values() + for test in suite.get_tests())) + self.assertEqual(tests, textwrap.dedent(""" + AOTInductorTestABICompatibleCpuWithStackAllocation.test_fail_and_skip: failure + AOTInductorTestABICompatibleCpuWithStackAllocation.test_skip_and_fail: failure + CudaGraphTreeTests.test_workspace_allocation_error: failure + DistQuantizationTests.test_all_gather_fp16: success + DistQuantizationTests.test_all_gather_fp16: success + DistQuantizationTests.test_all_gather_fp16: success + DistQuantizationTests.test_all_gather_fp16: success + DynamicShapesCtxManagerTests.test_autograd_profiler_dynamic_shapes: success + DynamicShapesCtxManagerTests.test_generic_context_manager_with_graph_break_dynamic_shapes: success + DynamicShapesCtxManagerTests.test_generic_ctx_manager_with_graph_break_dynamic_shapes: success + DynamicShapesMiscTests.test_outside_linear_module_free_dynamic_shapes: failure + DynamicShapesMiscTests.test_packaging_version_parse_dynamic_shapes: success + DynamicShapesMiscTests.test_pair_dynamic_shapes: success + DynamicShapesMiscTests.test_param_shape_binops_dynamic_shapes: success + DynamicShapesMiscTests.test_parameter_free_dynamic_shapes: failure + DynamicShapesMiscTests.test_patched_builtin_functions_dynamic_shapes: success + DynamicShapesMiscTests.test_proxy_frozen_dataclass_dynamic_shapes: success + DynamicShapesMiscTests.test_pt2_compliant_ops_are_allowed_dynamic_shapes: success + DynamicShapesMiscTests.test_pt2_compliant_overload_dynamic_shapes: success + DynamicShapesMiscTests.test_pure_python_accumulate_dynamic_shapes: success + DynamicShapesMiscTests.test_py_guards_mark_dynamic_dynamic_shapes: success + DynamicShapesMiscTests.test_python_slice_dynamic_shapes: success + DynamicShapesMiscTests.test_pytree_tree_flatten_unflatten_dynamic_shapes: success + DynamicShapesMiscTests.test_pytree_tree_leaves_dynamic_shapes: failure + MiscTests.test_packaging_version_parse: success + MiscTests.test_pair: success + MiscTests.test_param_shape_binops: success + MiscTests.test_parameter_free: failure + MiscTests.test_pytree_tree_map: success + MiscTests.test_shape_env_no_recording: success + MiscTests.test_shape_env_recorded_function_fallback: success + MiscTests.test_yield_from_in_a_loop: success + TestBackendAutoload.test_autoload: success + TestBackendAutoload.test_unload: skipped + TestBuiltins.test_name: success + TestCustomFunction.test_autograd_function_with_matmul_folding_at_output: success + TestDTensorOpsCPU.test_dtensor_op_db_H_cpu_float16: success + TestDTensorOpsCPU.test_dtensor_op_db_H_cpu_float32: success + TestDTensorOpsCPU.test_dtensor_op_db_H_cpu_float64: skipped + TestDTensorOpsCPU.test_dtensor_op_db_H_cpu_int8: skipped + TestDynamicQuantizedOps.test_qrnncell: success + TestFakeQuantizeOps.test_backward_per_channel: skipped + TestFakeQuantizeOps.test_backward_per_channel_cachemask_cpu: success + TestFakeQuantizeOps.test_backward_per_channel_cachemask_cuda: success + TestName.test_bar: success + TestNestedTensor.test_bmm_cuda_gpu_float16: failure + TestNestedTensor.test_bmm_cuda_gpu_float32: failure + TestNestedTensor.test_bmm_cuda_gpu_float64: error + TestNestedTensor.test_cat: success + TestNestedTensor.test_copy_: success + TestNestedTensor.test_reshape_cpu_float16: skipped + TestNestedTensor.test_reshape_cpu_float32: skipped + TestNestedTensor.test_reshape_cpu_float64: failure + TestNestedTensorSubclassCPU.test_linear_backward_memory_usage_cpu_float32: skipped + TestNumericDebugger.test_quantize_pt2e_preserve_handle: success + TestNumericDebugger.test_re_export_preserve_handle: success + TestPadding.test_reflection_pad1d: success + TestQuantizedConv.test_conv_reorder_issue_onednn: success + TestQuantizedConv.test_conv_transpose_reorder_issue_onednn: success + TestQuantizedFunctionalOps.test_relu_api: success + TestQuantizedLinear.test_qlinear_cudnn: skipped + TestQuantizedLinear.test_qlinear_gelu_pt2e: success + TestQuantizedOps.test_adaptive_avg_pool2d_nhwc: success + TestQuantizedOps.test_adaptive_avg_pool: skipped + TestQuantizedOps.test_qadd_relu_cudnn: skipped + TestQuantizedOps.test_qadd_relu_cudnn_nhwc: skipped + TestQuantizedOps.test_qadd_relu_different_qparams: success + TestTorchrun.test_bar: error + TestTorchrun.test_baz: failure + TestTorchrun.test_cpu_info: success + TestTorchrun.test_foo2: skipped + TestTorchrun.test_foo3: skipped + TestTorchrun.test_foo: skipped + TestTorchrun.test_multi_threads: success + TestTorchrun.test_reshape_cpu_float64: failure + TestTracer.test_jit_save: success + bar.test_2.test_func3: success + bar.test_foo.TestBar.test_func2: success + bar.test_foo.TestName.test_func1: success + """).strip()) + + # Some error cases + error_log_dir = test_log_dir / 'faulty-reports' + + self.assertErrorRegex(ValueError, " or ", + pytorch.get_test_results, error_log_dir / 'root') + self.assertErrorRegex(ValueError, "Failed to parse", + pytorch.get_test_results, error_log_dir / 'invalid_xml') + self.assertErrorRegex(ValueError, "multiple reported files", + pytorch.get_test_results, error_log_dir / 'multi_file') + self.assertErrorRegex(ValueError, "Path from folder and filename should be equal", + pytorch.get_test_results, error_log_dir / 'different_file_name') + self.assertErrorRegex(ValueError, "Unexpected file attribute", + pytorch.get_test_results, error_log_dir / 'file_attribute') + self.assertErrorRegex(ValueError, "Invalid state", + pytorch.get_test_results, error_log_dir / 'skip_and_failed') + self.assertErrorRegex(ValueError, "no test", + pytorch.get_test_results, error_log_dir / 'no_tests') + self.assertErrorRegex(ValueError, "Invalid test count", + pytorch.get_test_results, error_log_dir / 'consistency') + self.assertErrorRegex(ValueError, "Duplicate test", + pytorch.get_test_results, error_log_dir / 'duplicate') + def suite(loader): """Return all easyblock-specific tests.""" diff --git a/test/pytorch_test_logs/README.md b/test/pytorch_test_logs/README.md new file mode 100644 index 00000000000..7191e9e8815 --- /dev/null +++ b/test/pytorch_test_logs/README.md @@ -0,0 +1,5 @@ +# PyTorch test result files + +This Folder contains files as written by the PyTorch test step (via `unittest-xml-reportin`) to be used in tests of the parsing in the PyTorch easyblock. + +Most files are simplified or constructed in a way to reproduce a specific corner case of the parser or format. diff --git a/test/pytorch_test_logs/cleanup_files.py b/test/pytorch_test_logs/cleanup_files.py new file mode 100755 index 00000000000..59ce1de3016 --- /dev/null +++ b/test/pytorch_test_logs/cleanup_files.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 + +"""This script strips content and filenames of PyTorch test result XML files in a deterministic way and formats them. +The intent is to keep the general structure of the files but still make them shorter and easier to read. + +Usage: Pass the target directory as the single argument or +run this script to format the XML files in the "full" directory next to the script. +""" + +import re +import subprocess +import sys +from hashlib import md5 +from pathlib import Path + + +def shorten_filename(path: Path) -> Path: + """Shorten the file name by truncating random part of .e.g. test_quantization-d1303cbc2b57cf06.xml""" + match = re.search(r'-(?P[a-z0-9]{6,})\.xml$', path.name) + if match: + fixed_part: str = path.name[:match.start()] + short_hash = match['hash'][:5] + new_name: Path = path.with_name(f"{fixed_part}-{short_hash}.xml") + path.rename(new_name) + return new_name + return path + + +def shorten_content(path: Path): + """Shorten attribute values and tag content (stdout, stderr, etc.) in the XML file.""" + content: str = path.read_text(encoding='utf-8') + + # Shorten messages in tags: + content = re.sub(r'message="[^"]+"', 'message="..."', content) + # Shorten time + content = re.sub(r'time="[^"]+"', 'time="4.2"', content) + # Ignore timestamp & hostname + content = re.sub(r'timestamp="[^"]+"', '', content) + content = re.sub(r'hostname="[^"]+"', '', content) + # Remove type attribute from tags + content = re.sub(r'( or ) + pattern = re.compile( + rf'(<{tag}([^>/]*?)>)(.*?)', + re.DOTALL + ) + if remove_output and tag in ["system-out", "system-err"]: + content = pattern.sub('', content) + else: + content = pattern.sub(rf'\1[snip]', content) + + # Remove empty lines + content = re.sub(r'\n\s*\n', '\n', content) + # Combine empty tags + content = re.sub(r'(<(\w+) [^>]*)>\s*', r'\1/>', content) + + path.write_text(content, encoding='utf-8') + + +def format_xml(path: Path) -> bool: + try: + subprocess.check_output( + ["xmllint", "--format", str(path), "-o", str(path)], + encoding='utf-8', + stderr=subprocess.STDOUT, + ) + except subprocess.CalledProcessError as e: + # Ignore error "Start tag expected" for empty files + if ' + + + + + + [snip] + + + [snip] + + + [snip] + + + diff --git a/test/pytorch_test_logs/faulty-reports/different_file_name/sync.skip.test_name/sync.skip.test_foo-1.xml b/test/pytorch_test_logs/faulty-reports/different_file_name/sync.skip.test_name/sync.skip.test_foo-1.xml new file mode 100644 index 00000000000..67893db4a7e --- /dev/null +++ b/test/pytorch_test_logs/faulty-reports/different_file_name/sync.skip.test_name/sync.skip.test_foo-1.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/pytorch_test_logs/faulty-reports/duplicate/test_name/test_name-1.xml b/test/pytorch_test_logs/faulty-reports/duplicate/test_name/test_name-1.xml new file mode 100644 index 00000000000..35f6368ed12 --- /dev/null +++ b/test/pytorch_test_logs/faulty-reports/duplicate/test_name/test_name-1.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/pytorch_test_logs/faulty-reports/file_attribute/test_name/TEST-foo.test_name.TestName-1.xml b/test/pytorch_test_logs/faulty-reports/file_attribute/test_name/TEST-foo.test_name.TestName-1.xml new file mode 100644 index 00000000000..bdc796e33e3 --- /dev/null +++ b/test/pytorch_test_logs/faulty-reports/file_attribute/test_name/TEST-foo.test_name.TestName-1.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/pytorch_test_logs/faulty-reports/invalid_xml/test_name/test_name-1.xml b/test/pytorch_test_logs/faulty-reports/invalid_xml/test_name/test_name-1.xml new file mode 100644 index 00000000000..d32f954bbb8 --- /dev/null +++ b/test/pytorch_test_logs/faulty-reports/invalid_xml/test_name/test_name-1.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/test/pytorch_test_logs/faulty-reports/multi_file/test_name/TEST-Name-1.xml b/test/pytorch_test_logs/faulty-reports/multi_file/test_name/TEST-Name-1.xml new file mode 100644 index 00000000000..78dd9f5c7fb --- /dev/null +++ b/test/pytorch_test_logs/faulty-reports/multi_file/test_name/TEST-Name-1.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test/pytorch_test_logs/faulty-reports/no_tests/test_name/test_name-1.xml b/test/pytorch_test_logs/faulty-reports/no_tests/test_name/test_name-1.xml new file mode 100644 index 00000000000..568b67bb677 --- /dev/null +++ b/test/pytorch_test_logs/faulty-reports/no_tests/test_name/test_name-1.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/pytorch_test_logs/faulty-reports/root/test_name/test_name-1.xml b/test/pytorch_test_logs/faulty-reports/root/test_name/test_name-1.xml new file mode 100644 index 00000000000..a2ecb902aa7 --- /dev/null +++ b/test/pytorch_test_logs/faulty-reports/root/test_name/test_name-1.xml @@ -0,0 +1,3 @@ + + + diff --git a/test/pytorch_test_logs/faulty-reports/skip_and_failed/test_name/test_name-1.xml b/test/pytorch_test_logs/faulty-reports/skip_and_failed/test_name/test_name-1.xml new file mode 100644 index 00000000000..fdae2191838 --- /dev/null +++ b/test/pytorch_test_logs/faulty-reports/skip_and_failed/test_name/test_name-1.xml @@ -0,0 +1,9 @@ + + + + + + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/dist-gloo-init-env/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-1d671.xml b/test/pytorch_test_logs/test-reports/dist-gloo-init-env/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-1d671.xml new file mode 100644 index 00000000000..bdf01393666 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/dist-gloo-init-env/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-1d671.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/pytorch_test_logs/test-reports/dist-gloo-init-file/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-78879.xml b/test/pytorch_test_logs/test-reports/dist-gloo-init-file/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-78879.xml new file mode 100644 index 00000000000..bdf01393666 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/dist-gloo-init-file/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-78879.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/pytorch_test_logs/test-reports/dist-nccl-init-env/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-5f224.xml b/test/pytorch_test_logs/test-reports/dist-nccl-init-env/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-5f224.xml new file mode 100644 index 00000000000..bdf01393666 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/dist-nccl-init-env/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-5f224.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/pytorch_test_logs/test-reports/dist-nccl-init-file/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-d5cb5.xml b/test/pytorch_test_logs/test-reports/dist-nccl-init-file/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-d5cb5.xml new file mode 100644 index 00000000000..bdf01393666 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/dist-nccl-init-file/distr.algorithms.quantization.test_quantization/distr.algorithms.quantization.test_quantization-d5cb5.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-1.xml b/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-1.xml new file mode 100644 index 00000000000..dbc55f47eec --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-1.xml @@ -0,0 +1,26 @@ + + + + + [snip] + + + [snip] + + + [snip] + + + [snip] + + + [snip] + + + [snip] + + + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-2.xml b/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-2.xml new file mode 100644 index 00000000000..c8372ce9101 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-2.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-3.xml b/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-3.xml new file mode 100644 index 00000000000..1c86924bf8f --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-3.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-4.xml b/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-4.xml new file mode 100644 index 00000000000..9a3e05b534f --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/backends.xeon.test_launch/backends.xeon.test_launch-4.xml @@ -0,0 +1 @@ + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/distributed.tensor.test_dtensor_ops/distributed.tensor.test_dtensor_ops-2fe9b.xml b/test/pytorch_test_logs/test-reports/python-pytest/distributed.tensor.test_dtensor_ops/distributed.tensor.test_dtensor_ops-2fe9b.xml new file mode 100644 index 00000000000..b1010ead5c7 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/distributed.tensor.test_dtensor_ops/distributed.tensor.test_dtensor_ops-2fe9b.xml @@ -0,0 +1,17 @@ + + + + + + + + + [snip] + + + + [snip] + + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_dynamic_shapes/dynamo.test_dynamic_shapes-189f6.xml b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_dynamic_shapes/dynamo.test_dynamic_shapes-189f6.xml new file mode 100644 index 00000000000..9b5af2a0487 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_dynamic_shapes/dynamo.test_dynamic_shapes-189f6.xml @@ -0,0 +1,20 @@ + + + + + [snip] + + + [snip] + + + [snip] + + + [snip] + [snip] + [snip] + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_dynamic_shapes/dynamo.test_dynamic_shapes-266ee.xml b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_dynamic_shapes/dynamo.test_dynamic_shapes-266ee.xml new file mode 100644 index 00000000000..94500d25c6a --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_dynamic_shapes/dynamo.test_dynamic_shapes-266ee.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_dynamic_shapes/dynamo.test_dynamic_shapes-3f6e0.xml b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_dynamic_shapes/dynamo.test_dynamic_shapes-3f6e0.xml new file mode 100644 index 00000000000..c0cbe2faa59 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_dynamic_shapes/dynamo.test_dynamic_shapes-3f6e0.xml @@ -0,0 +1,13 @@ + + + + + + + + [snip] + [snip] + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_misc/dynamo.test_misc-18930.xml b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_misc/dynamo.test_misc-18930.xml new file mode 100644 index 00000000000..dd64b286cbb --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_misc/dynamo.test_misc-18930.xml @@ -0,0 +1,11 @@ + + + + + [snip] + [snip] + [snip] + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_misc/dynamo.test_misc-86d5b.xml b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_misc/dynamo.test_misc-86d5b.xml new file mode 100644 index 00000000000..7969c7d1799 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_misc/dynamo.test_misc-86d5b.xml @@ -0,0 +1,16 @@ + + + + + + + + + + [snip] + [snip] + + + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_misc/dynamo.test_misc-d062d.xml b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_misc/dynamo.test_misc-d062d.xml new file mode 100644 index 00000000000..74e37835363 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/dynamo.test_misc/dynamo.test_misc-d062d.xml @@ -0,0 +1,20 @@ + + + + + [snip] + + + [snip] + + + [snip] + + + [snip] + [snip] + [snip] + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_aot_inductor_arrayref/inductor.test_aot_inductor_arrayref-bfd31.xml b/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_aot_inductor_arrayref/inductor.test_aot_inductor_arrayref-bfd31.xml new file mode 100644 index 00000000000..b2b186b80bd --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_aot_inductor_arrayref/inductor.test_aot_inductor_arrayref-bfd31.xml @@ -0,0 +1,13 @@ + + + + + + [snip] + + + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_aot_inductor_arrayref/inductor.test_aot_inductor_arrayref-bfd31_2.xml b/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_aot_inductor_arrayref/inductor.test_aot_inductor_arrayref-bfd31_2.xml new file mode 100644 index 00000000000..37ff24b617b --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_aot_inductor_arrayref/inductor.test_aot_inductor_arrayref-bfd31_2.xml @@ -0,0 +1,13 @@ + + + + + + [snip] + + + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_cudagraph_trees/inductor.test_cudagraph_trees-17dac.xml b/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_cudagraph_trees/inductor.test_cudagraph_trees-17dac.xml new file mode 100644 index 00000000000..6fb969802b8 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_cudagraph_trees/inductor.test_cudagraph_trees-17dac.xml @@ -0,0 +1,14 @@ + + + + + + [snip] + [snip] + [snip] + + + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_cudagraph_trees/inductor.test_cudagraph_trees-bbc64.xml b/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_cudagraph_trees/inductor.test_cudagraph_trees-bbc64.xml new file mode 100644 index 00000000000..3ce296ae6a6 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/inductor.test_cudagraph_trees/inductor.test_cudagraph_trees-bbc64.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/run_test/run_test.xml b/test/pytorch_test_logs/test-reports/python-pytest/run_test/run_test.xml new file mode 100644 index 00000000000..2964c5a3e6f --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/run_test/run_test.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/test_nestedtensor/test_nestedtensor-671fe.xml b/test/pytorch_test_logs/test-reports/python-pytest/test_nestedtensor/test_nestedtensor-671fe.xml new file mode 100644 index 00000000000..802b93b6665 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/test_nestedtensor/test_nestedtensor-671fe.xml @@ -0,0 +1,8 @@ + + + + + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/test_nestedtensor/test_nestedtensor-8e17a.xml b/test/pytorch_test_logs/test-reports/python-pytest/test_nestedtensor/test_nestedtensor-8e17a.xml new file mode 100644 index 00000000000..c2049f46e24 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/test_nestedtensor/test_nestedtensor-8e17a.xml @@ -0,0 +1,26 @@ + + + + + + + + [snip] + + + [snip] + + + [snip] + + + [snip] + + + [snip] + + + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/test_quantization/test_quantization-3146b.xml b/test/pytorch_test_logs/test-reports/python-pytest/test_quantization/test_quantization-3146b.xml new file mode 100644 index 00000000000..981e103162d --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/test_quantization/test_quantization-3146b.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/pytorch_test_logs/test-reports/python-pytest/test_quantization/test_quantization-97a67.xml b/test/pytorch_test_logs/test-reports/python-pytest/test_quantization/test_quantization-97a67.xml new file mode 100644 index 00000000000..18afe8bc184 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-pytest/test_quantization/test_quantization-97a67.xml @@ -0,0 +1,36 @@ + + + + + [snip] + + + + [snip] + + + [snip] + + + + [snip] + + + + + + + + + [snip] + + + + + + [snip] + [snip] + [snip] + + + diff --git a/test/pytorch_test_logs/test-reports/python-unittest/-c/TEST-TestFooCPU-20251030150550.xml b/test/pytorch_test_logs/test-reports/python-unittest/-c/TEST-TestFooCPU-20251030150550.xml new file mode 100644 index 00000000000..4afd9909341 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-unittest/-c/TEST-TestFooCPU-20251030150550.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/test/pytorch_test_logs/test-reports/python-unittest/-c/TEST-unittest.suite._ErrorHolder-20251030150550.xml b/test/pytorch_test_logs/test-reports/python-unittest/-c/TEST-unittest.suite._ErrorHolder-20251030150550.xml new file mode 100644 index 00000000000..2015b560986 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-unittest/-c/TEST-unittest.suite._ErrorHolder-20251030150550.xml @@ -0,0 +1,11 @@ + + + + ", line 16, in tearDownClass +RuntimeError: called with TestFooCPU +]]> + + diff --git a/test/pytorch_test_logs/test-reports/python-unittest/jit.test_builtins/TEST-jit.test_builtins.TestBuiltins-1.xml b/test/pytorch_test_logs/test-reports/python-unittest/jit.test_builtins/TEST-jit.test_builtins.TestBuiltins-1.xml new file mode 100644 index 00000000000..f161a814732 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-unittest/jit.test_builtins/TEST-jit.test_builtins.TestBuiltins-1.xml @@ -0,0 +1,4 @@ + + + + diff --git a/test/pytorch_test_logs/test-reports/python-unittest/test_autoload/TEST-TestBackend-1.xml b/test/pytorch_test_logs/test-reports/python-unittest/test_autoload/TEST-TestBackend-1.xml new file mode 100644 index 00000000000..c2686aee667 --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-unittest/test_autoload/TEST-TestBackend-1.xml @@ -0,0 +1,4 @@ + + + + diff --git a/test/pytorch_test_logs/test-reports/python-unittest/test_autoload/TEST-TestBackend-2.xml b/test/pytorch_test_logs/test-reports/python-unittest/test_autoload/TEST-TestBackend-2.xml new file mode 100644 index 00000000000..3477dc744ca --- /dev/null +++ b/test/pytorch_test_logs/test-reports/python-unittest/test_autoload/TEST-TestBackend-2.xml @@ -0,0 +1,7 @@ + + + + + [snip] + +