2013. 9. 12. 00:53

Device and Driver Layering I

오늘은 디바이스와 드라이버 레이어에 대해 공부해 봅시다.

 

Windows Driver Model(이하 WDM)은 아래 그림과 같이 드라이버 레이어를 표현하고 있습니다.

 

 

 

  일반적으로 디바이스 오브젝트의 스택은 위의 그림처럼 표현합니다. (디바이스에 따라 디바이스 스택은 위의 그림보다 계층이 적을 수도 혹은 보다 많을 수도 있음을 유의하셔야 합니다) 우선 디바이스 오브젝트를 정의하자면, 이것은 소프트웨어가 하드웨어를 관리하기 위해 시스템이 생성한 데이터 스트럭쳐라고 할 수 있습니다. 하나의 디바이스 오브젝트는 I/O REQUEST를 처리하기 위한 논리적, 가상 혹은 물리적인 디바이스를 의미합니다. 전혀 관련이 없는 다른 개념이지만 좀 더 이해를 돕고자 비유한다면, 우리는 객체 지향에서 어떤 기능과 속성을 포함하는 클래스라는 용어를 알고 있습니다. 그리고 클래스로 각기 다른 속성값을 가지고 있는 메모리에 존재하는 객체나 인스턴스로 생성하여 이를 표현합니다. 이 비유에서 클래스는 논리적인 디바이스, 가상의 디바이스나 물리적인 디바이스를 의미합니다. 그리고 객체는 디바이스의 고유의 속성을 표현하기 위한 디바이스 오브젝트로 비유할 수 있습니다. 이 개념 비유는 절대적인 비유라고 할 수 없으며, 단지 이해를 돕기 위해서 이렇게 설명을 드립니다. 그래서 물리적인 디바이스 하나를 위해, 많은 디바이스 오브젝트가 존재할 수 있습니다. 디바이스 스택에서 가장 낮은 레벨의 디바이스 오브젝트는 PDO(Physical Device Object)라고 하며, 디바이스 스택에서 중간 계층 레벨에 존재하는 디바이스 오브젝트는 FDO(Functional Device Object)라고 합니다. 그리고 위의 그림에서 보이는 것과 같이, FDO의 위와 아래에는 하나 이상의 FiDO(Filter Device Object)가 위치할 수도 있습니다. 통상 FDO 위에 위치한 Filter Device Object는 Upper filter라고 하며, FDO와 PDO 사이에 위치한 Filter Device Object는 Lower filter라고 정의합니다.

  그렇다면 디바이스 스택은 언제 구성하게 될까요? 간략히 순서를 설명하면, 시스템을 부팅하는 동안 버스 드라이버는 버스에 연결된 디바이스를 열거하고 각 디바이스들의 PDO를 생성합니다. 그리고 PnP Manager는 버스 드라이버가 생성한 PDO list를 참조하여 각 드라이버의 엔트리 포인트인 DriverEntry를 호출하여 콜백 루틴을 초기화하고 AddDevice로 디바이스를 위한 FDO를 생성하고 이를 디바이스 스택에 추가합니다. 물론, 여전히 PDO와 FDO 개념에 대한 감이 오지 않을 것이라고 생각합니다. 한 가지 예를 들어 보도록 하겠습니다. 컴퓨터에 연결된 키보드 하나가 연결되어 가정합시다. 키보드는 흔히 우리가 잘 알고 있는 디바이스입니다. 당연히 키보드의 입출력을 처리하기 위한 키보드 디바이스 드라이버가 필요할 것입니다. 위에서 부팅 과정 중에 버스 드라이버가 모든 디바이스들을 열거한다고 하였습니다. 당연히 키보드도 디바이스기 때문에 열거가 되겠지요. 여기서 버스 드라이버가 인식한 키보드 장치를 관리하기 위해 생성한 객체가 바로 PDO(Physical Device Object)가 됩니다. 자, 그럼 생성하고 나서 키보드가 동작을 해야되겠죠? 이에 키보드 드라이버는 키보드 기능 동작에 관한 세부적인 설명을 기술한 FDO(Functional Device Object)를 생성합니다.

  위에서 언급한 것처럼, 버스 드라이버가 디바이스의 PDO를 생성하고 해당 디바이스의 드라이버에서 구체적으로 기능적인 역할을 위해 FDO를 생성한다고 하였습니다. 그 이후의 동작 과정을 살펴보면, PnP Manager가 버스 드라이버에 의해 생성된 PDO List를 참조하여 디바이스 스택의 중간 계층에 위치한 Filter와 Function 드라이버를 찾기 위해 레지스트리 데이터 베이스를 조사합니다. 여기서 레지스트리 데이터 베이스는 디바이스 드라이버에 대한 여러가지 정보를 가지고 있는데, 특정 레지스트리 엔트리에서 디바이스 스택상에 순서대로 스택을 구성할 드라이버를 정의하고 있습니다. 그다음 PnP Manager는 가장 낮은 레벨의 Filter Driver를 로딩하고 Object를 생성하고나서 AddDevice Function을 호출합니다. 그리고 여기에서 FiDO(Filter Device Object)를 생성하고 이를 PDO와 연결하는 작업을 합니다. 마찬가지로 PnP Manager는 현재 구성중인 디바이스 스택에서 로딩하고 호출할 하위 Filter Driver, Function Driver, 상위 Fiter Driver의 Object를 각각 생성하고 차례대로 아래에서부터 서로 연결하여 디바이스 스택을 구성합니다. 결과적으로 위의 그림과 같이 디바이스 스택이 형성됩니다.

 

