메모리 성능
메모리 성능은 커널 처리량을 제한하는 경우가 많습니다. 연산 매핑을 변경하기 전에 먼저 고정된 스케줄끼리 비교하십시오. Fetch Engine, Commit Engine, DMA Engine은 각각 성능 결과에 직접 연결되는 API 선택지(Packet 크기, 접근 순서 등)를 제공합니다. 이 절에서는 이러한 선택의 바탕이 되는 하드웨어 제약 조건과 이 제약 조건이 측정 처리량에 미치는 영향을 설명합니다.
메모리 유형별 Chip당 최대 대역폭은 다음과 같습니다:
| 메모리 | 최대 대역폭 |
|---|---|
| DM | Chip당 2 TB/s |
| HBM | Chip당 1.5 TB/s |
이 최대치에 도달하려면 특정한 접근 패턴이 필요합니다. 다음 표는 위반하면 처리량이 저하되는 규칙을 정리한 것이며, 아래 절에서 각 메모리 유형과 요인을 자세히 설명합니다:
| 메모리 | 문제 | 규칙 | 불이익 |
|---|---|---|---|
| DM | 뱅크 기아 | 동일 뱅크 연속 접근 < 64회 | NoC 타임아웃 → 하드웨어 리셋 |
| DM | DMN 인터리빙 | Cluster당 2개의 DMN을 번갈아 사용 | 대역폭 50% 손실 |
| DM | Slice 인터리빙 | DMN당 32개의 Slice에 분산 | 명령 큐 경합 |
| HBM | 정렬 | 256바이트 정렬 접근 | 비정렬 읽기: 2배 페널티. 비정렬 쓰기: 약 50배 페널티(RMW) |
| HBM | 뱅크 충돌 | 같은 뱅크 안에서 행 전환을 피하십시오 | 30–40배 성능 저하 |
| HBM | Channel 인터리빙 | 32개 채널에 분산 | 병렬성 감소 |
먼저 표를 보고 정렬, 인터리빙, 패킷 크기를 정한 다음, 상세 섹션을 참고하여 뱅크 기아(starvation)나 HBM 충돌을 진단하십시오. 규칙 표는 후보 매핑에서 병목이 되는 자원을 알려 주며, DM, SPM, HBM 섹션에서 그 원인을 설명합니다.
Data Memory (DM)
Data Memory(DM)는 Chip당 256MB 용량이며, Cluster, Data Memory Network(DMN), Slice, 뱅크로 계층적으로 구성됩니다. 다음 표는 이 구조를 요약한 것입니다:
| 단위 | 개수 |
|---|---|
| Cluster | 2 / Chip |
| Data Memory Network(DMN) | 8 / Cluster |
| Slice | 32 / DMN |
| 뱅크 | 16 / Slice |
| 행 | 4096 / 뱅크 |
| 바이트 | 8 / 행 |
Cluster는 Switch Engine을 통해 데이터를 교환할 수 있습니다. 자세한 내용은 해당 섹션을 참조하십시오. 아래 하위 섹션에서는 이 구조가 대역폭과 뱅크 접근 제약 조건을 어떻게 결정하는지 설명합니다.
Slice 내 뱅크 구조
각 Slice는 전용 주소 공간을 갖춘 512KB의 SRAM을 제공합니다. 메모리는 각각 8바이트 데이터 폭을 갖는 16개의 병렬 뱅크로 구성되어 있으며, 이를 통해 총 128 B/사이클의 데이터 접근 속도를 제공합니다. 개별 뱅크에 대한 접근은 직렬화되지만, 주소 공간은 연속된 128바이트를 16개 뱅크 전체에 분산하여(뱅크당 8바이트) 병렬 접근을 가능하게 합니다. 다음 비트 매핑이 이 분산 방식을 정의합니다:
| 비트 번호 | 구성 요소 |
|---|---|
0–2 | 바이트 |
3–6 | 뱅크 |
7–18 | Row |
연속된 주소는 서로 다른 뱅크에 매핑되므로 순차 스캔 중에 병렬 접근이 가능합니다.
DMN과 Slice 인터리빙
각 DMN은 128 B/사이클의 대역폭만 제공합니다(32개의 Slice가 데이터 경로를 공유하기 때문입니다). 표준 전송 단위인 256바이트는 DMN당 두 사이클이 필요하므로, 연속적인 처리량을 유지하려면 두 DMN에 걸쳐 접근을 파이프라인으로 처리하십시오:
| 사이클 | DMN #0 | DMN #1 |
|---|---|---|
| 0 | 읽기 #0 (1/2) | (유휴) |
| 1 | 읽기 #0 (2/2) | 읽기 #1 (1/2) |
| 2 | 읽기 #2 (1/2) | 읽기 #1 (2/2) |
| 3 | 읽기 #2 (2/2) | 읽기 #3 (1/2) |
| … | … | … |
| 2n-1 | 읽기 #2n-2 (2/2) | 읽기 #2n-1 (1/2) |
| 2n | (유휴) | 읽기 #2n-1 (2/2) |
Note
명령 큐가 이론적으로는 인터리빙 없이도 어느 정도의 버스트 접근을 허용하지만, DMA 스트림을 생성할 때는 항상 DMN 간에 인터리빙하십시오. 이것이 가장 자연스러운 방법입니다.
Slice는 DMA, Fetch, Commit Engine이 공유하므로, 각 DMN 내의 32개 Slice에 요청을 분산하면 경합이 줄어듭니다. Data Memory Router는 각 DMN 내에서 이 Slice들을 링 토폴로지로 연결합니다: slice0_in → slice31_out, slice32_in → slice63_out. 각 Data Memory Slice에는 대기 중인 DMA 요청을 위한 2-엔트리 명령 큐가 있습니다. 우선순위 때문에 개별 Slice가 지연되더라도, 요청을 M개의 Slice에 분산하면 Slice당 필요한 처리량이 1/M로 줄어듭니다. n 사이클마다 DMN 인터리빙을 하면 포화 처리량인 256 B/cycle을 달성합니다.
뱅크 기아
뱅크 기아는 DMA Engine이 더 높은 우선순위의 엔진이 점유한 DM 뱅크를 기다리며 무기한 차단될 때 발생합니다. 64회 접근 규칙이 이를 방지합니다. 이 규칙을 위반하면 Network-on-Chip(NoC) 타임아웃과 전체 Cluster 리셋이 발생하여 모든 연산 상태를 잃게 됩니다.
각 DM 뱅크는 공유 자원입니다. 우선순위가 높은 엔진이 뱅크에 계속 접근하면 우선순위가 낮은 요청자는 무기한 차단되며, 이는 일종의 우선순위 역전입니다. DM 컨트롤러는 다음 순서로 요청의 우선순위를 정합니다:
- 메인 컨텍스트 Fetch Engine
- 메인 컨텍스트 Commit Engine
- 서브 컨텍스트 Fetch Engine
- 서브 컨텍스트 Commit Engine
- DMA Engine
정상 동작 중에는 연산 엔진이 데이터에 먼저 접근해야 하므로, DMA는 모든 메모리 엔진 중에서 우선순위가 가장 낮습니다. 우선순위가 높은 엔진은 같은 뱅크를 계속해서 사용할 수 있습니다. 이때 대기열에 있는 DMA 요청은 해당 엔진들이 뱅크를 점유하는 동안 기다려야 합니다. Tensor DMA는 NoC 허브를 통해 DRAM 및 DMN과 통신하며, 이 허브에서 각 포트(DMA, DRAM, DMN)는 4,096 사이클 이내에 요청에 응답해야 합니다. 응답 없이 4,096 사이클이 지나면 NoC 프로토콜은 해당 트랜잭션을 죽은 것으로 판정하고 예외 상태에 진입합니다. 이는 교착 상태와 무기한 멈춘 트랜잭션을 감지하기 위한 안전 장치입니다. 타임아웃이 발생하면 하드웨어에는 정상적으로 복구할 수 있는 메커니즘이 없습니다. 유일한 복구 방법은 Cluster 도메인 전체를 리셋하는 것이며, 이 경우 모든 연산 상태가 사라지고 완전한 재초기화가 필요합니다.
한도는 연속 접근 64회입니다. DMA가 활성화된 동안 Fetch와 Commit은 같은 뱅크를 64회 이상의 연산 동안 점유해서는 안 됩니다. 왜 64회입니까? 제약 조건은 (TDMA_IO_BYTE / DMN_IO_BYTE) * Max_Consecutive_Access * DMN_SIZE < 4096이며(TDMA_IO_BYTE = 256, DMN_IO_BYTE = 128, DMN_SIZE = 32), 이로부터 Max_Consecutive_Access < 64가 도출됩니다. 이 제약 조건은 최악의 경우에도 DMA 요청이 NoC 타임아웃 전에 완료되도록 보장합니다.
예를 들어, DMA Engine이 (다른 15개 뱅크와 함께) 뱅크 0에 요청을 보냈는데, 메인 컨텍스트의 Fetch Engine이 뱅크 0에 계속해서 요청을 보낸다고 가정해 봅시다. DMA 요청은 지연되고, 이 지연이 4,096 사이클을 넘으면 NoC 타임아웃으로 인해 하드웨어 리셋이 강제로 발생합니다.
컨텍스트 점유, 64회 접근 규칙, 메인/서브 뱅크 경합에 대해서는 스케줄링: 리소스와 뱅크 경합을 참조하십시오. 어떤 연산이 병렬로 실행되는지 보여 주고 실제 컨텍스트 할당을 검증하는 스케줄링 시각화 유틸리티에 대해서는 Schedule Viewer를 참조하십시오.
고대역폭 메모리(HBM)
HBM은 Chip당 48GB를 저장하고 총 1.5 TB/s의 대역폭을 제공하지만, 이 최대치에 도달하려면 256바이트 정렬 접근과 32개 Channel 전체에 걸친 Channel 인터리빙이 필요합니다. 정렬되지 않은 쓰기와 뱅크 충돌은 처리량을 30–50배까지 떨어뜨릴 수 있습니다. 다음 표는 HBM 구조를 요약한 것입니다:
| 단위 | 개수 |
|---|---|
| 스택 | 2 / Chip |
| 채널 | 16 / 스택 |
| Slice | 3 / 채널 |
| 뱅크 그룹 | 4 / Slice |
| 뱅크 | 4 / 뱅크 그룹 |
| 행 | 16K / 뱅크 |
| 바이트 | 2K / 행 |
최대 대역폭
단일 DMA Engine(용량 256GB/s)을 포화시키려면 여러 채널에 걸쳐 액세스를 인터리빙해야 합니다. 최대 HBM 대역폭은 스택과 Channel의 병렬 동작을 통해 Chip당 1.5TB/s에 이릅니다. 채널 컨트롤러는 0.75GHz에서 사이클당 64B를 전송하며,1 이는 채널당 48GB/s(0.75GHz x 64B/cycle), Chip당 1.5TB/s(48GB/s x 32채널)에 해당합니다. 기본 전송 단위는 256바이트이며, 채널당 4클록 사이클이 필요합니다.
최대 대역폭은 접근 패턴에 민감합니다. 정렬 불일치, 뱅크 충돌, 리소스 공유는 각각 처리량을 심각하게 저하시킬 수 있습니다. 각 채널 컨트롤러에는 페널티를 최소화하도록 액세스를 인터리빙하는 64개 항목의 명령 큐가 있지만, 병적인 경우에는 여전히 심각한 성능 저하가 발생할 수 있습니다. 다음 절에서는 성능 저하의 원인과 이를 피하는 방법을 설명합니다.
Chip 내 주소 공간
HBM 주소 공간은 병렬 순차 액세스에 최적화된 비선형 비트 매핑을 사용합니다. 이 설계는 병렬성을 극대화하고 오버헤드를 최소화합니다:
| 비트 번호 | 주요 구성 요소 | 추가 구성 요소 |
|---|---|---|
| 0–7 | 바이트 | |
| 8 | 스택 | |
| 9–12 | Channel | |
| 13 | 뱅크 그룹 | Channel |
| 14–16 | 바이트 | Channel |
| 17–18 | 뱅크 | Channel |
| 19 | 뱅크 그룹 | Channel |
| 20 | Slice | Channel |
| 21–33 | Row | Channel (21–28) |
| 34 | Slice | Row |
| 35 | Row |
각 구성 요소의 비트 할당은 물리적 메모리 구조에 대응합니다. 예를 들어 byte 구성 요소는 행당 2K(2^11)바이트를 표현하기 위해 11비트(비트 0-7, 14-16)를 차지합니다. 다음과 같은 세 가지 예외가 있습니다:
- Slice 표현: Slice는 세 개뿐이지만 Slice를 표현하는 데 두 비트(20과 34)를 사용합니다.
- 연속 주소 공간: 비트 34는 row 구성 요소의 영향을 받아 비트 34와 35가 동시에 1이 되지 않으며, 이를 통해 연속된 48GB 주소 공간이 보장됩니다.
- Channel XOR 매핑: channel 구성 요소는 비트 9-12와 13-28의 XOR과 같습니다(예: channel의 첫 번째 비트는 비트 9, 13, 21, 25의 XOR과 같습니다).
이러한 비트 순서 덕분에 순차 접근이 스택, 채널, 뱅크 그룹, 뱅크에 동시에 분산되므로 여러 메모리 자원이 병렬로 계속 동작합니다.
정렬되지 않은 접근
정렬되지 않은 접근은 HBM 성능을 크게 저하시킵니다. 256바이트 경계를 넘는 읽기는 두 번의 전송이 필요하고(2배 페널티), 정렬되지 않은 쓰기는 Read-Modify-Write(RMW) 연산이 필요합니다(약 50배 페널티). 256바이트 최소 접근 단위는 비트 0-7(하위 8비트)로 정의되므로, 이 경계를 넘는 데이터에는 이러한 페널티가 발생합니다.
- 정렬되지 않은 읽기: 256바이트 경계를 넘는 읽기 요청은 두 번의 NoC 전송이 필요하므로 대역폭이 사실상 절반으로 줄어듭니다.
- 비정렬 쓰기 또는 부분 쓰기: 비정렬 쓰기는 DMA 패킷이 내부적으로 256바이트 트랜잭션 단위로 분할되기 때문에 발생합니다. 패킷 크기가 256바이트 단위로 정렬되지 않은 경우(예: 2,800바이트 패킷은 256바이트 요청 10개와 240바이트 요청 1개로 분할됨), 마지막 “나머지” 트랜잭션에는 RMW 연산이 필요합니다. RMW는 256바이트 단위 전체를 읽고, 요청된 바이트를 갱신한 다음, 단위 전체를 다시 씁니다. RMW는 정렬된 쓰기에 비해 쓰기 속도를 약 50배까지 늦출 수 있습니다.
뱅크 충돌
HBM 뱅크는 한 번에 하나의 행만 열어 둡니다. 같은 뱅크 안에서 다른 행으로 전환하려면 현재 행을 닫고 새 행을 열어야 합니다. 이로 인해 40-50 ns(1.5 GHz 기준 60-75 사이클)의 지연 시간이 추가되며, 이는 이미 열린 행에 접근하는 것보다 30-40배 느립니다. 이 페널티는 연속된 접근이 같은 뱅크 안의 서로 다른 행을 대상으로 할 때마다 발생합니다. 모든 행은 닫힌 상태로 시작하므로, 어떤 행이든 첫 접근에서는 항상 행을 여는 비용을 치릅니다.
Channel 인터리빙은 뱅크 충돌을 완화합니다. 32개 채널 전체에 걸쳐 접근을 인터리빙하면 부하가 분산되고 충돌이 줄어듭니다. 비트 8-12(그다음 하위 5비트)는 독립적인 스택과 채널을 나타냅니다. 이 비트들을 하위 주소에 배치하면 인접한 접근 간의 간섭을 막을 수 있으며, 이는 연속 연산을 병렬화하는 데 매우 중요합니다. Channel 구성 요소가 비트 9-28에 걸쳐 있으므로, 비연속 연산은 자연스러운 Channel 인터리빙의 이점을 얻는 경우가 많습니다. 그러나 스택 성분은 비트 8에만 대응하므로, 완전한 스택 인터리빙을 달성하려면 프로그래머가 접근이 두 스택 사이를 번갈아 가도록 명시적으로 보장해야 합니다.
컨트롤러는 명령 인터리빙을 통해 행 전환 지연 시간을 숨깁니다. 각 채널 안에서 컨트롤러는 뱅크 간에 명령을 자동으로 인터리빙하여, 다른 뱅크가 행 전환을 수행하는 동안에도 유효한 전송이 이루어지도록 합니다. 컨트롤러는 명령 큐를 사용하여 뱅크 상태를 관리합니다. 컨트롤러는 FR-FCFS(First Ready-First Come First Served) 스케줄링을 사용하여, 이미 열린 행을 대상으로 하는 명령을 우선 처리합니다.
이러한 정교한 스케줄링에도 불구하고, 같은 뱅크 안에서 계속해서 행을 전환하는 접근 패턴은 여전히 성능을 크게 떨어뜨립니다. 컴파일러와 프로그래머는 코드를 생성할 때 행 전환 비용을 추정해야 합니다.
열 간 지연(Column-to-Column Delay)
tCCD(Column-to-Column Delay)는 같은 채널에서 연속된 읽기 또는 쓰기 명령 사이의 최소 시간이며, 이 값이 최대 명령 발행 속도를 결정합니다. 대부분의 접근 패턴에서는 tCCD가 병목이 되기 전에 뱅크 충돌이나 Channel 인터리빙이 지배적인 요인이 됩니다. 벤더 사양은 DRAM 스택 레이어와 공유 자원에 접근할 때의 아날로그 제약 조건을 바탕으로 tCCD 값을 정합니다.
tCCD 값은 연속된 명령이 어떤 메모리 자원을 대상으로 하는지에 따라 달라집니다:
| 명령 관계 | tCCD(1.5GHz 기준 사이클) | 상대 성능 | 페널티 원인 |
|---|---|---|---|
| 같은 Slice, 다른 뱅크 그룹 | 2 | 1 | 뱅크 그룹의 이상적인 인터리빙 |
| 다른 Slice | 3 | 2/3 | 데이터 경로 전환 |
| 같은 Slice, 같은 뱅크 그룹 | 4 | 1/2 | 네 뱅크가 공유하는 I/O 버퍼 |
한 Slice 안에서 뱅크 그룹을 인터리빙하면 1.5GHz에서 tCCD = 2 사이클이 됩니다. 이렇게 하면 0.75GHz 사이클마다 새로운 64B 명령을 보낼 수 있어 채널 최대 속도에 도달합니다. tCCD가 2보다 크면 명령 속도와 채널 활용률이 떨어집니다.
뱅크 충돌에 비해 tCCD로 인한 성능 저하는 덜 심각합니다. 최악의 패턴은 뱅크 충돌과 동시에 발생하거나(이 경우 tCCD는 부차적인 영향이 됨) Channel 인터리빙에 의해 가려지기 때문입니다:
- 다른 Slice(
tCCD = 3): Slice ID는 비트20에 대응하고, 비트21은 로우(row)에 대응합니다. 따라서 Slice 간 인터리빙은 뱅크 충돌을 동시에 일으킬 가능성이 높습니다. - 같은 Slice, 같은 뱅크 그룹(
tCCD = 4): 이 패턴은 비트13,19,20,34를 제외한 비트8-35를 인터리빙합니다. 비트29-35는 뱅크 충돌과 관련이 있습니다. 비트8-28은 Channel 인터리빙과 관련됩니다.
-
채널 컨트롤러는 0.75GHz의 주파수로 동작하지만 사이클당 8회의 버스트를 수행하므로 유효 주파수는 0.75×8=6GHz가 됩니다. ↩