Files
FESADev/docs/calculation-performance/verification.md
T

18 KiB

계산 성능 기준 측정과 도구 검증

T1은 production 계산 코드를 변경하지 않고 Release 설정, 외부 측정기와 기준 실행·VTune 자료를 준비한다. 최종 전체 Debug 회귀는 T5 책임이다. 기준 실행은 승인된 계산 소스 eaa5cbeb21b231862ed80f89386412232b0571c9와 동일한 production 파일로 수행한다. 시간 목표 초과는 기준자료의 미달로 기록한다.

재현 명령과 소유권

MSVC x64 Developer PowerShell에서 기존 로컬 GoogleTest/MKL/TBB/HDF5 설정을 사용한다. 공용 source에는 개인 경로나 자동 다운로드를 추가하지 않는다.

cmake --preset windows-msvc-ninja-release
cmake --build --preset windows-msvc-ninja-release --target fesa_cli --parallel 8
python scripts/performance/measure.py --exe .harness/build-ninja-msvc-release/src/fesa/fesa.exe --output-dir <새 artifact 디렉터리>

Release는 /O2 /Ob2 /DNDEBUG /Zi, link는 /DEBUG /OPT:REF /OPT:ICF다. 기존 Debug preset과 개인 config를 유지한다. 측정기만 단조 증가 시계와 native 프로세스·raw 실행 기록을 소유한다. 각 입력을 독립 디렉터리에 byte-copy하고 프로세스 시작 직전부터 종료 확인 직후까지 측정한다. 복사와 hash, HDF5 inventory, 외부 비교는 타이머 밖이다. timeout은 공식 CLI에서 설정하지 않는다.

2026-10-14 사용자 승인 PERF-ADR-004에 따라 워밍업 없이 모델별 1회만 측정한다. 각 새 결과의 identity·전체 frame·finite precheck를 기존 comparator의 reader로 검사한다. Hex8은 기존 schema/row 검사를, shell은 729 nodes/101 frames와 schema v2 및 실제 scratch 경로를 검사한다. 이 검사는 외부 reference 수치 비교의 통과를 의미하지 않는다. 실행 실패·중단·환경/source/binary 변경은 합격을 차단하고 완료된 raw 기록을 남긴다.

각 run의 native.json·run.json·로그·새 HDF5를 보존한다. measurements.json은 각 행이 완료된 뒤 atomic replace하며 중단된 case나 미시작 case를 완료 표본으로 채우지 않는다. 성공한 느린 실행도 제외하지 않는다. 측정기 exit 0은 정상 전체 실행·기록 완료, exit 1은 실행/기록 실패, exit 2는 잘못된 CLI다. exit 0은 시간 목표나 외부 비교의 합격이 아니다.

비교는 각 실제 scratch/result/native로 별도 실행하며 comparison.json을 run 디렉터리에 둔다. Hex8 명령은 다음 형태다.

python scripts/verification/compare_hex8.py --case <case> --input <scratch.inp> --results <new_results.h5> --references reference/hexa --execution-record <native.json> --report <run/comparison.json>
python scripts/verification/compare_hht_dynamic.py --input <shell-scratch.inp> --results <new_results.h5> --reference "reference/shellNL-dyn-meshfine/shellNL-dyn-meshfine displacements.csv" --report <run/comparison.json>
python scripts/performance/measure.py --output-dir <artifact/measurements> --link-comparisons

연결 단계는 input/result/native SHA-256과 raw 경과 시간을 확인한다. Hex8 합격에는 비교기가 검증한 동일 native record hash가 필요하다. Shell의 U blocking/UR warning 정책은 기존 비교기를 그대로 따른다. 연결 단계는 raw 시간과 native 기록을 변경하지 않는다. 비교 전 상태는 pending이다.

행동 검사

uv run --offline --with pytest --with numpy --with h5py python -B -m pytest -q tests/test_performance_measure.py