(참조 : http://www-user.tu-chemnitz.de/~heha/oney_wdm/ch02b.htm)

 

 

시간이 늦었으니, 오늘은 간단히 여기까지만 정리하도록 하겠습니다.

 

 

Written by Simhyeon, Choe

 

2013. 9. 8. 02:24

AMBA AXI PROTOCOL v1.0 - ADDITIONAL CONTROL INFORMATION

AXI가 지원하는 SYSTEM LEVEL의 CACHE와 PROTECTION UNIT에 대해 알아 봅시다.


Support for system level caches and other performance enhancing components is provided by the use of the cache information signals, ARCACHE and AWCACHE. These signals provide additional information about how the transaction can be processed.

 

 

The ARCACHE[3:0] or AWCACHE[3:0] signal supports system-level caches by
providing the bufferable, cacheable, and allocate attributes of the transaction:


AXI에서 인터커넥트 기반에서 마스터와 슬레이브간의 TRANSACTION 퍼포먼스를 개선하기 위해 몇 가지 CACHE SKIM을
지원합니다. 이것은 CACHE INFORMATION SIGNAL(ARCACHE와 AWCACHE)을 통해서 TRANSACTION을 처리하는 방법에 대해 추가적인 정보를 제공합니다. CACHE INFORMATION SIGNAL이 포함하고 있는 TRANSACTION의 속성은 BUFFERABLE, CACHEABLE 그리고 ALLOCATE가 있습니다.

 

1) Bufferable (B) bit, ARCACHE[0] and AWCACHE[0]
   When this bit is HIGH, it means that the interconnect or any component can delay the transaction reaching its
final destination for an arbitrary number of cycles. This is usually only relevant to writes.

 

문서에서 보면 "final destination"이라는 표현은 그 대상이 마스터나 슬레이브일 수도 있으며 혹은 IP와

INTERCONNECT 사이에 있는 또다른 Component를 의미합니다. 스펙에서 보면 Bufferable 경우에는 오로지 WRITE 동작에만 관련있다고 언급하니 어떤 IP가 요청한 WRITE TRANSACTION을 최종적으로 수신하는 IP(마스터 or 슬레이브)로 해석하시면 됩니다.

