Byeo

Understanding PCIe performance for end host networking 2 (PCIe 프로토콜) 본문

프로그래밍 (Programming)/논문 (Paper)

Understanding PCIe performance for end host networking 2 (PCIe 프로토콜)

BKlee 2024. 1. 17. 00:05
반응형

해당 포스트는 Sigcomm '18의 Understanding PCIe performance for end host networking 을 번역하여 정리한 글입니다.

 

Understanding PCIe performance for end host networking 1: https://byeo.tistory.com/entry/Understanding-PCIe-Performance-for-end-host-networking-1

 

Understanding PCIe performance for end host networking 1

해당 포스트는 Sigcomm '18의 Understanding PCIe performance for end host networking 을 번역하여 정리한 글입니다. 앞으로는 조금씩 요약하여 정리를 해볼까 합니다! 초록 최근 Programmable NIC의 등장과 발전으로

byeo.tistory.com

 

 

3. PCIe modelling

pcie-bench를 구현하기에 앞서, PCIe 설명서를 참고하여 PCIe 모델을 개발하였다. [PCI-SIG, 공식사이트에서는 구독자만 볼 수 있는 것으로 보인다. 대신, 구글에서 검색해보면 대략 1,300쪽 pdf가 있는 듯 하다.] 이 PCIe 모델은 (1) 설명서에 기반한 bandwidth 기댓값과 실제 측정값 비교, (2) 복잡한 device-host interaction을 갖고 있는 상황에서의 영향을 모델링할 수 있게 해준다.

 

  • PCIe는 엔드포인트간에 여러 개의 serial links (lanes)로 구성된 point-to-point topology 기반 interconnect를 높은 속도로 사용한다.
  • 이 데이터 교환은 다음과 같은 3가지 계층으로 이루어져 있다.: (1) physical, (2) data link, (3) transaction.
  • Data link layer (DLL)은 error correction, flow control, acknowledgements를 수행하고 (TCP 같다.), transaction layer는 user application data 혹은 완성된 (수신된) 데이터를 Transaction Layer Packets (TLPs)를 사용해 PCIe transaction으로 바꿔준다.

PCIe protocol, reference: oreilly.

  • 대부분의 40 Gbps NIC은 오늘날 PCIe 3.0 x 8 lanes를 사용한다. 각 lane은 8 GT/s (Giga Transactions per second)의 속도를 제공하며, 128b/130b encoding 기법을 사용한다. 이를 환산하면 $8 (lanes) \times 7.87 Gb/s = 62.96 Gbps$ 의 값을 나타낸다. ($7.87 Gb/s = 8 GT/s * 128b/130b$) 이 성능은 physical layer의 성능이다.
  • Data link layer는 8~10%의 overhead가 추가된다. 이는 flow control과 acknowldegement에서 기인한다. 이 계층의 overhead를 감산하면 57.88 Gbps ($62.96 Gbps \times (1 - 8.07\%)$)가 남는다. 매 transaction마다 physical layer는 2 Bytes의 프레이밍(양 끝에 1B씩)을, DLL은 6 Bytes의 헤더를 추가한다.
  • Transport layer계층을 살펴보자. TLP에는 다양한 종류가 정의되어있다. 이 논문에서는 NIC과 관련있는 TLP type만을 다룬다.: Memory Read (MRd), Memory Write (MWr), Completion with Data (CplD). TLP는 종류에 상관없이 공통헤더를 지니며, 그 외에도 타입-specific 헤더, 그리고 옵션 필드 (digest)가 존재한다.
  • TLP의 공통 헤더는 TLP의 종류와 TLP 길이가 적힌다. 타입-specific으로는, MWr과 MRd TLP가 12 Bytes의 길이를 (64 bit address system), CplD TLP는 8 Bytes를 추가로 지닌다. 
  • 하나의 TLP당 최대 data 수용 가능 길이 (Maximum Payload Size, MPS)는 각 peer별로 합의를 하여 결정된다. 마지막 4 Bytes digest는 end-to-end CRC (ECRC)가 포함되어있다. 
  • 일반적인 MPS 값은 256 Bytes 혹은 512 Bytes이다. (바이오스에서 설정 가능했던 것 같다!)

MWr 모델링

