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

21 KiB
Raw Blame History

Hex8 계산 경로 개선 기록

이 기록은 성능 요구사항의 Hex8 구현 범위와 개발 검증을 설명한다. 기준 작업 소스는 8c7c41729eb9eaa904f6739b54d34c37b1bd555f다. MKL 경계 수치 소스는 71e08169ecfc3eee8372cd831b799b87aa47c78b에서 검토·검사했으며 이후 43c747f는 오류 우선순위 검사 두 개만 추가했다. 6d709fd는 trial-local 반복 연산 제거로 별도 검토·검사했다. 후속 774bfbc는 geometric 첫 곱을 같은 point 안에서 재사용하며, 6bc5cd3은 아래 선택적 paired Hessian의 준비 수명을 바꾼 소스다. a08df0f는 동시 호출 검사의 시작 대기 조건만 추가했고 같은 production을 새 Debug/Release로 검증했다. 후속 병합 45aac19에는 root의 공통 finite classifier 47d2a81이 포함된다. 이 병합 뒤의 소비자 재빌드와 동적 개발 실행은 문서 commit decd959에서 수행했다. 이전 검사 결과를 새 소스의 통과로 대입하지 않는다. 공식 기준 Release 소스와 이 개발용 Debug 대조 소스를 혼용하지 않는다.

실제 병목에 대응하는 변경

기준 VTune의 TwoSum → Add → Multiply → hex8_high_low::operator* → EvaluateHighLow 호출 경로에서 확인한 pair 산술 비용을 줄였다. 이 단계에서는 공통 high+low 산술을 바꾸지 않고 Hex8 private hex8_pair_arithmetic.h에 두 helper를 추가했다.

  • AddPair는 양쪽 입력의 finite·normalized 검사를 먼저 수행한다. Canonical zero operand만 항등원으로 처리하고 결과 low의 signed zero를 원래 Add와 같은 +0으로 만든다. 두 항이 비zero면 원래 Add를 그대로 호출한다.
  • MultiplyPair는 같은 입력 검사를 유지한다. Low가 zero인 경우에만 정확히 zero인 cross-product와 반복되는 zero Add를 생략한다. Nonzero component의 곱 순서는 원래와 같으며 TwoProduct의 least-bit underflow 판정, FMA tail, overflow 실패를 유지한다. 두 low가 모두 비zero면 원래 Multiply를 호출한다.

Normalized pair에 zero를 더하는 원래 연산은 값과 비zero low를 보존하며 low의 zero 부호만 canonicalize한다. 한 번 수행한 뒤 반복해도 같은 결과이므로 이 항등 연산만 줄일 수 있다. 임의의 작은 값이나 거의 zero인 값을 제거하지 않는다. Signed zero·비정규화 pair·비유한 값은 shortcut 전에 원래 guard에서 거부한다. 최종 독립 수치 검토는 이 증명과 아래 MKL·오류 수명 경계를 확인했다. 검토 PASS는 실제 실행이나 공식 전체 성능 합격을 대신하지 않는다.

동일 trial point에서 deviatoric_coefficient*fg, mu*fg, mu*fft의 첫 곱을 각각 24·24·9개 준비한다. 원래 576개 tangent entry마다 같은 첫 곱을 반복했던 경로에서만 재사용하고 두 번째 곱과 덧셈 association은 유지한다. Bulk의 같은 첫 곱도 row별 24개 준비한다. 다음 trial에서는 새로 계산하며 reference나 다른 trial의 constitutive 값을 가져오지 않는다. 이 변경의 독립 검토는 같은 입력·연산으로 생성한 pair의 bit 및 invalid propagation이 유지됨을 확인했다.

Geometric의 gradient[a][j]*s[l][j]도 b에 무관하므로 point별 72개 첫 곱으로 준비한다. 원래 뒤의 gradient[b][l] 곱과 j/l 누적 순서는 그대로다. 이는 nonlinear trial point의 automatic storage 1,152 bytes이며 global 또는 다른 trial의 cache가 아니다. 새로운 조기 finite 반환이나 clamp를 넣지 않는다.

선택적 paired Hessian의 준비 수명