해당 비트가 HIGH일 때, TRANSACTION의 타깃이 되는 어떤 IP에서 임의의 CYCLE동안 해당TRANSACTION이 도달하는 것을 지연할 수 있다고 설명되어 있습니다. 아마도 이 설명으로 어떤 케이스가 있는지 잘 이해가 안되실 수도 있습니다만, 해당 케이스는 제가 예전에 포스팅한 [ARCHITECTURE OVERVIEW II]에서 언급된 REGISTER SLICE를 사용하는 케이스로 보시면 됩니다. 아래 그림으로 한가지 가정으로 필요성을 간단히 설명드리겠습니다.

 

 

 

마스터1이 슬레이브쪽으로 WRITE TRANSACTION을 전송하려고 하나, 현재 슬레이브는 마스터2와 TRANSACTION을 R/W하는 관계로 BUSY 상태에 놓여 있어서 WRITE TRANSACTION을 할 수 없습니다. 그 후 슬레이브는 다시 IDLE 상태가 되어 마스터1의 WRITE TRANSACTION을 받을 수 있는 상태가 되었습니다. 하지만 이번에는 INTERCONNECT가 다른 여러 IP들로부터 많은 TRANSACTION REQUEST에 의해 DECODING TIME이 길어지고 결과적으로 마스터1로부터 WRITE TRANSACTION을 처리하는 LATENCY 지연이 발생할 수 있습니다. 이 때문에 SLAVE와 INTERCONNECT 사이에 MASTER TRANSACTION을 임시로 저장할 REGISTER SLICE를 버퍼로 두어, SLAVE가 다른 마스터의 통신하느라 BUSY 상태라고 하더라도 버퍼에 미리 저장하여 슬레이브가 IDLE 상태가 될 때까지 WRITE TRANSACTION을 지연하고 있습니다. IDLE 상태가 되면 슬레이브는 INTERCONNECT DECODING 상태와 상관없이 MASTER REGISTER SLICE를 통해서 바로 WRITE TRANSACTION을 처리할 수가 있습니다. 장황하게 설명하였는데 그냥 말 그대로 처리할 작업을 미리 더블 버퍼링하는 개념이 되겠지요.

 


2) Cacheable (C) bit, ARCACHE[1] and AWCACHE[1]
    When this bit is HIGH, it means that the transaction at the final destination does not have to match the
characteristics of the original transaction.
For writes this means that a number of different writes can be merged together.
For reads this means that a location can be pre-fetched or can be fetched just once for multiple read
transactions.
To determine if a transaction should be cached this bit should be used in conjunction with the Read Allocate
(RA) and Write Allocate (WA) bits.

 

해당 비트가 HIGH일 때, 최종 타깃 IP의 TRANSACTION이 원래 TRANSACTION과 일치하지 않아야 한다는 것을 명시하고 있습니다. 이것이 무엇을 의미하는지 잠시 후 다시 설명드리도록 하고 우선 해당 비트가 HIGH 아닌 경우를 먼저 살펴 보도록 하겠습니다. 아래 그림처럼 마스터와 슬레이브 사이에 하나의 INTERCONNECT가 존재하고 마스터와 INTERCONNECT간에는 32비트 버스 라인을, INTERCONNECT와 슬레이브간에는 64비트 버스 라인으로 구성된 버스 아키텍처가 존재한다고 가정하겠습니다.

 

여기서 만약 마스터가 슬레이브쪽으로 단지 32비트의 WRITE TRANSACTION을 두 번 이슈하는 상황이라면 총 4번의 Latency가 보입니다. 마스터에서 INTERCONNECT, 그리고 INTERCONNECT에서 슬레이브쪽으로 말이죠. 마스터가 보낸 WRITE TRANSACTION이 INTERCONNECT를 거치고 여기서 Final destination인 슬레이브쪽으로 바로 전달되는데 즉, 이것은 마스터가 보낸 WRITE TRANSACTION이 슬레이브 입력으로 항상 일치하게 됩니다.