PCIe MWr transaction은 단순하게 보내는 (post) transaction이다. 따라서 $sz$ 크기를 DMA write하는데 전송되는 총 DMA bytes는 다음과 같다.

$$B_{tx} = \lceil sz/MPS \rceil \times MWr\_Hdr + sz \ \ \ \ (1)$$

여기서 $MWr\_Hdr$은 24 bytes (2 Bytes framing for phsycal, 6 Bytes DLL, 4 Bytes TLP, 12 Bytes MWr header를 모두 합한 값) 이다.

 

MRd 모델링

PCIe MRd transaction은 다음과 같은 두 가지 작업으로 이루어진다.: MRd TLPs와 CplD TLPs. MRd TLP는 peer에게 MRd TLP요청을 먼저 전송하고, peer는 하나 혹은 여러개의 CplD TLPs를 거쳐 데이터가 리턴된다. 따라서, PCIe memory read는 양쪽 방향으로 bandwidth를 소모한다!! MRd request는 한 번의 요청에 사전 협의(nego)된 특정 사이즈 (Maximum Read Request Size, MRRS, 바이오스에서 설정 가능했던 것 같다.)만큼만 요청한다. 일반적인 MRRS size는 512 Bytes이다. CplD TPs의 크기는 MPS에 제한된다. 따라서 $sz$ 만큼의 데이터를 DMA read 하기 위해 소모되는 최종 bandwidth는 다음과 같다.

$$B_{tx} = \lceil sz / MRRS \rceil \times MRd\_Hdr + sz \ \ \ \ (2)$$

$$B_{rx} = \lceil sz / MPS \rceil \times CplD\_Hdr + sz \ \ \ \ (3)$$

여기서 $MRd\_Hdr$는 24 Bytes, $CPL\_Hdr$은 20Bytes다.

 

예측

  • 장비의 PCIe configuration은 우리에게 가능한 bandwidth를 제안한다. 위 계산식을 이용하면 $sz$ 크기를 전송하는데 실질적인 bandwidth를 계산할 수 있다. Figure 1 (이전 포스트)Effective PCIe BW는 PCIe 3.0 x 8, MPS = 256 Bytes, MRRS = 512 Bytes, 64bit addressing의 시스템에서 계산된 값이다.
  • 상어 이빨 패턴은 매 MPS bytes마다 DLL/TLP 헤더가 추가 됨에 따라서 나타난 것이다. 이 비용은 전송 size가 작을수록 그 영향이 크게 나타난다. 
  • 그리고 MRRS의 배수에 해당하는 값을 넘어가면 MRd TLP의 overhead때문에 그 영향이 더 커진 것을 볼 수 있다.

복잡한 환경

  • 이 모델은 더 복잡한 device/host 상호작용에서의 비용도 계산할 수 있게 해준다. 예를들어, Figure 1의 Simple NIC을 이용해 Tx, Rx한 사례를 살펴보자. 
  • Tx의 경우에는 ① driver가 device에 있는 TX queue의 tail pointer를 update (4B PCIe write, driver write to device)한다. 그 다음에는 ② device가 descriptor를 DMA read (16B PCIe read, device read from driver)하며, 그 뒤에 ③ packet buffer를 DMA read (device read from driver)한다. 전송이 끝나면 ④ device는 interrupt를 생성하며 (4B PCIe write, device write to driver), 마지막으로 ⑤ driver는 TX queue의 head pointer를 읽는다  (4B PCIe read, driver read from device).
  • Rx의 경우에는 ① driver가 device의 freelist에 buffer를 enqueue 하기 위하여 RX queue의 tail pointer를 update한다 (4B PCIe write, driver write to device). 그 다음 ② device는 freelist descriptor를 DMA하여 가져오며 (16B PCIe read, device read from driver), ③ 인입된 packet (PCIe write, device write to driver)과 ④ RX descriptor (16B PCIe write, device write to driver)을 driver에게 전송한다. 마지막으로 ⑤ interrupt를 생성 (4B PCIe write, device write to driver)한다. 마지막으로, ⑥ driver는 RX queue head pointer를 읽는다 (4B PCIe read, driver read from device).
  • 모델은 이처럼 각각의 transaction마다 overhead를 계산한 뒤, 달성가능한 bandwidth를 얻을 수 있다.

