421 lines
33 KiB
Markdown
421 lines
33 KiB
Markdown
# 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`에서 수행했다.
|
||
이전 검사 결과를 새 소스의 통과로 대입하지 않는다.
|
||
후속 `3576f3f`는 root가 공통 최하위 bit 검색을 MSVC x64 intrinsic으로 바꾼
|
||
소스다. 같은 수치 header hash의 root Debug 검사와 T3 Release 실행을 아래에서
|
||
구별한다. T3가 공통 산술을 직접 수정하지 않았다.
|
||
공식 기준 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에서 거부한다.
|
||
[최종 독립 수치 검토](../../.harness/performance/t3/source-numerical-review-71e0816.md)는
|
||
이 증명과 아래 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 값을 가져오지 않는다.
|
||
[이 변경의 독립 검토](../../.harness/performance/t3/source-numerical-review-6d709fd.md)는
|
||
같은 입력·연산으로 생성한 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에는 없다.
|
||
[소유 경로별 집계](../../.harness/performance/t3/vtune-owner-attribution.json)는
|
||
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 결과와 구별한다.
|
||
[수명과 동기화의 독립 검토](../../.harness/performance/t3/source-numerical-review-6bc5cd3.md)는
|
||
`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](../../.harness/performance/t3/before-native.json), [log](../../.harness/performance/t3/before-checks.txt) |
|
||
| Production `71e0816` | Debug build 0, Hex8·static·frequency·paired state/kinematics 84/84 PASS, native 0 | [Native](../../.harness/performance/t3/after-native.json), [log](../../.harness/performance/t3/after-checks.txt) |
|
||
| `43c747f` tests-only delta | Build 0, overflow 진단 우선순위 2/2 PASS, native 0 | [Native](../../.harness/performance/t3/priority-native.json), [log](../../.harness/performance/t3/priority-checks.txt) |
|
||
| `6d709fd` trial-local 반복 연산 제거 | Debug build 0, Hex8 48/48 PASS, native 0 | [Native](../../.harness/performance/t3/cache-native.json), [log](../../.harness/performance/t3/cache-checks.txt) |
|
||
| 동일 TU의 원본/현재 Debug 진단 대조 | 60 finite-input 조합, 출력 306행 동일, 각각 native 0 | [Native](../../.harness/performance/t3/diagnostic-native.json), [comparison](../../.harness/performance/t3/diagnostic-comparison.json), [original manifest](../../.harness/performance/t3/original-debug/manifest.json) |
|
||
| `a08df0f` 선택적 준비 수명 | Fresh Debug configure/build 0, Hex8·paired state/kinematics·serial/TBB 59/59 PASS, native 0 | [Native](../../.harness/performance/t3/lazy-native.json), [검사](../../.harness/performance/t3/lazy-checks.txt), [dependencies](../../.harness/performance/t3/lazy-dependencies.txt) |
|
||
| 같은 TU의 원본/current pair snapshot | Flat/warped, linear/nonlinear 전체 response의 raw bits 9,804행 동일, 양쪽 compile/run native 0 | [Native](../../.harness/performance/t3/pair-snapshot-native.json), [대조](../../.harness/performance/t3/pair-snapshot-comparison.json) |
|
||
| `decd959` 공통 finite classifier 통합 | Correct-prefix Debug configure/build/deps 0, HighLowArithmetic·Hex8·paired·serial/TBB 68/68 PASS, native 0 | [Native](../../.harness/performance/t3/postmerge-debug-native.json), [검사](../../.harness/performance/t3/postmerge-debug-checks.txt) |
|
||
|
||
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 비교를 통과했다.
|
||
[최초 실행](../../.harness/performance/t3/development-static.json),
|
||
[후속 실행](../../.harness/performance/t3/development-static-cache.json),
|
||
[후속 비교](../../.harness/performance/t3/development-static-cache/run-1/comparison.json),
|
||
[선택적 준비 지연 실행](../../.harness/performance/t3/development-static-lazy.json),
|
||
[해당 비교](../../.harness/performance/t3/development-static-lazy/run-1/comparison.json)를
|
||
모두 보존한다. 서로 다른 개발 소스의 값이며 빠른 값을 골라 공식 표본으로 쓰지
|
||
않는다. 마지막 개발 값은 2초 이내지만 최종 통합 소스의 공식 목표 합격은 아직 아니다.
|
||
|
||
최초 개발 Release binary의 [VTune 함수 자료](../../.harness/performance/t3/vtune-functions.csv)와
|
||
[호출 경로](../../.harness/performance/t3/vtune-callstacks.csv),
|
||
[실제 명령과 native 기록](../../.harness/performance/t3/vtune-native.json)을 보존한다.
|
||
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 작업이 겹쳤다. [겹침 기록](../../.harness/performance/t3/diagnostic-overlap.json)을
|
||
보존하며 해당 elapsed는 성능 evidence에서 제외한다. 이미 완료된 동일 진단을
|
||
반복하지 않았다. Finite 조합의 동일 결과를 모든 극단 입력의 증명으로 확대하지 않는다.
|
||
|
||
기존 Debug/Release Ninja의 MSVC include prefix가 깨졌고 조사한 Hex8 object의
|
||
header dependency 수가 0이었다. [실제 조사](../../.harness/performance/t3/dependency-audit.txt)를
|
||
보존한다. 산술 변경의 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 기록](../../.harness/performance/t3/lazy-release-native.json)은
|
||
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 재빌드](../../.harness/performance/t3/postmerge-release-native.json)의
|
||
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는
|
||
같았다. [실행 자료](../../.harness/performance/t3/development-dynamic-lazy.json)와
|
||
[실제 target 기록](../../.harness/performance/t3/development-dynamic-lazy/run-1/native.json)을
|
||
보존한다. 100초 목표 미달이며 timeout을 완료된 표본으로 처리하지 않는다.
|
||
|
||
후속 software sampling은 같은 binary로 30초 한 번만 수집했다. PowerShell이
|
||
VTune의 정상 stderr를 `NativeCommandError`로 처리하여 wrapper native 1로
|
||
끝났고 collector/target의 actual exit는 포착하지 못했다. 해당 값은 unknown이다.
|
||
[실패 기록](../../.harness/performance/t3/vtune-dynamic-lazy-wrapper-failure.json)을
|
||
보존하고 수집을 반복하지 않았다. 기존 raw 자료만 finalize/export했으며 두 export와
|
||
그 wrapper는 native 0이다. 수집과 export 후 관련 프로세스가 모두 끝났음을 확인했다.
|
||
[함수 자료](../../.harness/performance/t3/vtune-dynamic-lazy-functions.csv),
|
||
[호출 경로](../../.harness/performance/t3/vtune-dynamic-lazy-callstacks.csv),
|
||
[export native](../../.harness/performance/t3/vtune-dynamic-lazy-export-native.json)는
|
||
부분 구간의 개발 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 소유 범위의 후속 검토로 전달했다.
|
||
|
||
## 공통 bit-scan 통합 뒤의 개발 실행
|
||
|
||
Root는 같은 비영 significand의 최하위 bit 위치를 `_BitScanForward64`로 찾도록
|
||
공통 private helper를 바꿨다. Exponent 구성과 exact dyadic-tail 거부 기준은
|
||
유지했다. [독립 source 검토](../../.harness/performance/shared-bitscan/source-numerical-review.md)는
|
||
header SHA `F231B9C1B0FBF963EBE1AA88D7FE4C7A291CE91C5CE4E28280AEDEB3155B7A71`의
|
||
수치·계약 범위 PASS이며 실행 검증과 구별한다. 같은 working candidate hash에서
|
||
root가 Debug 소비자 36개 edge를 재빌드하고 합성 68개 검사를 통과한
|
||
[native 기록](../../.harness/performance/shared-bitscan/after-native.json)을 보존한다.
|
||
그 뒤 root가 `3576f3f`로 commit했으며 T3는 동일 Debug 검사를 반복하지 않았다.
|
||
|
||
T3는 `3576f3f`를 동기화하고 기존 정상 dependency Release tree의 소비자 8개
|
||
edge를 재컴파일했다. Configure/build/deps 모두 native 0이며 Hex8 dependencies
|
||
15개를 확인했다. [Release 기록](../../.harness/performance/t3/bitscan-release-native.json)에
|
||
실제 argv와 소스를 남겼다. 새 binary SHA는
|
||
`54fa853d3f16ef63b0b056d1cdd18bb6b28e6e723ade3caa4b0b6b01b9d1d97e`다.
|
||
|
||
이 binary의 원본 동적 입력 개발 실행은 워밍업 없이 한 번만 수행했으며
|
||
150.1015395초 timeout이었다. Target와 측정 wrapper native는 각각 1,
|
||
execution_valid는 false이며 최종 HDF5가 없어 101-frame U 비교는 미실행이다.
|
||
[실행 자료](../../.harness/performance/t3/development-dynamic-bitscan.json),
|
||
[target 기록](../../.harness/performance/t3/development-dynamic-bitscan/run-1/native.json),
|
||
[wrapper native](../../.harness/performance/t3/dynamic-bitscan-native.json)를 보존한다.
|
||
원본/scratch 바이트와 source/header/binary/build/runtime DLL/thread/power identity가
|
||
전후 같았다. AC 연결 상태 1과 전원 scheme GUID
|
||
`8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c`를 기록했다. 종료 뒤 관련 프로세스가
|
||
없음을 확인하고 CPU 권한을 반환했다. 이번 실행 뒤 새 profile은 수집하지 않았다.
|
||
|
||
이전과 이번 실행은 모두 제한 시간에 중단되었으므로 두 elapsed로 전체 실행의
|
||
개선 비율을 계산하지 않는다. Bit-scan의 source/Debug 검증 PASS를 동적 100초
|
||
목표의 합격으로 확대하지 않는다.
|
||
|
||
## Bit-scan 소스의 남은 병목
|
||
|
||
같은 binary로 별도 승인된 software sampling 30초를 한 번 수집했다. 새 wrapper는
|
||
ProcessStartInfo의 stdout/stderr를 비동기로 분리하고 collector의 actual native를
|
||
즉시 기록했다. Collector native는 4, wrapper는 1이며 이 값을 성공으로 바꾸지
|
||
않는다. Raw result는 finalize 100%를 완료했고 기존 자료의 함수·전체 callstack·
|
||
summary export는 각각 native 0, 별도 export wrapper도 0이었다. Target native는
|
||
독립 포착하지 못해 unknown이다. 관측한 owned descendant PID 5개의 시작 ticks를
|
||
보존했으며 강제 종료 없이 모두 닫혔다. 관련 프로세스도 0개였다.
|
||
[실제 명령과 종료](../../.harness/performance/t3/vtune-dynamic-bitscan-native.json)를 보존한다.
|
||
|
||
[Summary](../../.harness/performance/t3/vtune-dynamic-bitscan-summary.csv)의 구간 elapsed는
|
||
29.859555초, CPU 227.129758초, effective 185.250598초, spin 36.140758초,
|
||
overhead 5.738402초다. 수집·finalization을 포함한 collector 경과 41.2746919초와
|
||
구별하며 어느 값도 전체 시간 목표 판정으로 사용하지 않는다.
|
||
[함수](../../.harness/performance/t3/vtune-dynamic-bitscan-functions.csv)와
|
||
[전체 호출 경로](../../.harness/performance/t3/vtune-dynamic-bitscan-callstacks.csv)는
|
||
TwoSum·Add·Multiply·MultiplyPair를 거쳐 nonlinear EvaluateHighLow로 이어지는
|
||
병목이 남음을 보여준다.
|
||
|
||
| 함수 | 보고된 self CPU초 | 제한된 core 경로의 inclusive CPU초 |
|
||
| --- | ---: | ---: |
|
||
| LowestBitExponent | 11.061455 | 11.061455 |
|
||
| TwoSum | 33.144893 | 33.144893 |
|
||
| Add | 6.402455 | 33.202178 |
|
||
| Multiply | 13.868298 | 51.911387 |
|
||
| MultiplyPair | 9.711280 | 71.850858 |
|
||
| AddPair | 4.231358 | 16.787786 |
|
||
|
||
Self는 같은 함수 이름의 export 행들을 합한 값이다. Inclusive 열은 각 blank로
|
||
구분한 stack의 첫 양수 weight 중 다른 arithmetic helper leaf만 더한 제한된
|
||
집계다. 같은 주소로 표시되는 inline finite/normalized/constructor attribution은
|
||
합산에서 제외했다. 완전한 inclusive 비용이 아니며 중첩 그룹을 서로 합산하지
|
||
않는다. [집계 근거](../../.harness/performance/t3/vtune-dynamic-bitscan-path-summary.json)에
|
||
방법과 leaf별 자료를 남겼다.
|
||
|
||
LBE/TwoSum의 독립 주소와 호출 경로는 out-of-line 경계 후보를 뒷받침하지만 실제
|
||
disassembly는 실행하지 않아 call/spill 수를 확정하지 않았다. HighLow는 16-byte
|
||
사용자 정의 pair이며 out-of-line 기본 MSVC x64 ABI에서는 간접 인자·반환 저장소가
|
||
필요하다. [Microsoft ABI 문서](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170)가
|
||
이 구조체의 호출 경계 근거다. Root가 검토할 좁은 MSVC x64 force-inline 후보는
|
||
식·guard·flags를 유지하며 실제 codegen과 개발 실행으로 효과를 확인해야 한다.
|
||
|
||
AddPair 검증 뒤의 Add와 양 low 비zero MultiplyPair 뒤의 Multiply는 normalized
|
||
입력 guard를 반복한다. 이는 source로 확인한 중복이며 inline finite attribution을
|
||
별도 비용으로 더해 절감량을 추정하지 않는다. Guard 제거보다 좁은 inline 후보를
|
||
먼저 검토하도록 전달했으며 이 단계에서 production을 수정하거나 추가 실행하지 않았다.
|
||
|
||
[Identity 자료](../../.harness/performance/t3/vtune-dynamic-bitscan-metadata.json)의 최종
|
||
before/after는 export 경계를 기록한다. 수집 전 준비 metadata는 export wrapper가
|
||
덮어썼으므로 독립 보존된 전체 수집 전후 대조로 주장하지 않는다. 최종 binary와
|
||
header/input hash는 고정된 이전 동적 실행과 같으며 이 한계를 함께 보존한다.
|
||
|
||
## 좁은 inline 선언 후보 뒤의 개발 실행
|
||
|
||
Root의 `8021dee`는 MSVC 호환 x64에서 TwoSum과 LowestBitExponent의 선언만
|
||
force-inline으로 바꾼 후보다. T3는 이를 `cb25d744`로 병합했다. 고정 arithmetic
|
||
header SHA는 `4F360FD4D11FCA68863E9FA7C084ED80E70FC4D903B9DF170AC946D19472987C`다.
|
||
Root의 [source-only 독립 검토](../../.harness/performance/shared-inline/source-numerical-review.md)와
|
||
fresh Release 205개 edge 및 같은 68개 consumer
|
||
[검사 native 0 자료](../../.harness/performance/shared-inline/after-native.json)를 보존한다.
|
||
T3는 같은 Debug 검사를 반복하지 않았다.
|
||
|
||
같은 flags·runtime·thread·power 설정으로 T3 Release 소비자 8개 edge를 재빌드했고
|
||
configure/build/deps native 0 및 Hex8 dependencies 15개를 확인했다.
|
||
[재빌드 native](../../.harness/performance/t3/inline-release-native.json)를 보존한다.
|
||
새 binary SHA는 `1532666241ab623854cdc08648fc5485371881aed9b09e1896068422185032ad`다.
|
||
|
||
원본 동적 입력을 워밍업 없이 한 번 실행한 결과는 150.0319488초 timeout이다.
|
||
Target와 측정 wrapper native는 1, execution_valid는 false이며 최종 HDF5가 없어
|
||
101-frame U 비교는 미실행이다. [실행](../../.harness/performance/t3/development-dynamic-inline.json)과
|
||
[wrapper native](../../.harness/performance/t3/dynamic-inline-native.json)를 보존한다.
|
||
이번에는 타이머 밖의 [before identity](../../.harness/performance/t3/development-dynamic-inline-before.json)와
|
||
[after identity](../../.harness/performance/t3/development-dynamic-inline-after.json)를
|
||
각각 별도 파일에 저장했다. Source/input/header/exe/DLL/build/runtime/thread/power
|
||
identity가 전후 같았고 종료 후 관련 프로세스가 없음을 확인해 CPU 권한을 반환했다.
|
||
|
||
새 profile이나 disassembly는 실행하지 않았다. Source의 annotation을 실제 모든
|
||
호출이 inline되었다는 증거로 확대하지 않는다. 이 후보도 100초 목표 미달이며,
|
||
제한 시간에 중단된 이전 후보들과의 전체 시간 개선 비율을 계산하지 않는다.
|
||
|
||
## Inline 후보의 실제 codegen과 후속 profile
|
||
|
||
별도 승인으로 같은 binary의 software sampling 30초를 한 번 수집했다. Collector
|
||
actual native 4와 outer wrapper 1을 유지한다. 기존 raw 자료만 함수·전체 callstack·
|
||
summary로 export했고 세 report와 export wrapper는 모두 native 0이다. 이번에는
|
||
collection과 export 각각의 metadata/native/before/after 파일을 분리했다.
|
||
[Collection native](../../.harness/performance/t3/vtune-dynamic-inline-collection-native.json),
|
||
[export native](../../.harness/performance/t3/vtune-dynamic-inline-export-native.json),
|
||
[collection metadata](../../.harness/performance/t3/vtune-dynamic-inline-collection-metadata.json)를
|
||
보존한다. Target native는 unknown이며 관련 owned PID는 모두 종료했다.
|
||
|
||
Source/input/header/exe/build/DLL/thread/power는 전후 같았다. 환경을 수집한 uv의
|
||
임시 Python Scripts PATH 첫 entry만 달랐으며 나머지 entry는 같았다. 실제 profiler가
|
||
상속한 parent PATH를 독립 필드로 저장하지 않았으므로 전체 runtime PATH equality는
|
||
false라는 한계를 유지한다. [Identity 검사](../../.harness/performance/t3/vtune-dynamic-inline-collection-identity-checks.json)는
|
||
이 차이를 포함하며 개발 profile을 공식 환경 합격으로 표시하지 않는다.
|
||
|
||
[Summary](../../.harness/performance/t3/vtune-dynamic-inline-summary.csv)는 elapsed
|
||
29.871824초, CPU 222.433211초, effective 173.657543초, spin 43.736681초,
|
||
overhead 5.038986초다. [함수 자료](../../.harness/performance/t3/vtune-dynamic-inline-functions.csv)의
|
||
Multiply 12.163382초, TwoProduct 11.910763초, MultiplyPair 9.367977초가 남는다.
|
||
TwoSum은 여러 inline 위치로 보고되어 다른 finite attribution의 같은 주소와
|
||
별도 비용으로 합산하지 않는다.
|
||
|
||
Hex8 paired TU 하나만 read-only dumpbin symbols/disasm으로 확인했으며 두 명령과
|
||
wrapper native는 0이다. [실제 codegen 명령](../../.harness/performance/t3/inline-codegen-native.json)과
|
||
[disassembly](../../.harness/performance/t3/inline-codegen-disasm.txt)를 보존한다.
|
||
이 TU의 direct call TwoSum/LowestBitExponent는 0개이며 TwoProduct 내부에 BSF와
|
||
TwoSum 식이 펼쳐진 명령을 확인했다. 독립 COMDAT symbol은 남아 있으므로 전체
|
||
binary의 모든 호출이 inline되었다고 주장하지 않는다. 이전 TU의 동일한 해시 object를
|
||
별도로 보존하지 않아 정확한 function-byte 크기 변화는 비교하지 않았다.
|
||
|
||
TwoProduct에는 실제 `call fma`가 남는다. Profile의 UCRT fma self는 0.975742초,
|
||
import thunk는 0.044582초이며 fma를 ancestor로 가진 다른 leaf 경로는 없었다.
|
||
단독 hardware residual dispatch는 좁지만 현재 주 병목에 대한 영향 근거가 작아
|
||
우선 후보로 선택하지 않았다. Scalar graph나 guard를 제거하는 대안으로 쓰지 않는다.
|
||
|
||
libiomp worker self 37.973383초 중 spin은 32.949078초다. Callstack은
|
||
OpenMP worker→BaseThreadInitThunk→RtlUserThreadStart만 보인다.
|
||
[FMA·spin 경로 자료](../../.harness/performance/t3/vtune-dynamic-inline-fma-spin-paths.json)는
|
||
이를 보존한다. Global PARDISO 뒤 dormant worker인지, paired TBB와 실제 시간상
|
||
겹친 resource 비용인지는 이 stack만으로 확정하지 못한다. Model을 작은 equation
|
||
system으로 가정하거나 전역 PARDISO threshold/thread 정책을 바꾸지 않았다.
|
||
|
||
`geo*point.weight`의 동일 결과를 diagonal 세 곳에서 재사용하는 작은 후보는 원래
|
||
식·누적 순서를 유지할 수 있는 별도 검토 사항으로만 남겼고 구현하지 않았다.
|
||
후속 4-column 특수 pair packet도 아직 구현·검증 전이며 이 profile의 통과 결과로
|
||
표시하지 않는다.
|
||
|
||
84개 실행과 추가 두 검사 실행은 서로 다른 검사 범위다. 이를 하나의 최종 전체
|
||
검사 실행으로 표시하지 않는다. 최종 전체 Debug/CTest, Hex8 필수 원본 5개 비교,
|
||
동적 101-frame 비교, 최종 VTune과 공식 단일 시간 측정은 아직 이 작업의 개발
|
||
검증으로 완료되지 않았다.
|