1. 문제의 핵심
현재 FFMA 프로브의 SASS를 확인하면 두 커널이 서로 다른 데이터 의존 구조로 생성됐다는 사실을 알 수 있다.
의존 커널에서는 모든 FFMA가 동일한 레지스터 R9를 입력과 출력으로 사용한다.
FFMA R9, R9, R0, ...
FFMA R9, R9, R0, ...
FFMA R9, R9, R0, ...
따라서 각 명령은 이전 FFMA가 만든 R9 값을 기다려야 한다.
R9₀
↓
FFMA
↓
R9₁
↓
FFMA
↓
R9₂
반면 독립 커널은 여러 accumulator를 번갈아 사용한다.
FFMA R12, R12, R7, ...
FFMA R11, R11, R7, ...
FFMA R10, R10, R7, ...
FFMA R9, R9, R7, ...
...
R12를 사용하는 FFMA가 실행된 뒤, 다음 R12 FFMA가 등장하기 전에 다른 레지스터를 사용하는 명령들이 배치된다. 따라서 하나의 결과를 기다리는 동안 다른 독립 명령을 발행할 수 있는 구조다. 실제로 업로드된 SASS에는 의존 커널의 단일 accumulator와 독립 커널의 8개 accumulator가 분명하게 나타난다.
이것으로 다음 사실은 확정할 수 있다.
컴파일러가 실험하려던 데이터 의존 구조를 실제 기계어에 보존했다.
그러나 이것만으로 다음과 같이 말할 수는 없다.
이 GPU에서 FFMA의 latency는 정확히 4 cycle이다.
그 이유는 SASS와 latency가 서로 다른 종류의 정보를 나타내기 때문이다.
2. SASS가 보여주는 것은 명령어 구조다
SASS는 NVIDIA GPU가 실행하는 저수준 기계 명령어를 사람이 읽을 수 있도록 디스어셈블한 결과다. cuobjdump와 nvdisasm은 CUDA 바이너리 안의 GPU 코드를 추출하고 분석하기 위한 도구다.
SASS에서 직접 확인할 수 있는 것은 주로 다음과 같다.
어떤 명령어가 생성됐는가
명령어가 어떤 순서로 배치됐는가
어떤 레지스터를 읽고 쓰는가
분기와 반복문이 어떻게 구성됐는가
메모리 load와 store가 존재하는가
컴파일러가 루프를 전개했는가
예를 들어 다음 명령은 R9를 읽어 계산한 결과를 다시 R9에 기록한다.
FFMA R9, R9, R0, immediate
이 명령이 연속으로 존재한다면 명령 사이에 RAW 의존성이 존재한다.
Read After Write dependency
명령 1: R9에 결과 기록
명령 2: 명령 1이 기록한 R9를 읽음
즉 SASS는 다음과 같은 논리적인 실행 관계를 보여준다.
명령 A의 결과가
명령 B의 입력으로 필요하다.
하지만 SASS 자체는 다음과 같은 실제 시간 정보를 기록한 실행 로그가 아니다.
명령 A가 정확히 몇 cycle에 발행됐는가
명령 A가 몇 cycle 뒤에 결과를 생성했는가
명령 B가 실제로 몇 cycle 대기했는가
어느 cycle에 파이프라인이 비어 있었는가
그 순간 GPU 클럭이 얼마였는가
따라서 SASS는 무엇을 실행하도록 준비했는가를 보여주지만, 실제 장치에서 얼마나 오래 걸렸는가를 직접 보여주지는 않는다.
3. 설계도와 실제 운행 시간의 차이
이를 도로에 비유할 수 있다.
SASS는 도로 지도와 같다.
A 지점
↓
B 지점
↓
C 지점
지도를 보면 A에서 B를 거쳐 C로 가야 한다는 경로는 알 수 있다.
하지만 지도만으로 실제 이동 시간을 정확히 알 수는 없다.
도로의 실제 속도 제한
교통량
신호 대기
차량 성능
공사 여부
기상 조건
이러한 실행 시점의 조건이 추가로 필요하기 때문이다.
SASS도 마찬가지다.
SASS
→ 명령어 경로와 의존 관계
실행 측정
→ 그 경로를 실제 하드웨어가 처리한 시간
따라서 SASS에서 의존 사슬을 확인하는 것은 latency 측정의 필수 조건이지만, 그 자체가 latency 측정 결과는 아니다.
4. latency는 실행 시간에 관한 성질이다
명령어 latency는 보통 다음 의미를 갖는다.
어떤 명령어의 입력이 준비된 시점부터, 그 결과를 의존하는 다음 명령어가 사용할 수 있게 될 때까지의 시간
예를 들어 FFMA 결과가 다음 FFMA에서 사용 가능해지는 데 4 cycle이 걸린다고 가정하자.
cycle 0: FFMA 1 발행
cycle 1: 결과 미준비
cycle 2: 결과 미준비
cycle 3: 결과 미준비
cycle 4: 결과 사용 가능
FFMA 2 발행 가능
의존 FFMA 사슬에서는 각 명령이 이전 결과를 기다려야 한다.
FFMA 1 ──4 cycles──> FFMA 2 ──4 cycles──> FFMA 3
이 경우 긴 사슬의 실행 시간을 측정하면 명령어 하나당 시간이 latency에 가까워질 수 있다.
추정 latency
≈ 전체 측정 cycle / 의존 FFMA 개수
하지만 여기서 중요한 표현은 가까워질 수 있다는 것이다.
실제 측정 시간에는 FFMA 자체 외에도 다른 비용이 들어가기 때문이다.
5. 현재 측정값에 포함되는 것
현재 커널의 측정 구간은 대략 다음과 같다.
clock64 읽기
↓
4096회 반복
├─ 루프 카운터 증가
├─ 종료 조건 비교
├─ FFMA 32개
└─ 분기
↓
clock64 읽기
실제 SASS에서도 시작과 종료 시점에 SR_CLOCKLO를 읽는 CS2R 명령이 있고, 반복문 안에는 IADD3, ISETP, BRA가 함께 존재한다.
따라서 측정된 전체 cycle은 개념적으로 다음과 같다.
전체 측정 cycle
=
FFMA 실행에 필요한 cycle
+
루프 카운터 비용
+
조건 비교 비용
+
분기 비용
+
타이머 읽기 비용
+
명령어 발행 및 스케줄링 영향
+
기타 파이프라인 영향
이를 식으로 표현하면 다음과 같다.
Tmeasured
=
N × Leffective
+
Tloop
+
Tbranch
+
Ttimer
+
Tother
여기서:
N : 실행된 FFMA 수
Leffective : 관측된 FFMA 간 유효 간격
Tloop : 반복문 관리 비용
Tbranch : 분기 비용
Ttimer : clock64 읽기 비용
Tother : 기타 실행 영향
따라서 단순히 다음 계산만 하면,
Tmeasured / N
정확히 순수한 하드웨어 latency만 나오는 것이 아니라 다음 값이 나온다.
FFMA latency에 가까운 값
+
FFMA 하나당 분산된 측정 오버헤드
반복 횟수를 충분히 크게 만드는 이유도 타이머와 초기화 같은 고정 비용을 많은 명령어에 나누어 희석하기 위해서다.
CUDA의 clock64()는 각 멀티프로세서의 cycle counter를 읽는 장치 함수다. 다만 두 번의 counter 값 차이는 해당 스레드가 측정 구간을 수행하는 동안 경과한 cycle을 나타내므로, 그 구간 안에서 발생한 모든 실행 영향이 함께 포함된다.
6. SASS의 명령어 간격이 latency 자체는 아니다
현재 의존 커널의 SASS를 보면 각 FFMA 뒤에 다음과 같은 두 번째 64비트 값이 출력된다.
FFMA R9, R9, R0, ...
/* 0x000fc80000000000 */
Ampere 계열 SASS의 명령어 인코딩에는 스케줄링과 의존성 제어를 위한 정보가 포함된다. 그러나 디스어셈블에 나타나는 제어 정보만 보고 실제 하드웨어의 결과 생성 latency를 그대로 확정해서는 안 된다.
그 이유는 이 정보가 다음 성격을 갖기 때문이다.
컴파일러가 선택한 정적 스케줄링 정보
의존성 관리를 위한 제어 정보
명령어 발행을 위한 힌트 또는 제약
이는 다음과 동일하지 않다.
실제 실행 시 측정된 결과 준비 시간
컴파일러는 특정 아키텍처에 대해 알고 있는 스케줄링 규칙을 이용해 명령을 배치한다. 따라서 SASS의 간격이나 제어 비트를 분석하면 컴파일러가 예상한 제약을 추론할 수는 있다.
하지만 그것만으로 다음을 모두 배제할 수는 없다.
실제 하드웨어의 추가 대기
명령 발행 자원 충돌
레지스터 파일 접근 충돌
파이프라인 점유 상태
warp scheduler의 선택
클럭 변화
전력 또는 온도 영향
즉 정적 스케줄링 정보는 강력한 단서이지만, 실제 cycle 측정을 대체하지는 않는다.
7. 명령어 latency와 명령어 발행 간격은 다르다
현재 실험은 의존 커널과 독립 커널을 비교한다.
7.1 의존 커널
FFMA R9 → FFMA R9 → FFMA R9
다음 명령이 이전 결과를 기다려야 하므로 결과 준비 latency가 직접 드러날 가능성이 크다.
cycles per FFMA
≈ dependency latency
단, 루프와 측정 오버헤드가 포함된다.
7.2 독립 커널
FFMA R12
FFMA R11
FFMA R10
FFMA R9
FFMA R8
FFMA R5
FFMA R4
FFMA R0
각 명령이 서로 다른 accumulator를 사용하므로 이전 FFMA 결과를 기다리지 않고 다음 FFMA를 발행할 수 있다.
이때 측정되는 값은 FFMA 하나의 latency라기보다 다음 성질에 가까워진다.
reciprocal throughput
또는
instruction issue interval
즉 하나의 FFMA가 완료되는 데 4 cycle이 걸리더라도, 파이프라인이 새로운 FFMA를 매 cycle 받아들일 수 있다면 다음과 같은 실행이 가능하다.
cycle 0: FFMA A 시작
cycle 1: FFMA B 시작
cycle 2: FFMA C 시작
cycle 3: FFMA D 시작
cycle 4: FFMA A 완료
cycle 5: FFMA B 완료
이 경우:
latency = 약 4 cycles
issue interval = 약 1 cycle
따라서 다음 두 값은 서로 모순되지 않는다.
Dependent cycles / FFMA ≈ 4
Independent cycles / FFMA ≈ 1
첫 번째는 결과 의존 latency의 영향을 보여주고, 두 번째는 충분한 독립 명령이 있을 때의 발행 능력을 보여준다.
Nsight Compute도 실행된 저수준 SASS 명령, 파이프라인 활동, stall 및 처리량 관련 지표를 제공한다. 다만 이러한 metric 역시 실행 시간 측정과 명령어 구조 분석을 보완하는 관측값으로 해석해야 한다.
8. SASS만으로 확정할 수 있는 것
현재 SASS 분석으로 다음 사항은 비교적 확실하게 말할 수 있다.
1. 목표 명령어가 FFMA로 생성됐다.
2. 의존 커널은 동일한 R9를 연속해서 사용한다.
3. 독립 커널은 8개의 accumulator를 사용한다.
4. 안쪽 반복문은 FFMA 32개로 전개됐다.
5. 바깥 반복문은 4096회 수행된다.
6. 총 FFMA 수는 131072개다.
7. clock64 읽기가 측정 구간 앞뒤에 존재한다.
8. 결과 store가 존재해 전체 계산이 제거되지 않았다.
즉 다음 실험 조건이 성립했다.
의존 FFMA 사슬
대
독립 FFMA 집합
이는 매우 중요한 결과다. 소스 코드만 보고 실험이 올바르다고 가정한 것이 아니라, 실제 실행 바이너리까지 확인했기 때문이다.
9. SASS만으로 확정할 수 없는 것
반면 현재 SASS만으로는 다음을 직접 확정할 수 없다.
FFMA 결과가 정확히 몇 cycle 뒤에 준비되는가
독립 FFMA를 실제로 몇 cycle마다 발행했는가
실행 중 dependency stall이 몇 cycle 발생했는가
warp scheduler가 각 명령을 어느 cycle에 선택했는가
루프 제어 명령이 실제 측정값에 얼마나 영향을 줬는가
GPU 클럭 변화가 측정값에 영향을 줬는가
관측된 대기가 FFMA 파이프라인 때문인지
다른 공통 자원 때문인지
SASS는 정적으로 존재하는 바이너리다.
실행 전에도 존재한다.
latency는 실제 하드웨어에서 명령이 처리될 때 나타나는 동적 성질이다.
실행해야 관측된다.
이 차이가 가장 중요하다.
10. 정확한 latency 추정을 위한 실험 절차
10.1 SASS 검증
먼저 현재처럼 실제 명령어를 확인한다.
목표 FFMA 존재
동일 accumulator 의존 사슬 존재
예상한 명령어 개수 확인
불필요한 load/store 확인
현재 단계는 통과했다.
10.2 실제 cycle 측정
커널을 실행해 다음 값을 얻는다.
Dependent total cycles
Dependent cycles / FFMA
Independent total cycles
Independent cycles / FFMA
이 결과가 있어야 SASS의 데이터 의존성이 실제 실행 시간 차이로 이어졌는지 확인할 수 있다.
10.3 빈 루프 대조 실험
FFMA를 제거하고 동일한 반복문 구조만 실행한다.
loop counter
조건 비교
branch
빈 루프 실행 시간을 측정하면 반복문 오버헤드를 추정할 수 있다.
보정된 FFMA 시간
≈
FFMA 커널 측정 시간
-
빈 루프 측정 시간
단, 명령어 제거로 인해 컴파일러가 루프 구조 자체를 바꿀 수 있으므로 동일한 구조가 유지됐는지 빈 루프 SASS도 확인해야 한다.
10.4 사슬 길이 변화
FFMA 개수를 여러 단계로 바꾼다.
N = 1024
N = 4096
N = 16384
N = 65536
N = 131072
측정값을 다음 모델로 본다.
T(N) = L × N + C
여기서:
L = FFMA 하나당 증가하는 cycle
C = 고정 오버헤드
여러 N에 대한 결과를 직선으로 회귀하면 단순히 한 번 나누는 방식보다 고정 오버헤드를 더 잘 분리할 수 있다.
직선의 기울기
→ 명령어당 cycle 추정값
직선의 절편
→ 고정 측정 오버헤드
10.5 accumulator 수 변화
독립 accumulator 수를 변화시킨다.
1개
2개
4개
8개
16개
예상되는 형태는 다음과 같다.
1개 → dependency latency 노출
2개 → 일부 latency 은폐
4개 → 처리량 증가
8개 → 처리량 포화 가능
16개 → 더 이상 개선되지 않을 가능성
이 실험을 통해 FFMA latency와 issue throughput을 분리해 볼 수 있다.
10.6 반복 측정
한 번의 결과가 아니라 여러 번 측정한다.
warm-up
반복 실행
최솟값
중앙값
평균
표준편차
최솟값은 외부 방해가 가장 적었던 실행을 나타낼 수 있고, 중앙값은 일부 이상치에 덜 민감하다.
10.7 프로파일러 교차 검증
Nsight Compute로 다음 종류의 값을 함께 확인한다.
실행된 FFMA 수
명령어 발행 상태
dependency 관련 stall
FP32 pipeline 사용률
warp scheduler 상태
Nsight Compute는 커널별 상세 성능 metric과 SASS 수준 분석 기능을 제공하므로 시간 측정 결과를 다른 관측값으로 교차 검증하는 데 사용할 수 있다.
11. 현재 실험에서 사용할 수 있는 정확한 표현
현재 SASS 분석만 완료된 단계에서는 다음처럼 표현하는 것이 적절하다.
의존 커널에서는 동일한 accumulator를 연속해서 사용하는 FFMA 데이터 의존 사슬이 생성됐으며, 독립 커널에서는 8개의 accumulator를 교대로 사용하는 FFMA 명령열이 생성됐다. 따라서 latency 노출 실험과 latency 은폐 실험을 비교하기 위한 기계어 구조는 의도대로 구성됐다.
아직 실행 결과가 없다면 다음 표현은 피해야 한다.
FFMA latency는 4 cycle로 확인됐다.
실행 결과가 나온 뒤에도 처음에는 다음처럼 표현하는 것이 안전하다.
의존 FFMA 사슬에서 명령어당 약 4 cycle이 관측됐다. 이 값은 FFMA 의존 latency와 일치하는 행동으로 해석할 수 있지만, 현재 측정에는 루프와 타이머 오버헤드가 일부 포함돼 있다.
빈 루프 보정, 사슬 길이 변화, 반복 측정까지 수행한 뒤에는 더 강하게 표현할 수 있다.
반복문 오버헤드를 보정하고 여러 사슬 길이에서 기울기를 추정한 결과, 해당 장치에서 FFMA 의존 사슬의 관측 latency는 약 4 cycle로 나타났다.
여기서도 물리적인 FFMA 회로의 절대 latency보다 다음 표현이 더 정확하다.
해당 GPU와 해당 실행 조건에서 관측된
FFMA 의존 사슬 latency
12. 실험 결과의 신뢰도 단계
하드웨어 프로빙 결과는 한 번에 확정되는 것이 아니라 증거가 누적되면서 강해진다.
단계 1: 소스 코드
의존 FFMA를 작성했다.
아직 컴파일러가 어떻게 변환했는지 모른다.
단계 2: PTX 확인
PTX에 fma 명령이 존재한다.
그러나 실제 GPU 기계어가 어떻게 생성됐는지는 아직 완전히 확인되지 않았다.
단계 3: SASS 확인
실제 FFMA가 생성됐다.
의존 레지스터 구조도 유지됐다.
현재 도달한 단계다.
단계 4: 실행 cycle 측정
의존 구조와 독립 구조 사이에
실제 cycle 차이가 관측됐다.
이때부터 latency에 관한 실험적 근거가 생긴다.
단계 5: 오버헤드 보정
빈 루프
타이머 비용
명령어 수 변화
이를 통해 순수한 명령어 효과에 더 가까워진다.
단계 6: 교차 검증
accumulator 수 변화
warp 수 변화
Nsight Compute metric
다른 GPU와 비교
여러 독립적인 실험이 같은 결과를 가리키면 신뢰도가 높아진다.
13. 핵심 정리
SASS가 답하는 질문은 다음과 같다.
실제로 어떤 명령어가 생성됐는가?
그 명령어 사이에 어떤 레지스터 의존성이 존재하는가?
컴파일러가 실험 구조를 유지했는가?
실행 측정이 답하는 질문은 다음과 같다.
그 명령어가 실제 하드웨어에서 몇 cycle 걸렸는가?
의존성이 실제로 얼마나 큰 대기를 만들었는가?
독립 명령을 배치했을 때 처리량이 얼마나 증가했는가?
따라서 두 분석은 다음 관계를 가진다.
SASS 검증
→ 실험 장치가 올바르게 만들어졌는지 확인
실행 측정
→ 그 실험 장치로 실제 하드웨어 행동을 관측
SASS 없이 실행 시간만 측정하면 어떤 명령어를 측정한 것인지 확신하기 어렵다.
반대로 실행 시간 없이 SASS만 보면 명령어 구조는 알 수 있지만 실제 latency를 알 수 없다.
결국 정확한 하드웨어 프로빙에는 둘 다 필요하다.
소스 코드
↓
PTX
↓
SASS 구조 검증
↓
실제 GPU 실행
↓
cycle 측정
↓
오버헤드 보정
↓
프로파일러 교차 검증
↓
관측 latency 추정
현재 실험에서 확정된 것은 다음이다.
FFMA latency를 노출하기 위한 의존 명령어 사슬과, latency를 숨기기 위한 독립 명령어 집합이 실제 SASS에 의도대로 생성됐다.
다음 단계는 실제 출력값을 수집하고 다음 관계를 확인하는 것이다.
Dependent cycles / FFMA
>
Independent cycles / FFMA
이 차이가 반복 측정에서도 유지되고, 오버헤드를 보정한 뒤에도 일관되게 나타날 때 비로소 FFMA latency와 throughput에 관한 실험적 결론을 세울 수 있다.
'SASS_Probe' 카테고리의 다른 글
| 소스 코드에서 하드웨어 실행까지 이어지는 추적 가능한 분석 모델의 구축 (0) | 2026.07.17 |
|---|---|
| SASS 기반 GPU 하드웨어 프로빙 방법론 (0) | 2026.07.09 |
| 공개되지 않은 하드웨어 특성을 실행으로 추론하는 방법 (0) | 2026.07.09 |
| SASSScope exp002 실험 과정 정리 (0) | 2026.07.07 |
| SASSScope Experiment 002 - 4→2 Linear의 Bias / ReLU 분리 관찰 (0) | 2026.07.07 |