현대의 NIC

  • 이 NIC model은 매우 간단한 NIC design을 모델링한 것이다.
  • 최신 NIC들은 정말 다양한 최적화를 적용하고 있다. 예를들어 Intel Niantic NIC의 경우에는 driver가 device에게 DMA를 40개의 TX descriptor까지 batching하여 처리할 수 있다. 반대로도 device가 driver에게 8개의 TX descriptor를 batching할 수 있다.
  • Intel DPDK driver의 경우에는 interrupt가 존재하지 않고, packet이 잘 전송/수신 됐는지 적혀있는 device register를 driver가 읽지 않음으로써 PCIe transaction의 수가 감소한다. 
  • Figure 1의 optimized NIC (Intel DPDK)로 알 수 있는 내용은 host driver와 device 양쪽을 잘 최적화 하는 것이 상당한 성능 향상을 이끌어낼 수 있다는 점이다.

다양한 PCIe device로의 적용

  • 우리의 PCIe 모델은 NIC이 달성가능한 throughput 값 만을 보여주는 것이 아니다. 이는 모든 PCIe device에 적용이 가능하다. 다만 device driver나 data sheet에 일반적으로 적혀있는 몇 가지 상세 사항을 확인하기는 해야한다. 
  • 나아가, 이 모델은 custom NIC functionality를 디자인하고 빠르게 평가하는데 사용이 가능하다.

모델의 몇 가지 한계

  • DLL의 flow control와 같은 몇몇 lower level PCIe overhead는 PCIe specification에 의해 추정치를 사용하였다. 따라서 우리의 model은 이 영향을 경미하게 과대평가할 수 있다.
  • 우리의 모델은 unaligned DMA read에서 발생할 수 있는 PCIe overhead를 고려하지 않는다. 이 과정은, 첫 CplD transaction으로 하여금 후속으로 오는 CplD transaction들이 알려진 Read Completion Boundary (RCB, 보통 64B)에 정렬될 수 있도록 조치해야 한다 (이해가 잘 안됨). 또한, 이러한 DMA not-aligned read는 추가 TLP를 발생시킬 수 있다.

4. PCIE-BENCH 방법론

  • PCIe 프로토콜 스택은 비교적 단순해서 모델링이 쉽지만, DMA의 구현 및 점점 증가하는 PCIe root complex의 복잡도는 실제 시스템의 PCIe 성능을 평가하기 어렵게 만든다. 따라서 우리는 lmbench, hbench:OS를 참고하여 PCIe micro-benchmarks를 디자인하였다.
  • Main idea는 device에서 host memory buffer로 각각의 PCIe operation을 수행하며, 그 중에서 성능에 영향을 줄만한 파라미터들을 신중히 제어한다.

  • Figure 3은 host buffer setup과 PCIe device가 접근할 수 있는 paramter들을 보여준다.
  • Host buffer는 (논리적으로) 연석된 버퍼 공간이다. 이 buffer는 DMA address space에서 연속적으로 존재하거나 혹은 더 작은 버퍼들 여러개로 구성되어 있을 수 있다. 
  • 이 buffer는 LLC size보다 상당히 커야한다. 몇몇 아키텍쳐에서는 PCIe root complex가 CPU의 cache system을 다루기 때문 (DDIO를 말하는 걸까?). 이 Cache effect를 측정하기 위해서, host buffer중에 일부 만큼 (window size)을 반복적으로 접근한다.

Micro-benchmark의 host buffer 구조

  • micro-benchmark에서는 호스트 buffer의 window size를 여러번의 DMA requests를 통해서 접근한다. 그리고 각 request마다 전달되는 data의 사이즈 (transfer size)를 고정한다. 
  • DMA는 host cache line에서 $offset$만큼 떨어져서 시작될 수 있다. 이는 unaligned DMA access에 대한 비용을 결정할 수 있게 해준다.
  • 각 DMA request가 cache line을 같은 횟수로 접근했는지 확인하기 위하여, window는 여러개의 동일한 $unit size$만큼 여러개로 분할되어 있다.
  • 이 unit size는 offset과 transfer size를 더하여 다음 캐시라인 까지 round up 한 값이다.
  • micro-benchmark는 이 unit을 순차적으로 접근할 지, 랜덤으로 접근할 지 설정할 수 있다. 