그럼 이번에는 다시 Cacheable 비트를 HIGH 세팅한 경우를 살펴 보도록 합시다.
WRITE하는 경우의 의미를 보면, 다수의 다른 WRITE TRANSACTION를 하나의 TRANSACTION로 합칠 수 있다고 설명하고 있
는데요. 마스터가 INTERCONNECT쪽의 버퍼(REGISTER SLICE)에 첫 번째 32BIT WRITE TRANSACTION을 이슈합니다. 그리고 두 번째 32BIT WRITE TRANSACTION을 이슈합니다. 그러면 버퍼에 64BIT WRITE TRANSACTION으로 합쳐집니다. 그러고나서 슬레이브쪽으로 한 번에 64BIT WRITE TRANSACTION을 이슈함으로써 총 3번의 Latency가 보입니다. 결론적으로 1번 줄어들게 되는 상황이 됩니다. READ의 경우도 TRANSACTION 방향만 달라질 뿐이고 역시 마찬가지겠지요.

 

오늘은 시간이 늦었으니 여기서 이만 줄이겠습니다. 나머지 내용들은 나중에 다시 설명드리도록 하겠습니다. 즐거운 주말 보내세요.

 

 

Written by Simhyeon, Choe

 

2013. 9. 5. 22:57

NVM Express 1.1 - INSTRODUCTION

NVM Express 1.1에 스펙 리뷰를 진행하도록 하겠습니다.

 

1.1 Overview
NVM Express (NVMe) is a register level interface that allows host software to communicate with a non-volatile memory subsystem. This interface is optimized for Enterprise and Client solid state drives, typically attached to the PCI Express interface.

 

위에서 설명된 정의처럼, NVM Express(이하 NVMe)는 Non-volatile memory subsystem 즉, SSD와 같은 저장 장치와 호스트 소프트웨어(일반적으로 디바이스 드라이버를 의미)간에 통신하는 레지스터 레벨의 인터페이스라고 정의하고 있습니다. 좀더 요약하면 호스트와 디바이스간에 통신하는 방법에 대해 기술한 스팩이라고 할 수 있습니다.

 

 

 

NVMe 스펙 1.0은 2011년 3월 1에 처음 릴리즈되었으며, PCI Express bus 기반의 SSD를 타깃으하고 있습니다. SSD는 PCI Express bus에 이미 개발되었지만, 시장에서는 여전히 비표준 스펙의 인터페이스를 사용중이었습니다. 그래서 SSD 인터페이스의 표준화를 위해, 모든 제조사의 SSD와 통신할 수 있는 호스트 디바이스 드라이버가 필요하였지요. 또한 과거도 그렇고 현재까지 대부분 SSD는 SATA와  같은 버스 인터페이스를 사용하고 있습니다. SATA는 퍼스널 컴퓨터에서 SSD를 연결하는 가장 일반적인 방법이지만, 당시 SATA는 SSD와 비교해 상대적으로 저속의 Hard Disk를 위해 디자인되었습니다. SSD의 성능은 점점 개선되고 현재에 와서 병렬적으로 더 많은 처리량을 필요로 하고 있지만 근본적으로 SATA가 가진 인터페이스 디자인의 한계로 인해, 최대 처리량이 제한되는 한계점에 도달하였습니다.

이것이 바로 PCIe bus를 기반으로 하는 NVMe가 출현하게 된 배경이라고 할 수 있습니다.

 

 

1.4 Theory of Operation
NVM Express is a scalable host controller interface designed to address the needs of Enterprise and Client systems that utilize PCI Express based solid state drives. The interface provides optimized command submission and completion paths. It includes support for parallel operation by supporting up to 64K I/O Queues with up to 64K commands per I/O Queue. Additionally, support has been added for many Enterprise capabilities like end-to-end data protection (compatible with T10 DIF and SNIA DIX standards), enhanced error reporting, and virtualization.

 