측정기 구현 전 같은 명령 exit 1(measure.py 부재)을 확인했다. 실제 subprocess와 독립 관측으로 타이머 경계·copy byte 보존·실행 분리·기존 출력 충돌·native nonzero/출력 존재·launch failure·입력 mutation·중단/timeout 기록, native 0의 missing/invalid HDF5, 느린 표본 보존과 source/binary 변경 차단을 검사한다. 비교 연결은 raw 시간 보존 및 다른 result hash 거부도 검사한다. 단일 측정 변경과 독립 검토 수정 전에는 6 FAIL/11 PASS, exit 1을 확인했다. 현재 관련 검사는 19 PASS, exit 0이다. 실제 Hex8 HDF5의 NaN/Inf 및 0이 아닌 동적 초기 변위를 기존 check_result_values로 거부한다. native 종료 뒤 HDF5 검사 중 KeyboardInterrupt는 native completed/exit 0/경과 시간/hash를 보존하고 result_validation_state=interrupted, execution_valid=false 행을 공개한 뒤 exit 1로 종료한다. 이전 case의 완료 행도 남는다. native 행 반환 뒤 환경 재검사 중단/실패도 별도로 2 FAIL, exit 1로 재현했다. 환경 재검사 전에 현재 행을 먼저 공개하고, environment_validation_state가 interrupted|failed인 행의 실제 native/elapsed/hash를 유지해 exit 1로 종료한다.

현재 기준 자료

새 공식 단일 기준 자료 위치는 repository root의 .harness/performance/baseline/t1-single-20261014-122548/다. MSVC 19.51.36252 x64, MKL 2026.1.0, TBB 2023.1, HDF5 2.1.1, VTune 2026.2.0 build 632324를 사용한다. 전원·CPU/OS·실제 cache/flags, dependency DLL hash/version, source commit/dirty, thread 요청은 JSON에 기록한다. MKL/OMP thread 요청은 8, dynamic FALSE다. TBB는 runtime default이며 TBB_NUM_THREADS를 실제 적용된 cap으로 주장하지 않는다.

설치된 VTune help를 보존했으며 software sampling은 10ms fixed다. -collect hotspots -knob sampling-mode=sw -knob enable-stack-collection=true -knob enable-characterization-insights=false -result-dir <profile> -- <exe> <scratch.inp>를 사용한다. characterization 하드웨어 카운터는 끄고 제품 PDB와 동일 Release binary로 수집한다. 정적은 full, 두 dynamic은 -duration 30의 partial 수집이다. 부분 수집은 전체 시간 합격 표본이 아니며 collection 종료의 native/tool 상태를 full 실행과 구분한다. raw 결과와 function/callstack CSV를 보존한다.

VTune raw/function/callstack 자료는 같은 Release binary의 재부팅 전 자료 .harness/performance/baseline/t1-20261014-0845/profiles/에 보존한다. 주요 product 함수와 source는 식별됐다. 일부 vendor 함수는 주소로만 식별되며 해당 vendor의 private symbol은 확보하지 않았다. 이 한계와 partial 수집을 구분한다.

이전 프로토콜과 재부팅 이력

사용자는 장시간 작업 중 PC 중단을 알리고 단일 측정으로 변경했다. 원인은 입증되지 않았다. 실제 OS LastBootUpTime은 2026-10-14T09:33:20.5000000+09:00다. 복구 시 fesa/VTune/build/측정 프로세스 조회는 비어 있었다. Win32 전원 조회는 AC line 1, battery flag 128이었다.

과거 .harness/performance/baseline/t1-20261014-0845/measurements/measurements.json은 static 워밍업+측정 5개, dynamic 워밍업+측정 4개 완료 행을 보존한다. dynamic 측정 5의 native 종료·경과 시간은 관측되지 않았으며 native record와 최종 HDF5가 없다. Shell은 시작하지 않았다. 해당 run의 scratch와 기존 raw 기록을 보존하며 부재·현재 hash·재부팅·프로세스 조회를 recovery-20261014.json에 기록했다. 과거 결과는 공식 단일 판정에 사용하지 않는다.

