-
[SPDK] Direct Memory Access (DMA) From User Space논문 정리/Vertical optimization 2019. 9. 18. 01:28
SPDK가 사용하는 데이터 버퍼는 거의
spdk_dma_malloc
을 통해 할당되는데 이후 설명할 이유 때문이다. 또한 SPDK가 메모리 관리기법을 DPDK의 기본 기능을 통해 구현했는지도 설명한다.컴퓨팅 플랫폼들은 대부분 물리적 메모리를 4KiB 페이지 단위로 쪼개서 사용한다. 이후 쪼개진 페이지들을 virtual memory 기법을 사용해 물리적 메모리를 매핑하는 데 사용한다.
물리적 메모리는 여러 채널에 연결되어 있고, 각 채널의 일정한 대역폭을 제공한다. 대역폭을 최대화 하기 위해서 메모리 주소에 접근할 경우 접근되는 메모리 영역을 잘개 쪼개서 여러 채널로 분산되도록 한다. 예를 들어 page 0는 channel 0에, page 1 은 channel 1에, page2는 channel 2에 분산시키는 등이 있다. 실제로는 페이지 단위보다 훨씬 작은 단위로 병렬화를 시킨다.
현대 컴퓨팅 플랫폼에서는 이러한 작업을 소프트웨어적으로 처리하지 않고 MMU에 의존하여 가상 메모리 관리를 가속화 해서 사용한다. 최근의 x86_64 시스템의 MMU는 4KiB, 2MiB, 1GiB 단위의 페이지를 지원한다. 보통 OS는 4KiB 페이지를 사용한다.
NVMe는 데이터를 이동할 때 DMA를 사용한다. 전송할 데이터가 있을 경우 버스를 통해 메시지에 전송할 데이터의 주소를 전달한다. IOMMU가 존재하지 않을 경우에는 physical 메모리 주소를 포함해야 한다. 이후 실제 데이터 전송은 CPU를 거치지 않고 MMU에 의해 자동으로 처리된다.
NVMe 1.0에서는 추가로 모든 물리 메모리가 PRP list로 표현되어야 함을 요구하고 있다. PRP list로 표현되기 위해서는 아래와 같은 속성을 따라야 한다.
- 메모리는 4KiB 페이지 단위로 쪼개질 수 있어야한다. (디바이스 페이지로 칭함)
- 첫 번째 디바이스 페이지는 시작 주소가 4 byte 로 align 된 partial page 일 수 있으나, 해당 페이지가 속한 4KiB의 끝까지만 공간을 차지할 수 있다.
- 두개 이상의 페이지가 존재하는 경우에 첫 번째 페이지의 끝은 4KiB에 align 되어야 한다.
- 마지막 디바이스 페이지는 4KiB 이하의 사이즈여도 된다.
스펙 문서에서는 4KiB가 아닌 다른 사이즈도 허용하고 있으나, 현재 시점으로는 대부분 4KiB를 사용한다.
NVMe 1.1에서는 완전히 유연한 scatter/gather list가 추가되었으나 선택사항이라서 대부분의 장치에서는 이를 지원하지 않는다.
SPDK의 유저 스페이스 드라이버는 일반적인 유저 프로세스 관점으로 동작하므로 virtual memory로 메모리를 접근한다. NVMe 를 지원하기 위해 정확한 물리 메모리 주소를 얻기 위해서는 변환 과정이 필요하다.
가장 간단한 방법은 linux의
/proc/self/pagemap
을 확인하는 것이다. 해당 파일은 현재 파일에 접근하는 프로세스의 virtual to physical memory address mapping을 보여준다. linux 4.0 기준으로 해당 파일에 접근할 때에는 root 권한을 필요로 한다. OS는 해당 매핑 정보가 정적(변하지 않음)임을 기본적으로 보장하지 않는다. OS 드라이버를 unbind 했으므로 OS는 장치가 DMA를 통해 물리 메모리에 접근하는 중인지 아닌지를 판단하지 못하므로 DMA 작업을 수행할 때에는 메모리 매핑이 변화함을 이해하고 다양한 상황을 대비하여야 한다. 매핑 정보가 바뀌지 못하도록 OS 레벨에서 flag를 변환하는 것을 pinning 이라고 한다.v2p 매핑 정보가 변하는 데에는 다양한 이유가 있다. 가장 일반적인 이유로는 page swapping, memory compaction (중복된 데이터를 갖는 페이지를 하나로 통합), memory compression, hot-add physical memory 상황이 있다.
POSIX 에서 제공하는
mlock
은 가상 메모리 하나당 물리 메모리가 반드시 할당되어 있어야 함을 보장하지만 (swap 을 disable 함), 매핑 정보가 static 함을 보장하지는 않는다. 매핑 정보가 static 함을 보장하기 위해서는 pin 을 수행해야 한다.SPDK는 DPDK의 pinned memory 관리 기법을 이용한다. Linux를 기준으로 DPDK는
hugepages
를 미리 할당하는 방식으로 해결한다.hugepage
를 할당할 경우 일반적인 4KiB 페이지와 별개로 취급하며 해당 영역에 할당된 물리 메모리의 위치를 절대로 변경하지 않는다. 이러한 구현은 linux가 의도적으로 한것이 아니므로 미래에는 변경될 가능성이 있지만 몇년간 유지되어 왔다. 미래에 변경될 경우에 대비한 방법은 IOMMU 섹션에서 설명하도록 한다.이러한 이유로 인해 pinned memory를 생성하기위해
spdk_dma_malloc
의 사용이 필요하다.IOMMU Support
많은 플랫폼들이 I/O Memory Management Unit (IOMMU)라고 부르는 하드웨어 장치를 사용한다. 일반적인 MMU와 유사한 기능을 제공하고, 주변 장치들이 메모리를 가상 주소로 접근할 수 있도록 해주는 기능을 추가로 제공한다. IOMMU는 각 프로세스 별로 할당된 v2p 을 알 수 있으며, 유저 프로세스에서 임의의 bus address 를 할당해서 해당 프로세스 내의 virtual process에 접근할 수 있도록 해준다. 이를 통해 주변 장치의 DMA 작업들은 모두 IOMMU의 bus address 를 통해 동작하고, IOMMU는 이를 virtual address로 변환하고 이를 통해 physical address로 접근하는 작업을 수행한다. 이러한 기능을 이용할 경우 OS가 매핑 정보를 마음대로 바꾸어도 문제가 없으며, 리눅스에서는
vfio-pci
드라이버를 통해 이를 제공한다.이 방식을 사용할 경우 SPDK나 DPDK의 메모리 관리 기법을 향후에도 유지할 수 있다. 거의 대부분의 플랫폼에서 이를 지원하므로 SPDK를 사용할 경우 vfio 와 IOMMU 기능을 모두 사용할 것을 권장한다.
'논문 정리 > Vertical optimization' 카테고리의 다른 글
[SPDK] What is SPDK? - SPDK 란 무엇인가? (0) 2019.09.19 [SPDK] Message Passing and Concurrency Theory (0) 2019.09.18 [SPDK] Concept - User Space Drivers (0) 2019.09.17 VirtIO-trace: 가상화 환경에서 NVMe SSD 입출력 특성 분석을 위한 통합 도구 (0) 2018.04.17 Don't stack your Log on my Log (0) 2016.03.19