NVMe의 두드러지는 특징 중 하나는 커맨드를 처리하기 위한 SUBMISSION QUEUE와 처리가 완료된 커맨드 정보를 저장하기 위한 COMPLEITION QUEUE가지고 MULTIPLE OUTSTANDING 방식으로 커맨드를 보내고 완료합니다. (Multiple Outstanding : 커맨드가 처리될 때까지 기다리지 않고 계속적으로 커맨드를 QUEUE에 넣는 방식)

 

그리고 각 큐의 최대 엔트리는 64K개까지 가질 수 있으며, 큐 역시 Submission, Completion 각각 64K개를 생성할 수 있습니다. 요약해서 대량의 커맨드를 보내고 처리할 수 있는 구조를 가졌지요.

 

아래의 NVMe의 핵심적인 속성을 설명하기 앞서, 기존의 인터페이스 아키텍쳐인 SATA 기반의 AHCI와비교해서 설명하도록 하겠습니다. 항상 새로운 아키텍쳐가 나오면 기존의 아키텍쳐와 비교해 어떤 장점이 있는지 살펴보는 자세는 매우 중요합니다. 그래야 최신 아키텍쳐를 보다 더 잘 이해할 수가 있거든요.

 

NVMe vs. AHCI

(테이블 출처 : http://www.extremetech.com/computing/161735-samsung-debuts-monster-1-6tb-ssd-with-new-high-speed-pcie-nvme-protocol)

 

 

1) Un-cacheable register access

 - 6 times or 9 times per command on AHCI vs. 2 times per command on NVMe

 

   AHCI의 경우, HBA(Host Bus Adapter)를 중심으로 Host와 Device간의 인터페이스를 하도록 디자인되어 있습니다. HBA는 PxCI, PxSA, PxCLB, PxCLB와 같이 커맨드를 처리하는 과정중에 순차적으로 확인하고 세팅하는 레지스터를 가지고 있습니다. 그래서 AHCI에서는 커맨드 하나를 이슈하고 완료하기위해 non-queued command는 6번, queued command는 9번의 HBA 레지스터 접근이 필요합니다. 만약 Command List에서 최초 32개 command가 모두 queued command라고 가정하면, 커맨드를 이슈하고 처리하는 데에 32 * 9의 오버헤드가 보여질 수 있다는 것을 의미합니다. 하지만 HDD의 속도는 매우 느리기 때문에 최초 32개의 command를 모두 큐잉하는 과정 중에 잠시 보였다가 이후부터는 HDD Seek Time Latency로 가려질 것입니다. 더구나 Sequential Read/Write에서는 위에서 언급한 오버헤드는 의미가 없다고 봐도 무방하지요. 다시 요약하면 느린 HDD의 성능을 고려하면 위의 오버헤드는 전혀 고려 대상이 아니었을 겁니다. HDD와 달리, NVMe는 고성능 Server향 SSD를 타깃으로 한 스펙입니다. Server향 SSD의 핵심적인 키워드는 응답 속도와 Random Read/Write의 성능인데, 기존의 AHCI와 같은 아키텍쳐로 충분한 Throuhput을 가질 수 있을까요? NVMe는 하나의 Queue가 가질 수 있는 최대 엔트리 갯수는 64K개, 그리고 그런 사이즈의 Queue를 64K개만큼 스펙상 이론적으로 생성 가능합니다. 위에서 언급한 레지스터 접근에 대해 다시 한 번 더 상기하면, AHCI는 커맨드 하나를 이슈하고 처리하는 데에 9번의 레지스터 접근(NCQ Command의 경우)을 해야한다고 언급하였습니다. 그에 반해 NVMe는 단 2번의 레지스터 접근으로 이슈하고 처리할 수 있지요. 즉, AHCI가 Command를 1번 이슈하고 처리할 동안 NVMe는 4번할 수 있다는 의미가 됩니다. 만약에 HBA를 기반으로 한 AHCI 아키텍쳐로 대량의 64K개의 큐 엔트리를 가지는 64K개의 큐에 커맨드를 이슈하고 처리한다면 64K * 64K * 4의 엄청난 버든이 발생할 수 밖에 없습니다. 그리고 클라이언트로부터 Random Read/Write가 아주 빈번하게 발생하는 상황이라면 매번 연산할 때마다 레이턴시가 보이기 때문에 고성능 SSD임에도 불구하고 처리량은 매우 제한적인 결과를 초래할 수 밖에 없게 되겠지요. 그래서 NVMe에서는 복잡한 레지스터 접근을 최소화하기 위해 HBA를 사용하지 않고 호스트 컨트롤러와 디바이스 컨트롤러가 직접 인터페이스하도록 설계를 하였습니다.

 

 