과거 frozen reader는 Hex8 schema/identity/frame을 검사했으나 독립 검토에서 별도 check_result_values 누락과 HDF5 검사 중 중단 행 누락이 발견됐다. 두 문제는 위 행동 검사로 재현·수정했다. 과거 elapsed/native 기록을 수정하지 않았고 frozen script SHA-256 34772002e774efe566b5331641285a5dadb2194b10e2c365f90a561ba521ef04도 build/measure-frozen-baseline.py로 보존했다. 새 공식 결과는 수정된 검사와 전체 기존 comparator를 적용한다.

공식 단일 기준 실행 상태

독립 conformance 재검토 통과 뒤 준비 commit bf512d137c8eda8b2bc02ab1330ceba0b8ba678a에서 모델별 1회만 실행했다. 워밍업과 별도 캐시 초기화를 수행하지 않았다. 측정 중 code/doc/gitstatus, binary/DLL/thread/power 환경을 고정했다. 측정기 exit 0이며 각 solver도 실제 exit 0이다. source/schema/frame/finite/초기 상태 및 환경 재검사를 통과했고, 기존 전체 comparator를 타이머 밖에서 실행했다. 비교 연결 exit 0이며 raw elapsed/native 기록을 수정하지 않았다.

모델 목표 초 전체 wall 초 native 외부 비교 시간 판정
hexa_nonlinearstatic 2 10.914924 0 전체 U/constrained RF/point S 통과 미달
hexa_dynnonlinear 100 402.069447 0 101 frames 전체 U 통과 미달
shellNL-dyn-meshfine 100 6372.325621 0 729 nodes/101 frames 확인; 9 nodes U blocking 통과, UR warning 200 entries 미달

세 comparator의 실제 exit는 각각 0이며 reference/결과의 identity와 finite 검사 뒤 기존 row 상대 허용 0.05, relative RMS 0.01, near-zero ratio 0.01을 적용했다. 최대 blocking relative RMS는 정적 9.338900e-6, 동적 2.155586e-6, shell U 0.0022824245다. UR warning은 기존 정책의 경고이며 회전 정확성 통과로 표시하지 않는다. 기준 자료 확보와 수치 비교는 완료됐으나 시간 목표는 세 모델 모두 실패다. baseline 시간 목표는 T1의 진행 차단 조건이 아니며 최적화/최종 전체 검증은 후속 작업이다.

실제 판정과 run/input/binary/result/native/comparison hash는 공식 measurements.json에 연결됐다. execution_complete, comparisons_complete, all_comparisons_passed는 모두 true이고 각 all_measured_runs_within_target은 false다. run.json/native.json은 실행 당시 raw 기록, 외부 비교의 현재 연결 상태는 최종 aggregate의 각 행이 소유한다.

VTune 비용과 후속 owner에 넘길 범위

재부팅 전 같은 binary의 정적 full profile은 TwoSum 1.648 CPU 초, Multiply 1.055 CPU 초, LowestBitExponent 0.615 CPU 초를 관측했다. 동적 Hex8 30초 partial은 각각 37.424, 17.042, 22.038 CPU 초와 ldexp 19.263 CPU 초를 관측했다. high+low/정밀도 의미를 변경할 근거로 사용하지 않는다.

최초 shell 30초 로그는 initial increment 0만 포함했다. 공식 시간 측정과 3개 비교 종료 뒤 동일 binary/source/thread 설정에서 sw 150초 partial을 1회 추가했다. 실제 accepted increment 2/time 0.2까지 포함하며 수집 종료 후 target/collector 프로세스가 없었다. VTune collector의 실제 native exit는 4, 함수/stack report의 실제 exit는 각각 0이다. target 자체의 종료 코드는 별도로 관측하지 않아 null이며 정상 전체 해석 표본이 아니다.

