Files
FESADev/docs/calculation-performance/README.md
T
KOKO\Mimi 01d004c385 docs: record Jet optimization results and validation limits
Record adopted outer-product, accumulation and scratch changes and the
nonadoption reasons for scalar/channel/arena candidates.

Report the fresh TBB single-pair result: 4134.657782 to 3747.788261 seconds,
9.356748 percent lower elapsed, with unchanged numeric bits and Newton counts.
Link raw evidence and retain 16 baseline failures, one skip, two missing
formal references, physical-validation gaps and existing performance targets.
Date-scope previous MKL/HHT evidence instead of replacing its history.

Documentation only. Product source bytes match the fully verified 685f5e6;
git diff --check and static report/link review passed. No build/test rerun.
2026-10-21 14:15:59 +09:00

17 KiB
Raw Blame History

계산 성능 개선

Hex8와 reduced-coordinate shell HHT의 실제 병목을 VTune으로 조사하고, 승인된 물리·입력·정밀도·결과 의미를 유지하며 실행 시간을 줄이는 작업이다. 새 요소·하중·적분법·공용 cache framework 추가는 범위 밖이다. 요구사항 FEM-REQ-PERF-001..009의 시간 목표와 검증은 별개이며 현재 최종 완료 상태는 아니다.

현재 MKL 연결과 확인 범위

2026-10-20 MKL threading layer를 TBB로 변경했다. 직접 MSBuild와 CMake의 x64 Debug·Release 네 빌드는 모두 종료0이며 CLI와 세 테스트 실행 파일 총16개의 링크 및 인접 DLL48개의 일반·지연 PE 의존성과 설치 원본 해시를 정적으로 확인했다. Debug는 mkl_tbb_threadd·tbb12_debug, Release는 mkl_tbb_thread·tbb12를 사용하고 HDF5의 libmmd.dll을 유지한다. 근거는 .build/mkl-tbb-20261020-01/에 보관했다.

사용자 지시로 당시 설정 변경에서는 테스트·모델·수치 비교·성능 측정·VTune을 실행하지 않았다. 실제 DLL loading, 수치 정확성, 속도 향상과 OpenMP 대기 제거는 당시 미검증이었다. 기존 OpenMP 전용 local-thread/TLS helper와 HHT cache 진단 코드는 유지했으며 TBB에서의 동등성도 당시 확인하지 않았다. 이후 Jet 최적화의 새 TBB 검증·측정은 다음 절과 구분한다. 아래 과거 OpenMP 시간·검증 기록을 새 TBB 구성의 결과로 승계하지 않는다.

Jet Product 최적화와 현재 검증

2026-10-21 TBB 기준 9ae7e6d414bfe36c20433c9dfa9fa4095aa9f7bd와 최종 제품 source 685f5e6a826c7bb66b9cef90e086ef4b2685252d를 새로 비교했다. 후속 3ede11b는 검증 근거만 기록한 빈 commit이며 제품 tree는 같다. 24자유도 Shell Jet과 private 누적 helper만 수정했고 물리·공개 API·schema·수렴 기준은 유지했다. 기본 직접 작은 drilling 스프링과 기존 상대 비틀림을 모두 보존했으며 공식 시간 모델은 직접 방식을 사용했다.

검토 후보 채택 결과와 이유
외적·Hessian 결합 모든 MXCSR 예외가 masked이고 첫 MKL 외적이 성공한 경우에만 그 전치를 재사용한다. 두 번째 외적 호출을 줄이되 각 성분의 덧셈 순서를 유지한다. Unmasked 또는 외적 거부 시 기존 순서로 계산한다.
누적의 중간 저장 소비되는 임시 Jet이 할당된 Hessian을 단독 소유할 때만 재사용한다. 공유·동일 객체 alias·unmasked 예외는 기존 경로를 유지한다.
상수 연산 특화 단순 scalar 대체는 원본 192개 경계 그룹 중 184개에서 signed zero 등의 결과가 달라 비채택했다. 기존 constant provenance와 implicit-zero는 유지한다.
요청 없는 방향 채널 생략 비채택했다. 사용하지 않는 고차 채널도 overflow·예외·finite 실패를 결정하므로 단순 생략은 실패를 성공으로 바꿀 수 있다. 필요한 방향·혼합 도함수는 모두 유지한다.
메모리 관리 서로 배타적인 빠른 경로와 기존 경로가 scratch 배열 하나를 공유한다. 단순 monotonic arena는 저장량 증가로 비채택했으며 범용 recycler는 구현·측정하지 않았다.