2) Command Queue

 - One command list and 32 commands per queue on AHCI vs.

   64K Cmd / 64K Queues on NVMe

 

NVMe에서는 이슈할 커맨드를 저장하는 SQ(Submission Queue)와 완료한 커맨드 정보를 저장하는 CQ(Completion Queue)로 나누어서 Command 처리를 합니다. 여기서 의문을 가져야 할 점이 있습니다. AHCI처럼 하나의 Command List로 커맨드를 이슈하고 완료하는 것을 각 32개의 Command Slot 마다 PxCI 레지스터로 확인할 수 있는데 굳이 SQ와 CQ로 나누어서 커맨드를 처리하려는 이유에 대해서 말입니다.

 

[AHCI Command List에서 command 처리/완료 확인 방식]

 

(위의 그림은 단지 AHCI Command List의 Command 처리/완료를 단일 큐에서 이루어지는 것을 설명하기 위해 간단히 도식화한 점을 유의하시기 바랍니다)

 

이유는 간단합니다. AHCI에서는 Command를 전달하고 처리할 때 HBA의 DMA가 그 역할을 담당하지만 NVMe는 디바이스쪽의 컨트롤러가 호스트의 Command를 패치해 옵니다. 이렇게 전혀 다른 방식으로 구동하는데 바로 HBA의 DMA가 버든이 적지 않을 거라는 예상이 가능합니다. 매번 32개의 Command Slot을 폴링 방식으로 확인하고 커맨드를 처리해야 할 의무가 있기 때문입니다. 만약에 Queue Entry가 64K개이고 Queue의 갯수가 64K개라는 Worst Case를 가정하면 엄청난 버든이 될 수 밖에 없겠지요. 따라서 NVMe에서는 처리할 커맨드를 SQ에다가 올려두면 디바이스쪽의 컨트롤러가 이를 패치하고 처리한 후에 완료했다는 정보만 호스트에게 알려주는 쉬운 자료구조로 디자인하였습니다.


The interface has the following key attributes:
 Does not require uncacheable / MMIO register reads in the command submission or

   completion path.
 A maximum of one MMIO register write is necessary in the command submission path.
 Support for up to 64K I/O queues, with each I/O queue supporting up to 64K commands.
 Priority associated with each I/O queue with well-defined arbitration mechanism.
 All information to complete a 4KB read request is included in the 64B command itself,

    ensuring efficient small I/O operation.
 Efficient and streamlined command set.
 Support for MSI/MSI-X and interrupt aggregation.
 Support for multiple namespaces.
 Efficient support for I/O virtualization architectures like SR-IOV.
 Robust error reporting and management capabilities.
 Support for multi-path I/O and namespace sharing.

 

 

일단 오늘은 여기까지 마무리하고 내일 다시 AHCI와 NVMe를 계속 비교하여 설명드리도록 하겠습니다.

 

 

Written by Simhyeon, Choe