현재 정적 모델은 Float64 Evaluate를 사용한다. 개발 static VTune에서 paired EvaluateHighLow는 Create가 선택적 zero-Hessian을 미리 준비하는 경로에 나타났다. 초기 보고에서 static에 EvaluateSolids를 연결했던 설명은 잘못이었다. EvaluateSolids는 원래 dynamic profile의 경로이며 이번 static에는 없다. 소유 경로별 집계는 Create의 descendant sampled CPU 5.15735초, writer 2.750676초, static state 2.626941초를 보였다. 중첩 그룹이며 각 메서드의 header-leaf 자체 비용은 제외되어 완전한 inclusive 총합이 아니다. 또한 71e0816 binary 자료를 후속 후보의 비용으로 소급하지 않는다.

기존 Create는 선택적 paired 준비가 실패해도 F64 모델을 거부하지 않았다. 따라서 현재 후보는 모든 필수 Create geometry/material/reference stiffness/finite/positive diagonal 검사를 유지하면서 이 선택적 준비만 첫 유효 EvaluateLinearHighLow 호출로 옮긴다. Float64 static·state·writer는 사용하지 않는 pair 준비를 하지 않는다. Nonlinear paired 계산은 이 cache의 ready/data를 읽거나 준비하지 않는다.

준비는 실제 trial의 환경·shape·normalized relative state·전체 current geometry 검사를 통과한 뒤 실행한다. call_once의 zero-trial callback은 같은 private paired quadrature graph를 쓰며 재귀적인 once 진입을 명시적으로 건너뛴다. Unsupported rounding/FTZ/DAZ 호출은 once에 들어가지 않으므로 환경 복원 뒤 정상 호출이 준비할 수 있다. 성공한 high와 low Hessian을 모두 저장한 뒤에만 ready를 설정한다. 정상 trial 입력을 cache에 저장하지 않는다.

Private prepared-data에는 once flag·ready와 두 matrix만 있다. 같은 owned reference coordinates/points/material을 복사한 Element끼리 공유한다. Caller나 Domain 주소에 의존하지 않고 callback의 this를 이후에 저장하지 않는다. 성공한 저장량은 24×24 high/low 각 하나, logical value 9,216 bytes와 metadata다. 다른 trial의 cache/history가 누적되지 않는다. Const 첫 호출의 동시성은 once로 동기화한다. 실제 서로 다른 trial과 copy·move의 첫 호출 검사는 모든 worker가 시작 대기에 도달한 뒤 함께 해제하며, 원래 전체 pair snapshot도 별도로 대조했다. Once 횟수와 최대 저장량의 source 구조 증명은 native 결과와 구별한다. 수명과 동기화의 독립 검토는 6bc5cd3 production 소스를 확인한 자료다.

MKL 적용과 연산 순서

경로 일반 연산 / MKL 경계 보존한 의미
Hex8Element::Create Deviatoric·shear·bulk의 24×24 rank-one outer → Matrix::Multiply / DGEMM k=1 Coefficient를 왼쪽 값에 먼저 곱하고 기존 point·entry 순서로 누적
Hex8Element::Evaluate 같은 24×24 outer와 node/component permutation → DGEMM k=1 기존 material/geometric 분리와 최종 tangent 합
GradientProduct Node Gram의 192 entry products → private MultiplyDiagonal / DSBMV k=0 원래 (p0+p1)+p2 association
GradientProduct의 geometric 경로 64개 entry의 9 terms, 두 단계 entry products → DSBMV k=0 원래 ga[j]*s[l][j] 뒤 gb[l] 곱, 원래 j/l 순서의 누적
Hex8Element::ComputeMass 8×8 rho*N_a*N_b outer → DGEMM k=1 Weight를 뒤에 곱하고 전체 consistent matrix의 행합을 BC 축소 전에 계산

Gram과 geometric 연산을 일반 GEMM으로 재결합했던 후보는 채택하지 않았다. 중간 G*Sᵀ의 큰 합이 원래 term별 연산에는 없는 overflow를 만들 수 있기 때문이다. 현재 entry products는 MKL을 사용하면서 원래 association과 ordered sum을 유지한다. Workspace는 단발 192 또는 576개의 연속 값이며 지속 cache나 global dense matrix를 만들지 않는다.