대표 local 평가의 Hessian 할당은 직접 방식에서 방향 없음 5416→4047회, 방향 있음 6452→4911회로 줄었다. 기존 방식은 7456→5733회, 7636→5897회다. MSVC Release 곱셈의 예약 stack은 통합 후보의 7696→5488 bytes로 2208 bytes 감소했지만 원래 5472 bytes보다 16 bytes 크고 __chkstk도 유지한다. 단순 arena는 직접 평가의 payload를 331776에서 18648576 bytes로 늘려 부적합했다. 이 할당·stack 수치를 전체 시간 단축률로 환산하지 않는다. 부동소수점 예외의 첫 trap, 수명·공유·동시·중첩 평가와 기존 private helper의 관성 consumer를 독립 검토했고 FMA·재결합·전역 compiler 옵션은 추가하지 않았다.

정식 모델 시간과 증분 기록

원본 reference/shellNL-dyn-meshfine/shellNL-dyn-meshfine.inp의 hash가 같은 새 복사본에서 MSVC x64 Release·동일 MKL/TBB runtime DLL·기본 스레드 환경·전원 조건으로 각각 한 번 실행했다. Ryzen7 5800H의 8 cores/16 logical processors 환경이며 별도 워밍업·VTune·동시 빌드·시험·모델 실행은 없다. 타이머는 Popen 요청 직전부터 wait 반환 직후까지로, 읽기·계산·복구·로그·HDF5 close/finalize를 포함하고 준비·빌드·비교는 제외한다.

실행 전체 초 분·초
새 TBB 기준 4134.657782 68분 54.66초
최종 개선본 3747.788261 62분 27.79초

이 단일 쌍에서 386.869521초(6분 26.87초), 9.356748% 감소·speedup 1.103226배를 확인해 improved로 판정했다. 변경하지 않은 Native Hex8 선형 사례에서도 약4.9% 시간 감소가 있었고, 긴 비선형·동일 CMake 경로의 Hex8/열 사례는 기준과 훨씬 가까웠다. 이는 실행 변동의 문맥이며 공식 시간을 보정하거나 분산·통계 신뢰도를 추정하는 데 사용하지 않았다. 현재 구체적인 환경·수치·반복 불일치가 없어 추가 쌍이나 profile은 실행하지 않았다. 한 쌍의 실측이며 반복 통계·다른 기계에서의 보장·특정 함수만의 기여를 입증한 것은 아니다. 기존 FEM-REQ-PERF-001..009와 Shell 100초 목표는 변경하지 않았고 여전히 미달이다.

두 실행 모두 증분0의 초기화와 양의 증분1..100을 구분했다. 모든 증분의 횟수가 같으며, 1..71은 Newton 보정 2회·로그 잔차 평가 3회, 72..100은 1회·2회다. 양의 증분 합은 171회·271회이고 초기화의 잔차 기록 1개는 별도다. 이는 고유 Newton 로그 기록 수이며 숨은 root·trial·assembly의 전체 호출 수가 아니다. 개선본의 초기화 9.044633초 + 스텝 합 3737.305479초 + 마무리 1.438149초는 전체 시간과 일치한다.

스텝 시간은 10ms 간격의 외부 accepted 로그 관측으로 얻은 경과시간이며 순수 요소 계산 시간이 아니다. 개선본의 최대 accepted 경계 관측 불확실성은 0.0329873초이고 누락·중복· observer 오류·구간 합계 오차는 없다. 이 경계 불확실성은 스케줄링이나 실행 변동의 상한이 아니다. 기준 CSV와 개선본 CSV에 101개 행의 시간·보정·관측 평가 수와 경계 간격을 보존했다.

정확성·회귀 결과와 남은 한계

정식 모델은 729절점·101프레임·schema2를 유지했다. HDF5의 2235개 dataset·27524개 attribute를 읽고 12358개 수치 leaf의 15066400개 성분을 대조해 finite·signed zero· 정수 identity를 포함한 수치 bytes가 모두 같음을 확인했다. 문자열 차이는 열거한 입력 경로 6개뿐이다. 전체729절점 내부 재현성과 외부9절점 참조의 U101 blocking family 통과를 구분하며, UR100 failed warning family·경고200개는 그대로다.

새 최종 검사 실제 실행 결과
Native MSVC x64 Debug 전체 1035개 = 1018 PASS / 기존16 FAIL / 기존1 SKIP
새 CMake Debug 전체 CTest 1036개 = 1019 PASS / 기존16 FAIL / 기존1 SKIP
Python 164 PASS
세 구성의 독립·원본 Jet 대조 구성별 5종, 총15개 명령 PASS

