diff --git a/.github/workflows/lapack-validation.yml b/.github/workflows/lapack-validation.yml index 090e02a4..0a360cf6 100644 --- a/.github/workflows/lapack-validation.yml +++ b/.github/workflows/lapack-validation.yml @@ -15,7 +15,7 @@ concurrency: jobs: validation: runs-on: ubuntu-latest - timeout-minutes: 50 + timeout-minutes: 55 outputs: unexpected: ${{ steps.summary.outputs.unexpected }} stale: ${{ steps.summary.outputs.stale }} @@ -36,7 +36,7 @@ jobs: python3 scripts/test-lapack-validation.py node --test scripts/test-lapack-reporter.cjs - name: Build once and run all numerical families - timeout-minutes: 44 # build <=20m; family limits sum to 20m; setup/headroom + timeout-minutes: 49 # build <=20m; family limits sum to 25m; setup/headroom run: scripts/run-lapack-validation.sh - name: Summarize known and new failures id: summary diff --git a/docs/lapack-validation.md b/docs/lapack-validation.md index 21464c2e..caa6e546 100644 --- a/docs/lapack-validation.md +++ b/docs/lapack-validation.md @@ -291,8 +291,10 @@ fired only for a failure that is not listed - or for a listed test that starts p lose its entry in the same change. Adding an entry without an issue is a bug in the entry. It caches dependencies on failure and uploads environment, build timing, exact selection, family logs and summary for 14 days. Per-family timeouts sum to -20 minutes; the build limit is 20 minutes, the combined step 44 minutes and the -validation job 50 minutes. A separate two-minute reporting job creates/updates one +25 minutes; the build limit is 20 minutes, the combined step 49 minutes and the +validation job 55 minutes. The family `svd_large` runs upstream's large SVD matrix +test `test_josef` (n = 8660, f32, full U and V; about 70 s and 2.3 GB locally), which is too slow to +run with every test and is therefore ignored there. A separate two-minute reporting job creates/updates one open issue titled “Scheduled LAPACK numerical validation is failing” with label `scheduled-lapack-validation`, retaining the failed status and run link. These are upper bounds, not expected runtimes. They allow every family timeout to expire diff --git a/faer/src/linalg/svd/bidiag_svd.rs b/faer/src/linalg/svd/bidiag_svd.rs index 783bc584..56c723f7 100644 --- a/faer/src/linalg/svd/bidiag_svd.rs +++ b/faer/src/linalg/svd/bidiag_svd.rs @@ -2147,7 +2147,9 @@ mod tests { } } #[test] - #[ignore] + // n = 8660 in f32 with full U and V: about a minute even optimised, so it runs in the nightly + // LAPACK validation (family `svd_large`, scripts/run-lapack-validation.py), not with every test. + #[ignore = "large (n = 8660): runs in the nightly LAPACK validation"] fn test_josef() { for file in std::fs::read_dir( PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test_data/svd/"), diff --git a/scripts/__pycache__/run-lapack-validation.cpython-310.pyc b/scripts/__pycache__/run-lapack-validation.cpython-310.pyc index d051f343..670cd0d9 100644 Binary files a/scripts/__pycache__/run-lapack-validation.cpython-310.pyc and b/scripts/__pycache__/run-lapack-validation.cpython-310.pyc differ diff --git a/scripts/__pycache__/run-lapack-validation.cpython-312.pyc b/scripts/__pycache__/run-lapack-validation.cpython-312.pyc index 4720260d..895a5e99 100644 Binary files a/scripts/__pycache__/run-lapack-validation.cpython-312.pyc and b/scripts/__pycache__/run-lapack-validation.cpython-312.pyc differ diff --git a/scripts/__pycache__/test-lapack-validation.cpython-310.pyc b/scripts/__pycache__/test-lapack-validation.cpython-310.pyc index 16cacd75..2b2b156a 100644 Binary files a/scripts/__pycache__/test-lapack-validation.cpython-310.pyc and b/scripts/__pycache__/test-lapack-validation.cpython-310.pyc differ diff --git a/scripts/run-lapack-validation.py b/scripts/run-lapack-validation.py index b3cb2d0c..2c71d4d7 100644 --- a/scripts/run-lapack-validation.py +++ b/scripts/run-lapack-validation.py @@ -12,14 +12,18 @@ FAMILIES = ( 'common', 'svd', 'hessenberg', 'schur', 'nonsymmetric_evd', 'schur_reorder', 'balance', 'tridiagonal_evd', 'self_adjoint_evd', - 'lu', 'cholesky', 'indefinite', 'qr', 'triangular', 'lstsq', + 'lu', 'cholesky', 'indefinite', 'qr', 'triangular', 'lstsq', 'svd_large', ) # Local measurements are documented in docs/lapack-validation.md. Hosted # timings remain unmeasured; these bounds leave several times the local runtime. LIMITS = dict(common=30, svd=120, hessenberg=60, schur=90, nonsymmetric_evd=60, schur_reorder=30, balance=30, tridiagonal_evd=90, self_adjoint_evd=120, lu=180, - cholesky=60, indefinite=120, qr=90, triangular=60, lstsq=60) + cholesky=60, indefinite=120, qr=90, triangular=60, lstsq=60, + svd_large=300) +# Upstream's large SVD matrix tests: too slow for every test run (about a minute each +# locally), so they are ignored there and run here, in a family of their own. +LARGE_SVD = ('linalg::svd::bidiag_svd::tests::test_josef',) CASE = re.compile( r'LAPACK_CASES family=(\S+) dtype=(\S+) planned=(\d+) attempted=(\d+) ' r'call_failures=(\d+) diagnostics=(\d+)(?: auxiliary_attempted=(\d+))?' @@ -28,6 +32,8 @@ def classify(name): + if name in LARGE_SVD: + return 'svd_large' if name.startswith('linalg::svd::tests::'): return 'svd' leaf = name.rsplit('::', 1)[-1] diff --git a/scripts/test-lapack-validation.py b/scripts/test-lapack-validation.py index 8aa8121a..11ba4834 100644 --- a/scripts/test-lapack-validation.py +++ b/scripts/test-lapack-validation.py @@ -18,6 +18,8 @@ def test_classification_and_empty_selection(self): self.assertEqual(v.classify('linalg::evd::lapack::f64::lapack_schur_reorder_cases'), 'schur_reorder') self.assertEqual(v.classify('linalg::qr::lapack::c64::lapack_qr_reflector_checkers'), 'qr') self.assertEqual(v.classify('linalg::svd::tests::lapack_svd_f32::lapack::diagonal_families'), 'svd') + self.assertEqual(v.classify('linalg::svd::bidiag_svd::tests::test_josef'), 'svd_large') + self.assertIsNone(v.classify('linalg::svd::bidiag_svd::tests::test_deflation43')) # a self-adjoint accuracy test beside the case suite (tensor4all/faer#100): classified, not a case record name = 'linalg::evd::lapack::c32::lapack_self_adjoint_evd_qr_spectrum_accuracy' self.assertEqual(v.classify(name), 'self_adjoint_evd') @@ -43,7 +45,7 @@ def fake(command, log, timeout): self.assertEqual(len(calls), len(v.FAMILIES)) self.assertEqual(next(r for r in rows if r['family'] == 'svd')['exit_code'], 101) self.assertFalse(next(r for r in rows if r['family'] == 'lu')['complete']) - self.assertEqual(rows[-1]['family'], 'lstsq') + self.assertEqual(rows[-1]['family'], 'svd_large') self.assertTrue(rows[-1]['complete']) self.assertTrue(all('--exact' in c and '--include-ignored' in c for c in calls))