공통 Matrix와 private diagonal adapter의 finite 입력 검사를 유지한다. 전역 thread 설정이나 vendor dispatch, PARDISO 제어, controller·수렴 기준은 바꾸지 않았다. 작은 MKL 호출의 비용을 아직 공식 전체 실행의 개선 효과로 단정하지 않는다.

실패한 계산과 진단

MKL 입력 검증이 이미 실패한 point 또는 bulk block에서만 원래 scalar 식을 진단용으로 재현한다. 이는 원래 실패 위치와 뒤따르는 gate의 우선순위를 유지하기 위한 경로다. backend_inputs_failed가 남으므로 기존 검사들이 모두 통과해도 정상 element/response를 반환할 수 없다. 이 경우 명시적인 MKL finite-validation 실패로 종료하며 직접 계산한 성공 결과로 대체하지 않는다.

Create의 volume·stiffness finite·positive diagonal 순서, Evaluate의 point tensor· 최종 energy·각 row force/tangent 검사를 유지한다. 뒤 point의 geometry나 tensor 실패가 먼저 선택되는 의미도 보존한다. 진단용 candidate는 caller state, accepted history, 최종 HDF5로 발행하지 않는다. 비유한 operand를 zero로 바꿔 backend를 실행하거나 tolerance를 완화하지 않는다.

Density는 Create에서 finite positive로 검증되고 Gauss shape는 불변이며 (0,1)에 있다. 따라서 mass의 rho*N_a 입력은 finite다. Product와 weight 뒤 finite 검사, consistent 누적 검사, 전체 행합의 positive/finite 검사는 각각 원래대로 남아 있다.

특수 정밀도와 소유권

파일 / 연산 크기·정밀도 예외 근거
hex8_high_low.cpp의 tensor·force·energy·24×24 tangent Normalized binary64 high+low Low 상태와 underflow-risk tail 정책을 Float64 BLAS로 대체할 수 없음. Shortcut은 원래 bit oracle와 독립 증명으로 제한
hex8_geometry.cpp의 whole-cell geometry certificate Fixed3 좌표, outward interval 전체 cell 양성 판정·depth 10·budget 65536을 유지. 변경 없음
hex8_element.cpp의 F/S/P/FFT/stress 좌표 tensor Fixed3×3 좌표·구성 관계 좌표 contraction이며 일반 node outer와 구별. 변경 없음
같은 파일의 displacement 차이와 force contraction FMA residual 및 보상 누적 큰 translation에서 tiny strain을 보존하는 오차항과 association 유지
solid_static_procedure.cpp의 uncancelled arithmetic scale 원래 CSR products의 절대값·오차 인증 누적 물리 matrix action이 아니라 기존 linear residual의 roundoff certificate. 변경 없음
MKL 검증 실패 block의 원래 scalar 식 실패 진단 전용 정상 성공 반환이 금지된 진단 재현. 성공 matrix action의 대체 경로가 아님

Element는 reference coordinates·gradients·weights를 값으로 소유한다. 새 helper나 MKL workspace는 호출 수명이며 trial 상태를 주소로 재사용하지 않는다. Relative high+low gradient0은 다른 gradient들의 negative pair sum을 그대로 사용한다. Mean-volume energy, full reference row-sum mass, point identity, RN64 출력 및 geometry/trial 검사를 변경하지 않았다. 조립의 deterministic tuple reduction과 parallel buffer 소유권도 변경하지 않았다.

실제 개발 검증