Native 단위915·통합74·참조46개와 CTest의 실제 등록·실행 identity를 대조했다. CTest에는 같은1035개 외 독립 Jet 검사1개가 포함된다. Native 단위 exit1·CTest exit8은 기준에서 재현된 실패 때문이며 전체 green이 아니다. 모든 기존 실패 assertion·수치·skip 진단은 명시한 source 경로와 GTest 시간 줄 외에 동일했고 신규 회귀는 없다. 원본 Hex8 동해석 101프레임 두 사례, 열 2차원 격자 수렴과 슬래브12개를 포함해 실행했다. 각 구성의 독립 항등식·원본42 private/64 public 사례·곱셈3072·누적192·alias8 대조도 통과했으며 기존 snapshot은 재생성하지 않았다. 결과 비교 도구는 동일 복사본/허용 경로 차이 2개와 값· signed zero·ID·예상 밖 문자열·NaN 검출 5개 대조 사례를 통과했다.

참조46개는 물리 모델46개의 정확성 통과를 뜻하지 않는다. 실제 분류는 positive Shell 검사3개·기타2개·policy/error 계약40개·기존 열 NT11 불일치 진단1개다. NT11의 87 failed rows·정규화 RMS0.049674084615673193은 기준과 동일한 수치 실패이며 진단 검사의 PASS를 열 정확성 PASS로 바꾸지 않았다. 정식 reference/shellNL-meshfine와 reference/shellNL-meshfine_02가 없고 후자의 전용 비교 계약도 없다. reference/temp는 사용하지 않았으며 정식 원본36개 파일의 전후 hash는 같다. 기존16 FAIL·1 SKIP·자료 누락, HHT 물리·시간 정확도와 열 필수 참조의 미해결 범위가 남아 전체 물리 검증은 미완료다.

기존 .build/cmake-debug 캐시는 다른 source root를 가리켜 그대로 보존했다. 이번에는 동일 preset에 -B .build/cmake-jet-debug를 지정하고 그 경로를 build·CTest --test-dir에 사용했다. 실제231개 compile command와 전체 검사 등록이 명시한 source/build 경로 외에는 기준과 같음을 확인했다. Native Release 명령의 include 경로 따옴표 차이는 Windows argv로 대조했고 옵션·순서·값은 같다. 과거 compiler binary SHA는 확보되지 않았으므로 동일 hash를 주장하지 않으며 보존된 compiler/pass 버전·경로·실제 옵션·SDK/runtime와 현재 hash를 기록했다.

전체 근거는 최종 비교, 검사·실행 요약, 독립 검토에 있다. 각 실행의 source· 실행물·입력·결과 hash와 raw·즉시 exit를 보존했으며, 자료는 로컬 .build에 있고 Git에 포함하지 않는다. 문서 갱신 뒤 제품 source가 바뀌지 않았으므로 build/test를 반복하지 않았다.

채택한 계산 경로와 수명

Matrix::Multiply는 dense GEMV/GEMM, SparseMatrix::Multiply는 CSR validate·finite/RHS/checked MKL_INT 확인 후 mkl_sparse_d_create_csr → mkl_sparse_d_mv → destroy를 사용한다. Const 호출마다 변환 배열·values 복사·handle을 소유하므로 copy/move·동시 호출에 backend pointer를 공유하지 않는다. Empty shape도 입력 검증 뒤 zero vector를 반환한다. 지속 symbolic cache나 scalar fallback은 없다. 호출마다 CSR 배열 복사 비용이 있으므로 MKL 연결만으로 전체 성능 향상을 주장하지 않는다.

Dense adapter가 MKL 세부를 감싸고 PARDISO와 tangent solver가 factor/solve/release를 소유한다. 성공한 동일 matrix의 여러 RHS는 재사용하지만 새 matrix·실패 분해의 stale factor는 쓰지 않는다. 기본1×1 SPD 호출의 기존 heap failure에만 local1-thread/TLS 복원을 적용했으며 vendor 원인은 미확정이다. Public core에 MKL 타입을 노출하지 않는다.

Hex8 high+low는 normalized pair의 원래 graph·ordered reduction·RN64 observable을 유지한다. LinearTangentCache는 동일 요소 복사본 사이의 불변 paired Hessian 두24×24 matrix만 call_once로 준비하고 nonlinear trial은 접근하지 않는다. Packet 경계·AVX2 구현·dispatch는 독립 b-lane의 순서를 유지하고 지원되지 않는 환경은 원래 scalar 경로를 사용한다. 이는 실패한 수치 계산을 다른 물리식으로 재시도하는 fallback이 아니다.

HHT trial context와 reduced procedure는 position 의존량과 rate 의존량의 재사용 수명을 구분한다. Nonlinear shell의 private Jet 영 seed는 정의된 numeric zero/도함수 provenance만 최적화하고 NaN/Inf·singular composition 실패를 지우지 않는다. 절점6×6 outer/full24 scatter 후보는 관련 검사가 통과했어도 단일 micro 차이 약1.44%와 production 호출 빈도 미확인으로 보류·복원됐으며 현재 채택 경로가 아니다.

