From f4fdee42683470fa687371ce39d8ab18aca014c0 Mon Sep 17 00:00:00 2001 From: "KOKO\\Mimi" Date: Wed, 14 Oct 2026 16:15:39 +0900 Subject: [PATCH] docs(performance): record MKL lifecycle and validation evidence --- docs/calculation-performance/mkl-coverage.md | 250 +++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 docs/calculation-performance/mkl-coverage.md diff --git a/docs/calculation-performance/mkl-coverage.md b/docs/calculation-performance/mkl-coverage.md new file mode 100644 index 0000000..3e0baf7 --- /dev/null +++ b/docs/calculation-performance/mkl-coverage.md @@ -0,0 +1,250 @@ +# MKL 적용 범위와 수명 근거 + +FEM-REQ-PERF-004/005/007/009의 T2 구현 기록이다. 공통 요구사항·물리·수치 +기준과 reference는 변경하지 않았다. T3/T4 인계 목록은 해당 owner가 완료한 +실제 diff와 검사를 통합한 뒤 갱신한다. 이 기록만으로 전체 production 적용이나 +세 모델의 공식 시간 목표 통과를 주장하지 않는다. + +## 공통 연산 경계 + +| 위치 | 연산 / 실제 private 호출 | 유지하는 의미 | +| --- | --- | --- | +| `math/matrix.cpp::Multiply` | dense gemv/gemm, `cblas_dgemv/dgemm` | 기존 shape/empty/checked MKL_INT 및 새 actual operand finite preflight | +| `math/vector.cpp` | Dot/Scale/Axpy와 copy, dense BLAS | 기존 공개 값·실패 의미 유지 | +| `math/dense_blas_internal.cpp::MultiplyTransposeLeft` | transpose storage copy 뒤 `Matrix::Multiply`; diagonal DSBMV(k0); LAPACK dpotrf/dtrtri | transpose-left shape 확인; ordinary product는 MKL | +| `math/sparse_matrix.cpp::Multiply` | `mkl_sparse_d_create_csr` → `mkl_sparse_d_mv` → destroy | canonical CSR와 structural zeros, general full matrix, zero-based index | +| `solvers/linear/mkl_pardiso_solver.cpp` | PARDISO SPD factorization/solve | 기존 경로와 scoped n=1 policy | +| `solvers/linear/mkl_pardiso_tangent_solver.cpp` | fresh phase 11/22, solve 33 | 새 분해 전 release; 실패 뒤 stale 사용 금지; 동일 성공 분해의 여러 RHS 허용 | +| `results/global_equilibrium_recovery.cpp` | full K*d, free/constrained masked RHS의 각 K*d | Kff*df/Kfc*dc scale를 별도로 유지; 원래 free rows만 norm 판정 | +| `analysis/linear_frequency_procedure.cpp` / `solid_frequency_procedure.cpp` | original/whitened pencil sparse action, dense Dot | original-pencil finite/independent residual/energy/Gram 검사 유지 | +| `solvers/eigen/mkl_feast_eigen_solver.cpp` | independent scaled full/mass/mirrored sparse actions; QR ddot/daxpy | FEAST actual 호출·count/solve budget·seed/Householder 절차 유지; backend residual로 독립 residual 대체하지 않음 | +| `analysis/eigen_reduction.cpp` | nodal/block congruence, mode restoration, nodal mass action | nodal analytic null split과 scaled original pencil 유지 | +| `analysis/thermal_transient_algebra.cpp` | BE RHS entry의 compact diagonal DSBMV, reduced/full/dissipation CSR actions | raw old constrained state·signed temperature·actual delta·independent interval companion 보존 | +| `elements/euler_beam_3d.cpp` | B*d, BᵀDB, TᵀKT, interpolationᵀq | 2 Gauss points·closed stiffness invariant·local force/section identity 유지 | + +### Sparse 단발 자원 + +입력 의존성은 현재 matrix의 전체 CSR shape/index/value와 현재 RHS이다. +`Validate()`가 canonical CSR와 finite coefficient를 확인한 뒤 actual `MKL_INT` +폭에 맞춰 rows/columns/nnz/각 index를 checked 변환한다. 공개 `size_t` storage는 +변경하지 않고 기존 private `ToMklSize`를 재사용한다. 이 설치의 ILP64를 public +API에 하드코딩하지 않는다. + +호출 stack이 변환 index 배열·복사 values와 handle을 소유한다. handle은 배열 뒤에 +생성되며 RAII destroy가 배열 소멸보다 먼저 실행된다. MKL이 CSR 배열을 참조한다는 +[Intel create CSR 계약](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2026-0/mkl-sparse-create-csr.html)을 따른다. +직접 private values 복사는 const-cast 없이 const 동시 호출을 분리한다. +호출 종료가 invalidation이며 지속 handle/cache가 없다. 저장량은 단발 +`(rows+1+nnz)*sizeof(MKL_INT)+nnz*sizeof(double)` 및 output이다. +측정 근거 없는 symbolic/persistent cache는 채택하지 않았다. 아래 n=1 PARDISO의 제한된 TLS 정책만 실제 baseline/보조 근거로 채택했다. + +0 rows/0 columns/no entries는 검증과 index range 확인 뒤 zero vector를 반환한다. +nonempty matrix의 구조상 빈 row는 MKL 결과의 zero row다. Copy/move/assignment는 +공개 CSR 값 storage 수명만 갖고 backend pointer를 보관하지 않는다. Moved-from +불완전 CSR은 사용 전에 validation에서 거부되므로 indexing UB로 진행하지 않는다. + +backend failure는 scalar fallback이나 성공 candidate 없이 `runtime_error`로, +integer overflow는 `length_error`로 전달한다. vendor enum/원시 오류 번호는 공개하지 +않는다. `GlobalEquilibriumRecovery`와 frequency/eigen/thermal consumer는 해당 +새 실패를 `Status/Result`로 변환하며 이전 state/history/final 결과를 commit하지 않는다. +실제 allocation/backend fault를 강제한 native 시험은 실행하지 않았다. 해당 +실패 branch의 fallback 부재·exception 변환·RAII 해제는 정적 검토 범위이며, +일반 실패/반복·copy/move·동시 const 호출과 bad RHS 복구는 실제 검사 범위다. + +### Finite의 owner + +CSR coefficient와 모든 RHS는 MKL 호출 전 math에서 finite 검증한다. 비유한 RHS는 +기존 값 반환/exception 형식의 `invalid_argument`로 거부하며, public signature는 +변경하지 않는다. Finite-input product overflow는 consumer의 기존 output finite +검증으로 실패한다. Empty/zero shape도 입력 finite/shape/range 검증을 유지한다. + +Dense gemv/gemm도양쪽actualownedstorage/VectorRHS를중앙Matrix::Multiply에서finite-first로검사한다. PrivateTransposeLeft는이중앙dispatch를사용하며 nonfinite입력에서invalid_argument를전달한다. BuildEigenReduction/linearfrequency/FEAST owner는해당typedfailure를기존Result taxonomy로변환한다. MakeLift actual basis/scaled operands와FEAST normalizedphi/mass_modes producer도dispatch전에검사한다. + +Production caller finite 입력은 별도로 확인한다. Recovery는 기존 +`IsFiniteVector`→Multiply→finite output 순서를 유지한다. Linear frequency의 physical +및 whitened x, solid frequency의 raw/normalized mode는 finite-first이며, FEAST가 +반환한 벡터의 finite gate도 기존대로 유지한다. Thermal은 기존 Validate·solver +candidate finite와 interval enclosures를 사용한다. Thermal RHS의 각 entry는 +`(c/delta)*(old-g)-k*g`라는 원래 association을 먼저 계산한 뒤 원래 row 순서로 +누적한다. 두 행곱을 별도로 합산한 뒤 빼는 후보는 stable b=4를 잃어 기존 +Cancellation 검사를 실패했으므로 폐기했다. 현재 private diagonal MKL은 O(nnz) +compact band k=0 storage로 entry별 곱만 계산한다. Exact companion과 construction +error·gamma·underflow certification·free/reaction 판정은 그대로다. +비유한 product를 정상값으로 clamp하거나 tolerance를 완화하지 않는다. + +### PARDISO 수명 + +현재 구현 그대로 `release → CSR/shape/width 확인 → private arrays → phase11 → phase22` +를 수행한다. 값/pattern이 달라지면 `FactorizeFresh`를 다시 호출한다. 새 singular +분해 실패 뒤 `SolveCorrection`은 not-factorized이며 caller correction은 보존된다. +잘못된 RHS의 실패는 output 보존과 유효한 기존 matrix 분해의 수명을 구별한다. +여러 RHS는 같은 성공 분해의 phase33을 사용할 수 있다. 새로운 symbolic 재사용이나 +다중 RHS framework를 도입하지 않았다. + +### One-equation PARDISO의 scoped 자원 정책 + +[T1 실제 VTune](verification.md)의 OMP worker/spin 비용과 아래 toy n=1 lifecycle +근거로, SPD/Tangent의 `CallPardiso`에서 **현재 retained equation_count=1**인 경우만 +호출 기본 thread 정책을1로 제한한다. Phase11/22/33/−1 각각의 호출 범위다. +`mkl_set_num_threads_local(1)`의 이전 TLS override가0인 경우만 scope1을 유지하고 +끝에0을 복원한다. 이전값이비영이면 즉시 그값을복원하여 caller override대로 +backend를실행한다. n=0/2이상·전역 MKL/OpenMP 요청·dispatch·iparm·pivot/scaling/ +regularization·acceptance는변경하지않는다. 넓은size threshold는추정하지않았다. + +Release의oldfactor는old retained count, newfactor는newcount를각call에서사용하므로 +작은oldmatrix release 뒤 큰newmatrix가 single-thread로 오염되지 않는다. +현재원시기록의 외부 MKL/OMP 요청은8/dynamicFALSE로baseline과같고 실제 source +정책은default1×1 calls에서달라진다. 이 차이를환경동일이라는표현으로숨기지않는다. +Phase 성공/오류/exception·잘못된 RHS 및 concurrent worker의 TLS 복원과 candidate +보존을실제검사한다. Native process crash는C++ RAII unwind를보장하지않으며, 해당 +진단의scope설정은종료한process의TLS여서다음실행/전역환경에남지않는다. + +### Baseline PARDISO heap failure와 제한 + +기존staticpartialfixture는full24×24/free1×1이다. `backend-isolation`의SpMV-only +1000회create/mv/destroy는native0이며, PARDISO-only100회예정실행은native +`−1073740940 (0xc0000374)`로중단됐다. 별도반복staticfixture도iteration3에서같은 +heap-corruption을재현했다. 이를새SpMV수명회귀나단순testPASS로분류하지않는다. + +같은freshauxTU를T1의기존Release library에`/O2 /Ob2 /MD /DNDEBUG /Zi`로link해 +실제baseline을대조했다. Baseline default8은61회완료뒤62에서같은nativecrash, +scoped1은100회native0와각scope끝effective8복원을기록했다. CurrentDebug +`/Od /Ob0 /MDd /RTC1 /Zi` recordedprobe의8/1은각100회완료했으나이전Debug +probe의2/3회crash를지우지않는다. 실패가간헐적이므로100회통과를vendor문제 +해결확정으로쓰지않는다. Debug/Release차이도그대로기록한다. + +Ordered full/free CSR offsets/columns/rawdoublebits와RHS inputSHA는양쪽 +`CC7E72000783E9694BAF76627D95AB7B420A31198B210B5A60C7ACE93E5E2258`로같다. +ILP64·mtype2·actual pardisoinit defaultcontrols(26 checker/34 zerobased 포함), 동일 +MKL/runtimeDLL hash는[recorded-probes metadata](../../.harness/performance/t2/recorded-probes-metadata.json)와 +[native 기록](../../.harness/performance/t2/recorded-probes-native.json)에있다. +기존PARDISO/backend영역실패를실제baseline에서재현했으며vendor내부원인은미확정이다. +[Intel release notes](https://www.intel.com/content/www/us/en/developer/articles/release-notes/onemkl/2026.html)의 +non-AVX2 PARDISO sporadic pivoting issue는조사근거이고현재원인확정이아니다. +설치·dispatch·전역registry/pageheap변경은하지않았다. + +같은toy n=1 보조비용실행에서default8은11회뒤crash/0.24s, +scope1은100회완료/0.15s였다. 이는동일입력준비/로그를포함한auxiliary이며 +실패/표본수차이가있어공식whole-model speedup이나시간목표판정에사용하지않는다. +[Tiny native 비용기록](../../.harness/performance/t2/tiny-pardiso-cost-native.json)에실제범위를기록했다. + +## 특수 정밀도 개선과 예외 + +T1의 실제 Hex8 VTune stack은 `TwoSum → Add → Multiply → hex8_high_low::operator*` +비용 및 frexp/ldexp 분류 비용을 확인했다. T2는 arithmetic association과 underflow +정책을 바꾸지 않고 두 helper만 개선했다. + +- `high_low_arithmetic.h::IsNormalized`: finite와 canonical exact-zero guard 뒤 + `RN(high+low)==high`. 이 경우 기존 TwoSum의 bridge=0/restored=high/error=low이며, + 반대 방향도 기존 predicate의 high equality가 같은 조건이다. overflow/nonfinite와 + noncanonical signed zero를 먼저 거부한다. +- `LowestBitExponent`: IEEE binary64를 memcpy로 읽어 정상은 + `(encoded exponent−1075)+trailing(implicit53bits)`, subnormal은 + `−1074+trailing(fraction)`으로 계산한다. 부호를 제외하고 actual least bit를 보존한다. + TwoProduct의 least-bit-sum < −1074 거부와 FMA residual·TwoSum 정규화는 그대로다. +- zero/low-zero shortcut, nonzero multiplication association 변경은 채택하지 않았다. + +[독립 수치 검토](../../.harness/performance/t2/arithmetic-numerical-review.md)는 +위 두 helper proof/source 범위 PASS이며 실제 검사/속도와 전체 MKL diff 검토를 +대체하지 않는다. Frozen original oracle는 pinned `b4fc1bb`의 원본이며 include guard와 +namespace만 바꾼 test 전용 `high_low_arithmetic_original.h`이다. 실제 모든 정상 +exponent×53 trailing-bit×양 부호, subnormal boundaries, signed zero/ties/overflow/ +invalid/raw random 입력의 bit 대조 및 기존 analytical checks를 실행했다. + +| 파일 / 함수 | 연산·크기·정밀도 | 예외 이유 / 검사·owner | +| --- | --- | --- | +| `math/high_low_arithmetic.h` 전체, `elements/hex8_high_low.cpp::EvaluateHighLow` | normalized binary64 high+low, 3×3 tensor 및 24×24 pair tangent | ordinary Float64 BLAS로 low/tail rejection을 잃을 수 없음; frozen oracle/Hex8HighLow·T3 | +| `elements/hex8_geometry.cpp`의 interval/relative coordinate 인증 | 3×3 inverse/Jacobian 및 outward interval | whole-cell certificate·직접 geometry predicate 보존; Hex8 geometry 검사·T3 | +| `elements/hex8_element.cpp` gradient/inverse·F/S/P/FFT/stress의 3×3 tensor | fixed3-coordinate contraction | 3-coordinate geometry/constitutive 의미; 24×24 ordinary tangent는 이 예외로 일괄 분류하지 않음·T3 | +| `elements/finite_rotation.cpp` Rodrigues/skew/invariant | fixed3×3 axis coordinate | 좌표 rotation/invariant; finite rotation 검사 | +| `analysis/eigen_reduction.cpp::MakeLift` analytic director/frame basis와 null-coordinate checks | fixed6 nodal coordinates, 최대6 positive basis | 고정 director/frame의 analytic 좌표 선택만 예외. 일반 mass whitening/Cholesky/inverse/congruence/reconstruction은 MKL 전환·EigenReduction | +| `elements/thermal_shell.cpp` shape/metric contraction | fixed4 shape·fixed3 gradient·2D metric, separable integration coefficient | local coordinate/shape quadrature; global capacity/conduction actions는 MKL·thermal local oracle | +| `analysis/thermal_transient_algebra.cpp`의 `I`/Add/Mul/Sub/Div/Norm/Error/Roundoff/Tiny | outward interval·construction/underflow enclosure | floating product와 분리된 정확대수 인증, gamma/epsilon/limit 변경없음·TransientHeatProcedure/ThermalPhysics | +| `analysis/hht_reduced_operators.cpp` Projection/Embed/Sum, BasisValue, reduced blocks | compensated sums 및 outward basis radius | low/error compensation 유지, ordinary Hessian/product는 T4 판별/전환 | +| `analysis/hht_dynamic_algebra.cpp` AddCompensated·constraint radius 및 3-vector director dot | compensated error·fixed coordinate | 승인 N3/N7·scale 인증; 일반 CSR contraction과 구별·T4 | +| `elements/nonlinear_mitc4_shell.cpp` / `nonlinear_mitc4_inertia.cpp` Jet 산술 | analytic derivative jets, fixed3 rotation | AD derivative association/coordinate 의미; ordinary24×24 Hessian/dense congruence blanket 예외 금지·T4 | +| `io/hdf5/nonlinear_hdf5_results_writer.cpp` spatial moment transform | fixed3×3 rotation coordinate | 공개 generalized/spatial quantity 변환 보존·T4 | + +## T3/T4 인계 + +전수 검색의 raw 위치 목록은 [ordinary-product-audit](../../.harness/performance/t2/ordinary-product-audit.txt)다. +검색은 +=*만으로 완료하지 않고 Multiply·중첩 루프와 각 함수의 precision/owner를 +함께 확인했다. 이 목록은 후속 diff에서 갱신해야 한다. + +- T3: Hex8 pair tangent/relative geometry/mean-volume certification은 pair/interval + 예외로 유지한다. Float64 24×24 response/tangent의 일반 contractions와 procedure + 직접 products는 ordinary MKL 적용 여부를 확인한다. +- T4: `mitc4_shell.cpp::` transformation congruence(기존241 주변), strainᵀCstrain + stiffness(기존635 주변), `nonlinear_mitc4_inertia.cpp` complement Gram/projection + (기존449/456), `hht_reduced_operators.cpp` bilinear Hessian action(기존620), + reduced block/gradient products(기존970 이후), `hht_dynamic_algebra.cpp` 일반 + stiffness projection(기존442)은 MKL 또는 구체적인 compensated 예외 근거가 필요하다. + `Jet*`의 derivative array 크기가24라는 이유만으로 모든24×24 Float64 products를 + 특수 정밀도 예외로 분류하지 않는다. +- 공통 recovery/eigen/thermal/beam은 T2 확장 owner로 직접 변경했다. Shared + assembly tuple reduction/source identity와 task별 CMake 등록은 root owner이며 변경하지 않았다. + +## 실제 검증과 남은 작업 + +Parent artifact `.harness/performance/t2/`는 worktree cleanup 뒤에도 남는다. +각 native JSON은 argv/cwd/실제 exit와 source 또는 snapshot 구분을 보존한다. +아래 링크는 통합한 저장소의 feature 문서 위치를 기준으로 한다. + +| 실행 범위 / source | 결과 | 실제 기록 | +| --- | --- | --- | +| 최초 Debug build | include 누락 exit2; 수정 뒤 build0 | `build-debug-initial-failed.txt`, `build-native-initial-failed.json` | +| 초기 개발 snapshot | core43/43·consumer71/71 PASS; whole-source hash 없는 precommit 자료 | `core-native.json`, `consumer-native.json` | +| Extended66 개발 snapshot | 64 PASS·1 thermal FAIL·1 large-mesh interrupted; whole native−1 | `extended-native.json`, `extended-checks.txt`, `extended-interruption.json`, `extended-cleanup.json` | +| 59c8e93 후보100개 | 99 PASS·열 RHS 상쇄1 FAIL; native8 | `final-native.json`, `final-checks.txt` | +| Thermal/finite/Gram/whitening 수정 snapshot82개 | 82/82 PASS; native0 | `corrected-native.json`, `corrected-checks.txt` | +| 후속 eigen20개 | 19 PASS·기존 PARDISO heap fixture1 native crash; native8 | `null-products-native.json`, `null-products-checks.txt` | +| 770fa2a scoped-policy 후보 | build0·99/99 PASS; native0 | `policy-build-native.json`, `policy-native.json` | +| 9c4e685 중앙 dense finite 후보 | build0·120/120 PASS; native0 | [build](../../.harness/performance/t2/finite-build-native.json), [native](../../.harness/performance/t2/finite-native.json), [log](../../.harness/performance/t2/finite-checks.txt) | +| 6fc7011 tests-only delta | build0·1↔2 retained-size 전환2/2 PASS; native0 | [build](../../.harness/performance/t2/transition-build-native.json), [native](../../.harness/performance/t2/transition-native.json), [log](../../.harness/performance/t2/transition-checks.txt) | + +`MklPardisoSolver.SingleEquationScopeTransitionsBetweenRetainedSizes`와 +`TangentSolver.SingleEquationScopeTransitionsBetweenRetainedSizes`는 각각 +1→2→1 factorize/solve와 old/new retained count별 TLS 복원을 직접 확인한다. +동시 default TLS의 성공→다른값→bad RHS→새 분해 실패→stale solve 거부는 +`SingleEquationPolicyPreservesLifecycleAndConcurrentTls` 및 +`SingleEquationScopeRestoresTlsAcrossFreshFailureAndReuse`에서 확인한다. +Caller의 비영 TLS override·exception unwind와 큰 크기 정책은 +`DenseBlasInternal.SingleEquationScopeRestoresTlsAndRespectsOverrides`의 직접 관찰이다. + +SpMV destroy/PARDISO release-error를 live 주입한 검사는 미실행이다. 유효 handle에서 +이를 안전하게 발생시킬 근거가 없고 production mutable fault hook은 추가하지 않았다. +정상 release·분해 오류 후 release·반복 및 크기 전환은 실제 검사이며, 원시 release +오류 분기의 candidate 실패 전달과 자원 수명은 독립 정적 검토 범위다. + +9c4e685 production source의 [독립 conformance 재검토](../../.harness/performance/t2/source-conformance-review.md)는 PASS다. 이후 6fc7011은 +검토자가 요청한 transition tests-only delta이며 production source는 같다. +High+low 두 helper의 독립 proof는 앞 절의 실제 보고서와 연결했다. +검토 PASS와 actual execution PASS는 서로 대체하지 않는다. + +최초 실패·상쇄 회귀·간헐적 heap 실패·중단 자료를 삭제하거나 현재 PASS로 바꾸지 않았다. +전체 MSVC Debug/CTest, 원본3+Hex8 필수5 비교, VTune 최종 raw 및 공식 +no-warmup/one-measurement 평가는 T5에서 미실행 항목을 완료해야 한다. +Task source를 fresh build했으며 다른 source의 object를 수동 복사하지 않았다. +Baseline-linked auxiliary는 root가 승인한 보존된 T1 Release library를 직접 link하고 +그 flags/runtime/input을 별도로 기록했으므로 현재 Debug evidence로 대체하지 않는다. + +High+low standalone 보조 microbenchmark는 같은 compiler/한 exe에서 +original/optimized 각400000 products를3회 대조했다. Original은 +0.129315/0.129951/0.129560s, optimized는0.069739/0.070177/0.068700s이며 +모든 checksum이 같고 native0이다. +[보조기록](../../.harness/performance/t2/microbench.jsonl)과 +[native](../../.harness/performance/t2/microbench-native.json)는 helper 비용 근거이며 +3모델의 공식 wall 평가를 대체하지 않는다. + +CSR consumer 전수 보강 검색은 +[csr-consumer-audit](../../.harness/performance/t2/csr-consumer-audit.txt)에 있다. +`assembly/load_assembler.cpp::EffectiveFreeRhs`의 Kfc*dc는 root owner가 T2 통합 뒤 +entrywise MKL diagonal products와 기존 개별 product/ordered row-sum finite gate로 +연결한다. 이 공유 파일은 T2가 수정하지 않았다. 최종 production 전수 완료는 +이 인계와 T3/T4 일반 연산 적용까지 확인해야 한다. + +최종 source/test hash·production 검토 이후 source 변경 없음·874개 검사 discovery native0은 +[final-source-manifest](../../.harness/performance/t2/final-source-manifest.json)에 기록했다. +[final CMakeCache](../../.harness/performance/t2/final-CMakeCache.txt)는 actual dependency와 Debug flags를 보존한다. +Whole changed-file clang-format dry-run은 기존 및 후보 formatting 위반으로 exit1이었다. +[실제 기록](../../.harness/performance/t2/clang-format-native.json)을 보존하며 formatter PASS로 보고하지 않는다.