범위 실제 결과 근거
새 MultiplyPair oracle, production은 원래 경로 Debug configure/build 0, Hex8 46/46 PASS Native, log
Production 71e0816 Debug build 0, Hex8·static·frequency·paired state/kinematics 84/84 PASS, native 0 Native, log
43c747f tests-only delta Build 0, overflow 진단 우선순위 2/2 PASS, native 0 Native, log
6d709fd trial-local 반복 연산 제거 Debug build 0, Hex8 48/48 PASS, native 0 Native, log
동일 TU의 원본/현재 Debug 진단 대조 60 finite-input 조합, 출력 306행 동일, 각각 native 0 Native, comparison, original manifest
a08df0f 선택적 준비 수명 Fresh Debug configure/build 0, Hex8·paired state/kinematics·serial/TBB 59/59 PASS, native 0 Native, 검사, dependencies
같은 TU의 원본/current pair snapshot Flat/warped, linear/nonlinear 전체 response의 raw bits 9,804행 동일, 양쪽 compile/run native 0 Native, 대조
decd959 공통 finite classifier 통합 Correct-prefix Debug configure/build/deps 0, HighLowArithmetic·Hex8·paired·serial/TBB 68/68 PASS, native 0 Native, 검사

Pair oracle는 고정된 원래 산술 header를 사용하여 raw high/low bits를 비교한다. Signed zero·half-ulp·invalid·최소 subnormal·최대값·overflow·underflow 경계, 모든 power-of-two exponent와 양 부호, 12,000개의 deterministic raw random 입력을 포함한다. 기존 analytical·energy/force/tangent·rigid·warped patch·mass· geometry·cached failure·state 보존 검사와 함께 실행했다.

별도 Release 개발 probe는 원본 정적 입력을 각각 새 scratch로 복사하여 워밍업 없이 소스별 1회 실행했다. 최초 43c747f는 9.4669573초, 반복 연산을 줄인 6d709fd는 5.2753221초, 선택적 준비를 지연한 a08df0f는 1.7391958초였다. 각각 native 0, identity·finite·완전한 결과 검사와 기존 전체 U/constrained RF/point S 비교를 통과했다. 최초 실행, 후속 실행, 후속 비교, 선택적 준비 지연 실행, 해당 비교를 모두 보존한다. 서로 다른 개발 소스의 값이며 빠른 값을 골라 공식 표본으로 쓰지 않는다. 마지막 개발 값은 2초 이내지만 최종 통합 소스의 공식 목표 합격은 아직 아니다.

최초 개발 Release binary의 VTune 함수 자료와 호출 경로, 실제 명령과 native 기록을 보존한다. Software sampling 10ms·stack 수집·hardware characterization 비활성 설정이다. Collector와 두 export는 native 0이며 target native는 독립 포착하지 않아 null이다. CPU 17.227초 중 effective 8.093초, spin 8.171초였고 iomp worker 6.605811초, LowestBitExponent 0.904216초, TwoSum 0.458413초, MultiplyPair 0.364517초였다. Fpclassify 29곳의 exclusive sampled CPU 합은 1.61345초다. Inclusive 호출 경로의 시간과 합산하지 않고 프로파일 경과 시간을 공식 목표 판정에 대입하지 않는다.

원본 Debug library와 candidate를 같은 TU·compiler flags·runtime DLL로 대조했다. 원본 library의 Hex8 production은 8c7c417이며 새 standalone helper 검사만 있던 build다. 이 진단의 컴파일/실행을 CTest 종료 확인 전에 시작하여 약 10초 CPU 작업이 겹쳤다. 겹침 기록을 보존하며 해당 elapsed는 성능 evidence에서 제외한다. 이미 완료된 동일 진단을 반복하지 않았다. Finite 조합의 동일 결과를 모든 극단 입력의 증명으로 확대하지 않는다.

기존 Debug/Release Ninja의 MSVC include prefix가 깨졌고 조사한 Hex8 object의 header dependency 수가 0이었다. 실제 조사를 보존한다. 산술 변경의 cpp 직접 재컴파일 로그는 있지만 header-only rebuild의 정확성은 보장하지 않는다. 1d77e6b는 private include guard만 고친 별도 commit으로 산술 본문은 같다. 최종 검증과 공식 Release는 정상 dependency를 갖춘 fresh build가 필요하며 기존 개발 build를 최종 검증으로 확대하지 않는다. VSLANG=1033만으로는 현재 설치의 Korean MSVC resource 문제를 해결하지 못했다. Root가 확인한 실제 prefix hook으로 a08df0f의 fresh Debug/Release build를 구성했다. 각각 Hex8 high+low object의 Ninja dependencies 15개와 private/public header를 확인했다. Release 기록은 configure/build와 dependency 검사의 실제 명령을 보존한다. 이번 private class layout의 변경에는 factory·state·writer 등 모든 소비자를 새로 컴파일해야 하며 옛 object를 수동 복사하거나 선택적으로 섞지 않는다.