150초 partial의 함수/모듈 sampled CPU 초 전체 sampled CPU 비중
shell Jet operator* 133.466 27.6%
libiomp5md 주소 함수 70.081 14.5%
malloc_base 30.289 6.3%
MKL PARDISO blkl_omp_mic_vbsr_real 27.669 5.7%
inertia Jet operator* 26.257 5.4%

T2 math/linear owner에는 CheckGraphRegularity → CheckSelectorTransversality → MklPardisoTangentSolver::FactorizeFresh/SolveCorrection → pardiso 경로를 넘긴다. leaf call-path의 양수 CPU weight를 caller별 한 번 합산한 보조 분석은 graph regularity 2.434118 CPU 초, nested selector 1.600014 CPU 초, PARDISO 42.725655 CPU 초다. flat 함수별 CPU와 call-path weight의 합계가 일치한다. 이는 중첩 inclusive attribution이며 서로 합산하거나 wall time으로 바꾸지 않는다. 현재 표본에서 graph/selector가 주된 병목이라고 단정할 근거는 없다.

T4 element/assembly owner에는 shell/inertia Jet 곱셈·할당과 EvaluateInternalResidualAndTangent/EvaluateAssembly의 TBB 경로, allocator 및 MKL/OMP 소비 자료를 넘긴다. EvaluateAssembly caller의 보조 inclusive CPU는 257.862958 초다. 아직 수치 구현을 변경하거나 향후 개선 배수를 추정하지 않았다.

보존과 검증 범위

실행 binary SHA-256은 fdb77bc39cc518d509e6bcf679d91f75d67a8c0bbde6b505fe555030274eccfb, 공식 측정기 hash는 4ae3dfcee43cd9aa25ce11a1a1c6d87646f745b881fac9ad6c79a52e1bc5b082다. 실제 exe/PDB/DLL은 parent artifact의 build/binary/에 복사했고 공식 환경의 모든 runtime DLL hash와 비교해 일치를 확인했다. 살아 있던 공식 Shell의 실제 DLL module 경로도 모두 Release exe 옆 staged DLL이었다. source numerical diff는 승인 baseline 대비 비어 있다.

Release build 범위는 fesa_cli다. Release CTest discovery exit 0의 3개 항목은 모두 *_NOT_BUILT placeholder이며 검사 통과가 아니다. 전체 MSVC x64 Debug build/CTest는 T1에서 실행하지 않았으며 후속 T5의 필수 검증으로 남는다. 원본 reference, 물리·질량· high+low·수치 tolerance와 결과 schema를 변경하지 않았다.

통합 source의 영향범위 Debug 검사

81757022806746addbb71ba101e0393a32ff48fd에서 Hex8 pair packet/guard와 셸 MKL·완성 trial 재사용을 함께 빌드해 consumer 상호 작용을 확인했다. MSVC x64 Debug configure/native0, unit·integration·CLI consumer 115 build edges/native0, Hex8 actual Ninja dependencies16/native0을 확인했다. Hook SHA는 00B39E0F778301785BC9F8DC9C8FA2A834C2E7D6FC9421D9EB0928BCA78FCC8F다. 관련 Hex8·산술·reduced shell·초기 Newton·private policy 검사 111개가 모두 통과했다(native0, CTest27.62초). 별도 discovery도 native0/111개다.

이 검사는 기존 corrected-prefix tree의 재빌드이며 최종 fresh/full Debug 검사가 아니다. 장시간 mixed-time 검사와 선택하지 않은 C08·다른 suite의 판정을 제공하지 않는다. 최종 reference/시간 목표와 독립 물리 검증도 대체하지 않는다. CPU 작업은 직렬로 실행하고 완료 후 관련 프로세스0을 확인했다. 준비 중 discovery 삽입과 delivery 메타데이터의 PowerShell 오류는 별도 기록으로 보존했고 실제 명령 결과와 구분했다.