일반 Float64 행렬 곱은 MKL을 쓰지만 작은 고정 좌표 계산, high+low·보상 누적·outward interval 인증은 해당 정밀도와 오차 의미를 보존한다. Thermal RHS를 두 행곱 차로 재배치한 후보는 cancellation oracle를 깨뜨려 폐기했다. 현재 entry association (c/delta)*(old-g)-k*g와 row 순서를 유지한다. 연산 순서·zero 부호·floating exception 상태도 실제 계약에 필요한 범위에서 검증한다.

시간·결과·reference 계약

공통 CLI·source identity·lease·atomic HDF5·비교 기준은 solver-core, 물리 의미는 Hex8·HHT를 따른다. Time step·increment·Newton gate·질량·적분점·출력량·schema·정밀도를 성능 때문에 줄이거나 바꾸지 않는다.

기준 환경은 Ryzen7 5800H Windows/MSVC x64 최적화 Release다. 동일 thread·runtime·전원·compiler 조건에서 워밍업 없이 모델별 별도 process를 한 번 측정한다. Process 시작 요청 직전부터 정상 종료 직후까지 읽기·계산·복구·로그·HDF5 close/final 교체를 모두 포함한다. 빌드·입력 복사·VTune·비교는 구간 밖이다. Debug 시간·CPU 합계·계측 elapsed·반복 중 최솟값을 목표 판정에 쓰지 않는다.

원본 case 목표 초 기존 단일 baseline 초 당시 수치 비교
hexa_nonlinearstatic 2 10.914924 U/constrained RF/point S 통과
hexa_dynnonlinear 100 402.069447 101-frame 전체 U 통과
shellNL-dyn-meshfine 100 6372.325621 729-node inventory·101-frame 확인,9-node U blocking 통과·UR warning200 entries

이 baseline은 세 목표 모두 미달이다. 최종 source의 세 모델 새 결과·공식 시간·전체 Debug·필수 reference·독립 검토가 모두 필요하다. 공유 consumer 회귀에는 Hex8 원본5개(정적2·고유치·동적2)의 기존 비교도 포함한다. 수치 판정은 source/frame/component·finite/schema 검사를 먼저 통과하고 공통 near-zero1%·일반 행5%·family RMS1%·zero-scale exact-zero를 적용한다. MITC4 eigen 예외를 Hex8에 쓰지 않는다.

실제 근거와 남은 범위

Hex8 기하 packet 수정본의 관련 Debug/Release82개씩, 독립 snapshot9,804행·전체 bytes 일치 기록이 있다. 이전 Release ordered-overflow 사례는 값 bit가 같아도 INVALID FE/MXCSR가 달라 실패했다. Nonfinite 첫 sum에서 원래 checked scalar bridge로 돌아가 error 계산을 생략하는 수정 후 통과했으며 flags clear·기대값 완화로 숨기지 않았다. 이 검증을 전체 모델 시간이나 모든 source의 현재 PASS로 확대하지 않는다.

그 수정본의 단일 동적 개발 실행은 native0·117.7986225초로 완료됐으나100초 목표 초과다.101 U frame 비교는 blocking PASS, 최대 relative RMS 약2.155586e-6이었다. Outer wrapper는 종료 자식의 null StartTime 처리에서1로 끝났고 실제 FESA native0·후속 comparator0과 구분한다. 이전135.9302297초와의 차이는 서로 다른 source의 단일 개발 표본이며 반복 통계나 특정 함수 비용이 아니다.

Shell 명시 영 seed 이후 SW60 수집은 partial이며 collector native4·target 종료 미관측, increment1까지 진행했다. 함수 sample의 Jet 산술·할당·작은 MKL 호출·OpenMP spin은 비용 후보지만 sample 부재를 cache hit 보장으로 바꾸거나 nested inclusive CPU를 합산해 wall time을 만들지 않는다. 전체 shell100초·최종 전체 Debug·원본5개 재실행·최종 물리 평가는 미완료다. 보류 후보의 PASS를 복원 source나 최신 통합본에 승계하지 않는다.

Refactor 통합 후 남은 성능 한계

Refactor의 2026-10-16 0b8de3a 당시 기록은 ShellNL whole elapsed가 원본 대비 Native+86.52%·CMake+120.91% 회귀했다고 보고한다. 이는 해당 source·환경의 과거 단일 기록이며 변산·메모리·배경 부하와 원인은 미확정이다. 이후 객체 복사 제거 revision의 정적 검증을 새 Release 성능 향상으로 승계하지 않는다. 원본 .build archive는 통합 작업 공간으로 자동 전달되지 않았으며 이번 병합에서 해당 시간의 원시 근거를 새로 재현한 것은 아니다. 통합된 코드와 정적 검증 범위는 병합 현황을 따른다. 새 Release 성능은 측정하지 않았다. 지속 SpMV cache나 새 산술 최적화를 도입한 것은 아니며, 성능 회귀 원인 해결·새 benchmark는 별도 작업으로 남긴다.