Pair snapshot의 원본 executable은 8c7c417 전체 include tree를 동결하여 원본 library와 함께 컴파일했다. Current executable은 current header와 fresh current library를 사용한다. 같은 probe TU와 Debug flags를 쓰되 두 executable의 response만 대조했다. Current header를 원본 library에 연결하면 Hex8Element의 private layout 변경으로 ABI가 맞지 않으므로 이 조합은 사용하지 않았다.

Root의 별도 47d2a81 finite bit-classification 소스는 45aac19에서 통합했다. Root의 독립 검토와 62개 검사는 별도 공통 산술 자료다. 이 병합 뒤 올바른 include prefix metadata를 가진 기존 fresh tree에서 Debug 15개, Release 8개 build edge로 실제 header 소비자를 재컴파일했다. Hex8 high+low dependencies 15개를 다시 확인했다. Release 재빌드의 configure/build/deps 모두 native 0이다. 이전 개발 시간이나 snapshot을 이 병합 소스의 결과로 소급하지 않는다.

다음 동적 개발 실행은 재컴파일한 고정 소스의 원본 hexa_dynnonlinear.inp를 워밍업 없이 한 번 실행하고 전체 경과 시간을 잰다. 제한은 150초이며 완료하면 기존 전체 101-frame U 비교를 수행한다. 100초 초과 또는 timeout이면 같은 소스로 30초 제한 VTune software sampling을 한 번 수집하는 범위가 승인되어 있다. 실제 decd959 실행은 150.0362372초에서 timeout으로 종료했다. 외부 측정기와 종료시킨 target native는 각각 1이며 결과 HDF5가 없어 101-frame 비교는 미실행이다. 입력 원본/scratch 바이트와 실행 전후 source/header/binary/build/DLL identity는 같았다. 실행 자료와 실제 target 기록을 보존한다. 100초 목표 미달이며 timeout을 완료된 표본으로 처리하지 않는다.

후속 software sampling은 같은 binary로 30초 한 번만 수집했다. PowerShell이 VTune의 정상 stderr를 NativeCommandError로 처리하여 wrapper native 1로 끝났고 collector/target의 actual exit는 포착하지 못했다. 해당 값은 unknown이다. 실패 기록을 보존하고 수집을 반복하지 않았다. 기존 raw 자료만 finalize/export했으며 두 export와 그 wrapper는 native 0이다. 수집과 export 후 관련 프로세스가 모두 끝났음을 확인했다. 함수 자료, 호출 경로, export native는 부분 구간의 개발 profile이며 전체 실행 시간 자료가 아니다.

최신 sampled CPU는 LowestBitExponent 51.037592초, TwoSum 27.917520초, TwoProduct 13.335204초, Multiply 10.732785초, MultiplyPair 7.678654초다. LowestBitExponent에서 TwoProduct·Multiply·MultiplyPair를 거쳐 nonlinear EvaluateHighLow와 EvaluateSolids로 이어지는 경로가 확인된다. 여러 inline 함수가 같은 주소의 서로 다른 attribution으로 표시되어 IsFiniteBinary64의 행들을 단순 합산하지 않는다. 이전 source/profile의 sampled CPU와 이 부분 자료를 직접 성능 비율로 비교하지 않는다. 공통 최하위 bit 검색의 정확한 같은 결과를 유지하면서 비용을 줄이는 후보를 root 소유 범위의 후속 검토로 전달했다.

84개 실행과 추가 두 검사 실행은 서로 다른 검사 범위다. 이를 하나의 최종 전체 검사 실행으로 표시하지 않는다. 최종 전체 Debug/CTest, Hex8 필수 원본 5개 비교, 동적 101-frame 비교, 최종 VTune과 공식 단일 시간 측정은 아직 이 작업의 개발 검증으로 완료되지 않았다.