Cache Hit / Miss

  • 각 benchmark에서 CPU cache의 상태는 조심스럽게 제어되어야 한다. 기본적으로 benchmark가 실행되기 전에 모든 cache를 cold 상태로 만든다. 옵션으로, test 전에 cache를 warm 상태로 만들 수 있다. 이는 window에 데이터를 쓰는 방법 (host warm), 또는 device가 여러번의 DMA write를 날림으로써 device가 데이터를 쓰는 방법 (device warm)을 통해 가능하다. 
  • 여기서 host cache system의 영향을 이해하는 것은 중요하다. 보통 Host가 packet을 보낼 때에는 최소한 packet header는 cache에 있을 것이다. 반대로 Host가 packet을 받을 때에는, 시스템의 cache 사용 상황에 따라 packet data가 cache되지 않은 buffer로 DMA가 될 수도 있다. 결국, host buffer의 locality가 제어되어야 하는 것이다.
  • PCIe와 memory controller가 집적된 SMP 시스템에서는, host buffer 전체가 NUMA local이거나 NUMA remote이다.

4.1 Latency Benchmark

  • PCIe micro-bencharmks의 첫 번째 set은 각 PCIe operations들에 대해 latency를 측정한다. PCIe Memory Read (MRd) from device는 상대적으로 쉽다. DMA read를 요청하기 전에 timestamp를 찍어 놓고, DMA read completion이 도착했을 때 timestamp를 찍어 비교하면 된다. 이를 LAT_RD라 하자.
  • DMA Write (MWr)은 latency 측정이 쉽지 않다. Ack가 없기 때문. 대신에, MWr를 요청하고 마지막에 MRd를 같은 address에 한 번 요청한다. PCIe root complex는 read after write를 보장한다. 이를 LAT_WRRD라 하자. (WRRD인 이유는 WRite를 수행하고 마지막에 ReaD를 수행하기 때문)
  • 우리의 latency benchmark는 이 기록들에 대해 평균, 중간값, 최소, 최대, 95th, 99th의 값을 계산한다.
  • Latency 측정은 cache 비용과 IO-TLB miss의 비용을 평가할 수 있게 해준다. 또는 PCIe device로부터 remote memory를 접근하는데 추가되는 latency를 알 수 있게 해준다.
  • 우리의 latency benchmark는 비록 MWr의 값만 순수하게 계산할 수는 없지만, LAT_WRRD는 같은 address에 대해 write와 read를 함으로써 DDIO와 같은 기술에 대한 인사이트를 제공한다.
  • Latency 측정은 programmable NIC에 software를 작성할 때 혹은 reconfigurable DMA를 구현할 때 특히 중요하다. Latency와 이의 분산에 대한 측정은 in-flight DMA가 동시에 얼마나 handle 될 수 있는지 알 수 있다 (이전 포스트 참고).

4.2 Bandwidth Benchmark

  • PCIe micro-benchmark의 두 번째 set은 bandwidth에 집중되어 있다. DMA bandwidth는 DMA를 상당한 양을 발생시킴으로써 측정한다. 측정의 시작과 끝에 timestamp를 찍어 놓으며, 총 DMA양과 시간 차를 나누어 계산한다.
  • DMA Read (BW_RD)와 DMA Write (BW_WR)에 우리는 관심을 갖는다. 양방향 bandwidth를 측정하기 위해서는 DMA Read와 Write를 교대로 실행하여 측정한다 (BW_RDWR). 이는 PCIe MRd TLP가 PCIe MWR TLP와 root complex에서 bandwidth 경쟁을 얼마나 하는지 확인할 수 있게 해준다.
  • Bandwidth benchmark는 시스템에 상당한 load를 생성한다 (특히 작은 size를 요청할 때와 random access pattern일 때). 
  • 만약 DMA enging이 PCIe link를 64 byte transfer 만으로 포화시킬 경우에는, 초당 6950만개의 transaction을 양방향으로 발생시키는 것이며, root complex가 tnransacition을 5ns만에 처리하는 것이다.
  • 즉, 우리의 Bandwidth benchmark는 root complex의 한계점을 알아낼 수 있을 뿐만 아니라 device의 DMA engine 구현에 대해 stress test도 가능하다.
반응형
Comments