모든 프로그래머가 알아야 할 메모리, 1부

ko생성일: 2025. 8. 19.갱신일: 2025. 8. 19.

현대 범용 하드웨어 구조(노스브리지/사우스브리지, 통합 메모리 컨트롤러, NUMA)와 DRAM의 동작 원리·타이밍·유형(DDR/DDR2/DDR3, FB‑DIMM), 그리고 메모리 접근이 성능에 미치는 영향을 소프트웨어 관점에서 설명하는 연재의 첫 편입니다.

LWN을 한 번 이용해 보시겠습니까? LWN 구독으로 리눅스와 자유 소프트웨어 커뮤니티의 최신 흐름을 따라가고, 구독자 전용 기능도 활용해 보세요. 저희는 여러분이 직접 경험해 보실 수 있도록 신용카드 없이 **무료 체험 구독**을 제공합니다. 함께하세요!

[_편집자 서문: 최근 Ulrich Drepper가 메모리와 소프트웨어의 상호작용에 관한 장문의 문서를 집필했으며, 이를 게재할 의향이 있는지 문의해 왔습니다. 잠시만 살펴봐도 많은 LWN 독자들의 관심사임을 알 수 있었습니다. 메모리 사용은 종종 소프트웨어 성능을 좌우하지만, 메모리 병목을 피하는 방법에 대한 제대로 된 정보는 찾기 어렵습니다. 이 연재가 그 상황을 바꿔 줄 것입니다. 원문은 100쪽이 조금 넘습니다. 저희는 이를 약 일곱 부분으로 나누어, 앞선 글 이후 1~2주 간격으로 게재할 예정입니다. 전체 연재가 끝나면 Ulrich가 전문을 공개할 것입니다.

원래의 LaTeX 문서를 재편집하는 작업은 꽤 도전적이었지만, 결과는 만족스러울 것이라 기대합니다. 온라인 가독성을 위해 Ulrich의 각주는 {본문에 삽입}했습니다. 하이퍼링크 교차 참조(및 [참고문헌 인용])는 전체 연재가 출판될 때까지 제공되지 않습니다._

이 자료의 게재를 허락한 Ulrich에게 깊이 감사드립니다. 가까운 미래에 우리의 시스템 전반에서 보다 메모리 효율적인 소프트웨어가 늘어나길 기대합니다.]

1 Introduction

초기의 컴퓨터는 훨씬 단순했습니다. CPU, 메모리, 대용량 저장장치, 네트워크 인터페이스 등 시스템의 여러 구성요소가 함께 개발되었고, 그 결과 성능 면에서 꽤 균형을 이루었습니다. 예를 들어, 메모리와 네트워크 인터페이스가 데이터를 제공하는 속도가 CPU보다 (그렇게) 빠르지 않았습니다.

컴퓨터의 기본 구조가 안정화되고 하드웨어 개발자들이 개별 하위시스템 최적화에 집중하면서 상황이 바뀌었습니다. 갑자기 일부 구성요소의 성능이 크게 뒤처지기 시작했고 병목이 생겼습니다. 특히 대용량 저장장치와 메모리 하위시스템은 비용상의 이유로 다른 구성요소에 비해 개선 속도가 느려졌습니다.

대용량 저장장치의 느림은 대부분 소프트웨어 기술로 대응해 왔습니다. 운영체제는 가장 자주 사용되거나 사용할 가능성이 큰 데이터를 주기억장치에 보관하여, 하드디스크보다 수십~수백 배 빠른 속도로 접근합니다. 저장장치 자체에도 캐시가 추가되어 운영체제 변경 없이도 성능을 높일 수 있습니다. {다만, 저장장치 캐시를 사용할 때 데이터 무결성을 보장하려면 변경이 필요합니다.} 본 문서에서는 대용량 저장장치 접근의 소프트웨어 최적화에 대해서는 더 자세히 다루지 않겠습니다.

저장장치 하위시스템과 달리, 주기억장치의 병목을 제거하는 일은 훨씬 어려웠고 거의 모든 해결책이 하드웨어 변경을 요구했습니다. 오늘날 이러한 변경은 주로 다음과 같은 형태로 나타납니다.

  • RAM 하드웨어 설계(속도와 병렬성)
  • 메모리 컨트롤러 설계
  • CPU 캐시
  • 장치의 DMA(Direct Memory Access)

본 문서는 대부분 CPU 캐시와 일부 메모리 컨트롤러 설계의 영향을 다룹니다. 이 주제들을 탐색하는 과정에서 DMA도 함께 큰 그림 속에 위치시킬 것입니다. 하지만 먼저 오늘날 범용 하드웨어의 설계를 개관합니다. 이는 메모리 하위시스템을 효율적으로 사용하는 데 따르는 문제와 제약을 이해하기 위한 전제입니다. 또한 다양한 RAM의 유형을 어느 정도 자세히 살펴보고, 왜 이러한 차이가 여전히 존재하는지 설명할 것입니다.

이 문서는 결코 모든 것을 포괄하는 최종본이 아닙니다. 범용 하드웨어를 대상으로 하며, 그 중에서도 일부에 한정합니다. 또한 많은 주제를 이 글의 목적에 필요한 만큼만 다룹니다. 그와 같은 주제에 대해서는 보다 자세한 문서를 참고하시기 바랍니다.

운영체제별 세부사항과 해결책에 관해서는 오직 리눅스만 다룹니다. 다른 OS에 대한 정보는 전혀 포함하지 않습니다. 필자는 다른 OS의 함의에 대해 논의할 의사가 없습니다. 다른 OS를 사용해야 한다고 생각하는 독자는 해당 벤더에게 이와 유사한 문서를 작성해 달라고 요구해야 합니다.

본격적으로 시작하기 전에 마지막 한 마디. 본문에는 “보통”과 같은 수식어가 여러 번 등장합니다. 여기서 다루는 기술은 현실 세계에서 매우 다양한 변종이 존재하며, 이 글은 가장 흔하고 주류인 버전만을 다룹니다. 이러한 기술에 대해 단정적으로 말할 수 있는 경우는 드뭅니다. 그래서 수식어가 붙습니다.

1.1 문서 구성

이 문서는 주로 소프트웨어 개발자를 위한 것입니다. 하드웨어 지향 독자에게 유용할 만큼 충분한 하드웨어 기술적 세부사항까지는 다루지 않습니다. 하지만 개발자를 위한 실용적 정보를 설명하기 전에 많은 기초 작업이 필요합니다.

이를 위해 2장에서는 RAM(랜덤 액세스 메모리)을 기술적으로 자세히 설명합니다. 이 장의 내용은 알면 좋은 지식이지만 이후 장을 이해하는 데 절대적으로 필수는 아닙니다. 해당 내용이 필요한 곳에는 적절한 역참조를 넣었으니, 성급한 독자는 처음에는 이 장 대부분을 건너뛰어도 좋습니다.

3장에서는 CPU 캐시 동작을 매우 자세히 다룹니다. 글이 너무 건조해지지 않도록 그래프를 사용했습니다. 이 내용은 문서 나머지를 이해하는 데 필수적입니다. 4장에서는 가상 메모리가 어떻게 구현되는지 간략히 설명합니다. 이것 역시 이후를 위한 기초입니다.

5장에서는 NUMA(Non Uniform Memory Access) 시스템을 자세히 다룹니다.

6장은 이 글의 핵심입니다. 앞선 모든 장의 정보를 종합하여, 다양한 상황에서 잘 동작하는 코드를 작성하는 방법을 프로그래머에게 조언합니다. 성급한 독자는 이 장부터 읽고, 필요하다면 앞선 장으로 돌아가 관련 기술을 복습해도 좋습니다.

7장에서는 프로그래머가 더 나은 작업을 하도록 도와줄 도구를 소개합니다. 기술을 완전히 이해하더라도, 비자명한 소프트웨어 프로젝트에서 문제가 어디에 있는지 분명하지 않은 경우가 많습니다. 몇몇 도구는 필수입니다.

8장에서는 가까운 미래에 등장할 기술이나, 있으면 좋을 기술을 전망합니다.

1.2 문제 보고

필자는 이 문서를 당분간 업데이트할 계획입니다. 기술 발전에 따른 업데이트뿐 아니라 오류 수정도 포함합니다. 문제를 보고하려는 독자는 이메일을 보내주시기 바랍니다.

1.3 감사의 말

Johnray Fuller, 그리고 특히 Jonathan Corbet께 감사드립니다. 필자의 영어를 보다 전통적인 형태로 바꾸는 벅찬 작업의 일부를 맡아 주셨습니다. Markus Armbruster는 본문 속 문제점과 누락에 대해 많은 귀중한 의견을 주셨습니다.

1.4 이 문서에 관하여

이 글의 제목은 David Goldberg의 고전 “What Every Computer Scientist Should Know About Floating-Point Arithmetic” [goldberg]에 대한 오마주입니다. Goldberg의 글은 누구나 진지한 프로그래밍을 위해 키보드를 잡기 전에 반드시 읽어야 할 선행 과제임에도 불구하고, 아직 널리 알려져 있지 않습니다.

2 Commodity Hardware Today

범용 하드웨어를 이해하는 것은 중요합니다. 특수 하드웨어가 쇠퇴하고 있기 때문입니다. 요즘 확장은 수직이 아닌 수평으로 이루어지는 경우가 많습니다. 즉, 아주 크고 매우 빠른(그리고 비싼) 시스템 몇 대를 쓰기보다, 더 작고 연결된 범용 컴퓨터 여러 대를 사용하는 것이 비용 효율적입니다. 저렴하고 빠른 네트워크 하드웨어가 널리 보급되었기 때문입니다. 물론 여전히 대형 특수 시스템이 필요한 상황이 있고, 이러한 시스템은 비즈니스 기회가 됩니다. 하지만 전체 시장은 범용 하드웨어 시장에 비하면 미미합니다. 2007년 현재 Red Hat은 앞으로의 제품에서 대부분의 데이터센터가 “표준 구성요소”로 최대 4소켓의 컴퓨터를 사용할 것으로 예상합니다. 각 소켓에는 쿼드코어 CPU가 장착되며, 인텔 CPU의 경우 하이퍼스레딩이 적용됩니다. {하이퍼스레딩은 약간의 추가 하드웨어만으로 하나의 프로세서 코어를 두 개 이상 동시 실행에 사용하도록 합니다.} 이는 데이터센터의 표준 시스템이 최대 64개의 가상 프로세서를 갖게 됨을 의미합니다. 더 큰 머신도 지원되지만, 4소켓·쿼드코어 구성이 현재 최적점으로 여겨지며 대부분의 최적화는 이런 머신을 대상으로 합니다.

범용 컴퓨터의 구조에는 큰 차이가 존재합니다. 그렇다 해도 가장 중요한 차이에 집중하면 90% 이상을 포괄할 수 있습니다. 이러한 기술적 세부사항은 빠르게 변하므로, 독자는 집필 시점을 염두에 두는 것이 좋습니다.

수년간 개인용 컴퓨터와 소형 서버는 노스브리지와 사우스브리지로 구성된 칩셋을 표준으로 삼아 왔습니다. 그림 2.1은 이 구조를 보여줍니다.

Image 1 그림 2.1: 노스브리지와 사우스브리지 구조

모든 CPU(예시에서는 두 개이지만 더 많을 수도 있음)는 공통 버스(FSB, Front Side Bus)를 통해 노스브리지에 연결됩니다. 노스브리지는 메모리 컨트롤러 등을 포함하며, 그 구현은 컴퓨터에서 사용되는 RAM 칩의 종류를 결정합니다. DRAM, Rambus, SDRAM 등 RAM 종류에 따라 서로 다른 메모리 컨트롤러가 필요합니다.

시스템의 다른 모든 장치에 접근하려면 노스브리지가 사우스브리지와 통신해야 합니다. 사우스브리지는 흔히 I/O 브리지라고도 하며, 다양한 버스를 통해 장치와의 통신을 처리합니다. 오늘날에는 PCI, PCI Express, SATA, USB 버스가 가장 중요하며, PATA, IEEE 1394, 시리얼, 패러럴 포트도 사우스브리지가 지원합니다. 예전 시스템에는 노스브리지에 연결된 AGP 슬롯이 있었습니다. 이는 노스브리지와 사우스브리지 간 연결 속도가 충분히 빠르지 않아 생기는 성능 문제 때문이었습니다. 그러나 오늘날 PCI-E 슬롯은 모두 사우스브리지에 연결됩니다.

이러한 시스템 구조는 몇 가지 주목할 만한 결과를 낳습니다.

  • 한 CPU에서 다른 CPU로의 모든 데이터 통신은 노스브리지와의 통신에 사용되는 동일한 버스를 통해 이동해야 합니다.
  • RAM과의 모든 통신은 노스브리지를 통과해야 합니다.
  • RAM은 단일 포트만 가집니다. {이 문서에서는 멀티포트 RAM을 다루지 않습니다. 이 RAM은 범용 하드웨어에서는, 적어도 프로그래머가 접근할 수 있는 곳에서는, 사용되지 않습니다. 최고 속도가 중요한 네트워크 라우터와 같은 특수 하드웨어에서는 볼 수 있습니다.}
  • CPU와 사우스브리지에 연결된 장치 간의 통신은 노스브리지를 경유합니다.

이 설계에서는 몇 가지 병목이 즉시 드러납니다. 그 중 하나는 장치의 RAM 접근입니다. PC 초창기에는 두 브리지의 장치와의 모든 통신이 CPU를 통과해야 했고, 이는 시스템 전체 성능에 부정적 영향을 주었습니다. 이 문제를 해결하기 위해 일부 장치는 DMA(Direct Memory Access)를 지원하게 되었습니다. DMA는 장치가 노스브리지의 도움을 받아 CPU 개입(및 그에 따른 성능 비용) 없이 데이터를 RAM에 직접 저장하거나 RAM에서 직접 읽도록 합니다. 오늘날 어떤 버스에 연결된 고성능 장치든 DMA를 활용할 수 있습니다. 이는 CPU의 작업량을 크게 줄여주지만, DMA 요청이 CPU의 RAM 접근과 대역폭을 경쟁하게 되므로 노스브리지의 대역폭에 대한 경합을 유발합니다. 따라서 이 문제는 반드시 고려해야 합니다.

두 번째 병목은 노스브리지에서 RAM으로 가는 버스입니다. 버스의 세부사항은 사용된 메모리 종류에 따라 달라집니다. 구형 시스템에는 모든 RAM 칩에 하나의 버스만 있어 병렬 접근이 불가능합니다. 최신 RAM은 두 개의 별도 버스(DDR2에서는 채널이라 부름, 그림 2.8 참조)를 요구하여 사용 가능한 대역폭을 두 배로 늘립니다. 노스브리지는 채널 전반에 메모리 접근을 인터리브합니다. 더 최신 메모리 기술(FB-DRAM 등)은 채널을 더 추가합니다.

대역폭이 제한되어 있으므로 지연을 최소화하는 방식으로 메모리 접근을 스케줄링하는 것이 중요합니다. 보시다시피, CPU 캐시를 쓰더라도 프로세서는 훨씬 빠르므로 메모리 접근을 기다려야 합니다. 여러 하이퍼스레드, 코어, 프로세서가 동시에 메모리에 접근하면 대기 시간은 더 길어집니다. 이는 DMA에도 해당됩니다.

메모리 접근에는 동시성만 있는 것이 아닙니다. 접근 패턴 자체도 메모리 하위시스템의 성능에 큰 영향을 미치며, 특히 다중 메모리 채널에서 그러합니다. RAM 접근 패턴에 관한 자세한 내용은 2.2장을 참조하십시오.

좀 더 비싼 시스템에서는 노스브리지에 실제로 메모리 컨트롤러가 포함되지 않기도 합니다. 대신 노스브리지가 여러 외부 메모리 컨트롤러(예: 네 개)에 연결될 수 있습니다.

Image 2 그림 2.2: 외부 컨트롤러를 가진 노스브리지

이 아키텍처의 장점은 하나 이상의 메모리 버스를 가질 수 있어 총 대역폭이 증가한다는 점입니다. 더 많은 메모리를 지원하기도 합니다. 동시에 서로 다른 메모리 뱅크에 접근하면 지연이 줄어듭니다. 그림 2.2처럼 여러 프로세서가 노스브리지에 직접 연결된 경우 특히 그렇습니다. 이러한 설계에서는 내부적으로 노스브리지의 대역폭이 주된 제약인데(인텔의 이 아키텍처에서는) 이 대역폭이 엄청납니다. {완전성을 위해, 이러한 메모리 컨트롤러 배열은 핫플러그 메모리와 결합되어 유용한 “메모리 RAID” 같은 다른 목적으로도 사용할 수 있음을 언급합니다.}

여러 외부 메모리 컨트롤러를 사용하는 것이 메모리 대역폭을 늘리는 유일한 방법은 아닙니다. 점점 더 인기 있는 다른 방법은 메모리 컨트롤러를 CPU에 통합하고 각 CPU에 메모리를 부착하는 것입니다. 이 아키텍처는 AMD Opteron 기반의 SMP 시스템이 대중화했습니다. 그림 2.3은 이러한 시스템을 보여줍니다. 인텔도 Nehalem 프로세서부터 CSI(Common System Interface)를 지원하는데, 이는 기본적으로 동일한 접근입니다. 즉, 통합 메모리 컨트롤러와 각 프로세서의 로컬 메모리입니다.

Image 3 그림 2.3: 통합 메모리 컨트롤러

이러한 아키텍처에서는 프로세서 수만큼의 메모리 뱅크가 존재합니다. 쿼드 CPU 머신에서는 복잡한 노스브리지와 엄청난 대역폭 없이도 메모리 대역폭이 4배가 됩니다. 메모리 컨트롤러를 CPU에 통합하면 추가적인 이점도 있습니다. 여기서는 더 깊이 파고들지는 않겠습니다.

물론 단점도 있습니다. 먼저, 시스템의 모든 메모리를 모든 프로세서가 접근 가능해야 하므로 메모리가 더 이상 균일하지 않습니다(그래서 이런 아키텍처를 NUMA, 비균일 메모리 아키텍처라고 합니다). 로컬 메모리(해당 프로세서에 부착된 메모리)는 보통의 속도로 접근할 수 있습니다. 다른 프로세서에 부착된 메모리에 접근할 때는 상황이 다릅니다. 이 경우 프로세서 간 인터커넥트를 사용해야 합니다. CPU 1에서 CPU 2에 연결된 메모리에 접근하려면 인터커넥트 하나를 거칩니다. 같은 CPU가 CPU 4에 부착된 메모리에 접근하면 인터커넥트를 두 번 건너야 합니다.

각 통신에는 비용이 있습니다. 원격 메모리 접근에 필요한 추가 시간을 설명할 때 “NUMA 계수(NUMA factor)”라고 부릅니다. 그림 2.3의 예시 아키텍처에서 각 CPU에 대해 두 수준이 있습니다. 바로 인접한 CPU들, 그리고 두 번의 인터커넥트를 건너야 하는 CPU 하나입니다. 더 복잡한 머신에서는 수준의 수가 크게 늘 수 있습니다. 또한 IBM x445, SGI Altix 시리즈처럼 연결 유형이 하나 이상인 아키텍처도 있습니다. CPU는 노드로 조직되며, 노드 내부에서는 메모리 접근 시간이 균일하거나 NUMA 계수가 작을 수 있습니다. 그러나 노드 간 연결은 매우 비쌀 수 있고 NUMA 계수가 꽤 높을 수 있습니다.

범용 NUMA 머신은 현재도 존재하며 앞으로 더 큰 역할을 할 것입니다. 2008년 말부터 모든 SMP 머신이 NUMA를 사용할 것으로 예상됩니다. NUMA와 관련된 비용 때문에, 프로그램이 NUMA 머신에서 실행되는지 인지하는 것이 중요합니다. 5장에서 더 많은 머신 아키텍처와, 이를 위한 리눅스 커널 기술을 논의합니다.

이 절의 나머지에서 설명할 기술적 세부사항 외에도 RAM 성능에 영향을 미치는 요소가 더 있습니다. 소프트웨어가 제어할 수 없는 요소이기 때문에 여기서는 다루지 않습니다. 관심 있는 독자는 2.1장에서 일부 요소를 확인할 수 있습니다. 이는 RAM 기술의 보다 완전한 그림을 얻고, 경우에 따라 컴퓨터 구매 시 더 나은 결정을 내리는 데 필요합니다.

다음 두 절에서는 게이트 수준의 하드웨어 세부사항과 메모리 컨트롤러와 DRAM 칩 간의 접근 프로토콜을 다룹니다. 프로그래머들도 이 정보가 유익하다고 느낄 것입니다. 이러한 세부사항이 RAM 접근이 왜 그렇게 동작하는지를 설명해 주기 때문입니다. 하지만 선택적 지식이며, 일상에 더 즉각적으로 관련 있는 주제로 빨리 가고 싶은 독자는 2.2.5절로 건너뛰어도 됩니다.

2.1 RAM 유형

세월이 흐르며 다양한 RAM이 있었고, 서로 꽤 다릅니다. 오래된 유형은 오늘날 역사적 관심사에 가깝습니다. 여기서는 자세히 다루지 않겠습니다. 대신 현대 RAM 유형에 집중하고, 커널이나 애플리케이션 개발자가 성능 특성으로 체감할 수 있는 부분만 일부 표면적으로 살펴보겠습니다.

먼저 흥미로운 질문은 왜 같은 머신 안에 서로 다른 종류의 RAM이 있는가입니다. 구체적으로, 왜 정적 RAM(SRAM {다른 문맥에서는 SRAM이 “synchronous RAM”을 의미하기도 합니다.})과 동적 RAM(DRAM)이 둘 다 존재하는가? 전자는 훨씬 빠르고 기능은 같습니다. 왜 모든 RAM을 SRAM으로 하지 않을까요? 답은 예상대로 비용입니다. SRAM은 DRAM보다 생산과 사용 비용이 훨씬 높습니다. 두 가지 비용 요인이 모두 중요하며, 후자는 점점 더 중요해지고 있습니다. 이러한 차이를 이해하려면 SRAM과 DRAM에서 비트 저장이 어떻게 구현되는지 봐야 합니다.

이 절의 나머지에서는 RAM 구현의 저수준 세부사항을 다룹니다. 가능한 낮은 수준으로 유지하겠습니다. 이를 위해 신호를 하드웨어 설계자가 사용하는 수준이 아닌 “논리 수준”에서 논의합니다. 우리의 목적에는 그 정도의 세부사항이면 충분합니다.

2.1.1 정적 RAM

Image 4 그림 2.4: 6T 정적 RAM

그림 2.4는 6 트랜지스터 SRAM 셀의 구조를 보여줍니다. 셀의 핵심은 두 개의 교차 결합 인버터를 이루는 트랜지스터 M1~M4입니다. 두 개의 안정 상태(각각 0과 1)를 가집니다. Vdd에 전원이 공급되는 한 상태는 안정적입니다.

셀의 상태에 접근하려면 워드 접근선 WL을 올립니다. 그러면 셀의 상태가 즉시 BL과 BL에 읽기용으로 나타납니다. 셀의 상태를 덮어쓰려면 먼저 BL과 BL 라인을 원하는 값으로 설정한 뒤 WL을 올립니다. 외부 드라이버가 네 개의 트랜지스터(M1~M4)보다 강하므로 이전 상태를 덮어쓸 수 있습니다.

자세한 작동 방식은 [sramwiki]를 참고하십시오. 이하 논의를 위해 중요한 점은 다음과 같습니다.

  • 하나의 셀은 여섯 개의 트랜지스터를 필요로 합니다. 네 개 트랜지스터 변형도 있지만 단점이 있습니다.
  • 셀 상태 유지를 위해 지속적인 전력이 필요합니다.
  • 워드 접근선 WL을 올리면 셀 상태는 거의 즉시 읽기 가능해집니다. 다른 트랜지스터 제어 신호처럼 신호는 직사각형(두 이진 상태 사이를 빠르게 전환)입니다.
  • 셀 상태는 안정적이며 리프레시 주기가 필요 없습니다.

더 느리고 전력 소모가 적은 SRAM 형태도 있지만, 여기서는 관심사가 아닙니다. 우리는 빠른 RAM을 다루기 때문입니다. 이러한 느린 변형은 DRAM보다 인터페이스가 단순하여 시스템에서 더 쉽게 사용할 수 있다는 점에서 주로 흥미롭습니다.

2.1.2 동적 RAM

동적 RAM은 구조적으로 정적 RAM보다 훨씬 단순합니다. 그림 2.5는 일반적인 DRAM 셀 설계를 보여줍니다. 트랜지스터 하나와 커패시터 하나로 구성됩니다. 이 엄청난 복잡도 차이는 기능 면에서도 큰 차이를 의미합니다.

Image 5 그림 2.5: 1T 동적 RAM

DRAM 셀은 커패시터 C에 상태를 저장합니다. 트랜지스터 M은 상태 접근을 보호하는 데 사용됩니다. 셀의 상태를 읽으려면 접근선 AL을 올립니다. 그러면 커패시터의 전하량에 따라 데이터선 DL에 전류가 흐르거나 흐르지 않습니다. 셀에 쓰려면 데이터선 DL을 적절히 설정한 뒤 AL을 충분한 시간 동안 올려 커패시터를 충전하거나 방전시킵니다.

DRAM 설계에는 여러 가지 복잡성이 있습니다. 커패시터를 사용하기 때문에, 셀을 읽으면 커패시터가 방전됩니다. 이 과정을 무한히 반복할 수 없으며, 어느 시점에는 커패시터를 다시 충전해야 합니다. 더 나쁜 점은 엄청난 수의 셀을 수용하기 위해(오늘날 10^9 셀 이상의 칩이 흔함) 커패시터의 용량을 낮춰야 한다는 것입니다(펨토패럿 범위나 그 이하). 완전히 충전된 커패시터는 수만 개의 전자를 담습니다. 커패시터의 저항이 매우 높다 하더라도(수 테라옴), 전하가 소실되는 데 오래 걸리지 않습니다. 이 문제를 “리키지(leakage, 누설)”라고 합니다.

이 누설 때문에 DRAM 셀은 지속적으로 리프레시되어야 합니다. 오늘날 대부분의 DRAM 칩은 64ms마다 리프레시해야 합니다. 리프레시하는 동안에는 메모리에 접근할 수 없습니다. 어떤 워크로드에서는 이 오버헤드가 메모리 접근의 최대 50%까지 정지시키기도 합니다([highperfdram] 참조).

두 번째 문제는 아주 작은 전하량에서 비롯됩니다. 셀에서 읽어낸 정보가 직접 사용 가능하지 않다는 것입니다. 데이터선은 전 범위의 전하 상태에서 저장된 0과 1을 구분할 수 있는 센스 앰프에 연결되어야 합니다.

세 번째 문제는 커패시터의 충방전이 즉시 일어나지 않는다는 것입니다. 센스 앰프가 감지할 수 있는 전류가 즉시 나오지 않습니다. 그림 2.6은 충전과 방전 곡선을 보여줍니다. X축은 RC(저항×용량) 단위로 표시되며, 시간의 단위입니다.

Image 6: [Formulas]

이는 커패시터가 충전·방전되는 데 시간이 걸림을 의미합니다(용량 C와 저항 R이 결정). 또한 센스 앰프가 감지할 수 있는 전류가 즉시 이용 가능하지 않음을 의미합니다. 그림 2.6은 충전과 방전 타이밍을 보여줍니다.

Image 7 그림 2.6: 커패시터 충·방전 타이밍

정적 RAM에서는 워드 접근선을 올리는 즉시 출력이 가능하지만, DRAM에서는 커패시터가 충분히 방전될 때까지 항상 약간의 시간이 필요합니다. 이 지연은 DRAM의 속도를 심각하게 제한합니다.

하지만 단순한 접근에는 장점도 있습니다. 가장 큰 장점은 크기입니다. DRAM 셀 하나에 필요한 칩 면적은 SRAM 셀보다 훨씬 작습니다. SRAM 셀은 상태 유지를 위한 트랜지스터마다 전력이 필요합니다. DRAM 셀 구조는 더 단순하고 규칙적이어서 다이에 빽빽하게 집적하기 쉽습니다.

결국 비용(상당히 극적인 차이)이 승리합니다. 특수 하드웨어—예: 네트워크 라우터—를 제외하면, 우리는 DRAM 기반의 주기억장치를 사용할 수밖에 없습니다. 이는 프로그래머에게 큰 함의를 가지며, 나머지 글에서 논의하겠습니다. 다만 그 전에 DRAM 셀의 실제 사용에 관한 몇 가지 세부사항을 살펴봅니다.

2.1.3 DRAM 접근

프로그램은 가상 주소를 사용하여 메모리 위치를 선택합니다. 프로세서는 이를 물리 주소로 변환하고, 마지막으로 메모리 컨트롤러가 해당 주소에 대응하는 RAM 칩을 선택합니다. RAM 칩의 개별 메모리 셀을 선택하려면 물리 주소의 일부가 여러 주소선 형태로 전달됩니다.

메모리 컨트롤러에서 각 메모리 위치마다 개별적으로 주소를 내보내는 것은 비현실적입니다. 예컨대 4GB RAM에는 2^32개의 주소선이 필요합니다. 대신 주소는 더 적은 주소선을 사용하는 이진수로 인코딩되어 DRAM 칩에 전달됩니다. 이렇게 DRAM 칩으로 전달된 주소는 먼저 디멀티플렉서에서 역다중화해야 합니다. 주소선이 N개인 디멀티플렉서는 2^N개의 출력선을 가집니다. 이 출력선으로 메모리 셀을 선택할 수 있습니다. 이 직접 접근은 용량이 작은 칩에서는 큰 문제가 되지 않습니다.

하지만 셀 수가 증가하면 더 이상 적합하지 않습니다. 용량이 1Gbit {SI 접두어가 정말 싫습니다. 제게 기가비트는 언제나 2^30이지 10^9가 아닙니다.}인 칩에는 30개의 주소선과 2^30개의 선택선이 필요합니다. 속도를 포기하지 않으려면 디멀티플렉서의 크기는 입력선 수에 대해 지수적으로 증가합니다. 30개 주소선에 대한 디멀티플렉서는 칩 면적을 많이 차지할 뿐 아니라, 디멀티플렉서 자체의 복잡성(크기와 시간)도 큽니다. 더 중요하게도, 30개의 펄스를 주소선에 동기적으로 전송하는 것은 “고작” 15개의 펄스를 전송하는 것보다 훨씬 어렵습니다. 정확히 같은 길이나 적절한 타이밍으로 배선해야 할 선의 수가 줄어들기 때문입니다. {DDR3 같은 최신 DRAM은 타이밍을 자동 조정할 수 있지만 허용 한계가 있습니다.}

Image 8 그림 2.7: 동적 RAM 개략도

그림 2.7은 매우 높은 수준에서 본 DRAM 칩입니다. DRAM 셀은 행과 열로 구성됩니다. 모두를 한 줄로 정렬할 수도 있지만, 그 경우 DRAM 칩에는 거대한 디멀티플렉서가 필요합니다. 배열 방식에서는 절반 크기의 디멀티플렉서와 멀티플렉서 하나씩으로 충분합니다. {멀티플렉서와 디멀티플렉서는 동치이며, 쓰기 시에는 멀티플렉서가 디멀티플렉서처럼 동작해야 합니다. 이후로는 구분을 생략합니다.} 이는 모든 면에서 큰 절감입니다. 예시에서 주소선 a0과 a1은 행 주소 선택(RAS) 디멀티플렉서를 통해 전체 행의 셀을 선택합니다. 읽기 시, 그 행의 모든 셀 내용이 열 주소 선택(CAS) {이름 위의 선은 신호가 부정(negated)됨을 의미합니다} 멀티플렉서에 제공됩니다. 그 다음 주소선 a2와 a3에 따라 한 열의 내용이 DRAM 칩의 데이터 핀에 제공됩니다. 이는 데이터 버스 폭에 해당하는 총 비트 수를 만들기 위해 여러 DRAM 칩에서 병렬로 수행됩니다.

쓰기의 경우, 새로운 셀 값을 데이터 버스에 올려두고, RAS와 CAS로 셀을 선택하면 셀에 저장됩니다. 꽤 직선적인 설계입니다. 물론 실제로는 더 많은 복잡성이 있습니다. 신호 후 데이터를 읽기 위해 데이터 버스에 언제 데이터가 나타나는지 지연 규격이 필요합니다. 앞 절에서 설명했듯 커패시터는 즉시 방전되지 않습니다. 셀로부터의 신호는 너무 약해 증폭이 필요합니다. 쓰기 시에는 새로운 값을 셀에 성공적으로 저장하려면 RAS와 CAS 이후 데이터가 버스에 얼마나 오래 있어야 하는지도 규정해야 합니다(역시 커패시터는 즉시 충·방전되지 않습니다). 이러한 타이밍 상수는 DRAM 칩 성능에 결정적입니다. 다음 절에서 다룹니다.

두 번째 확장성 문제는 30개의 주소선을 모든 RAM 칩에 연결하는 것이 현실적이지 않다는 점입니다. 칩의 핀은 소중한 자원입니다. 데이터는 가능한 한 병렬로(예: 64비트 단위로) 전송해야 한다는 것만으로도 “나쁩니다.” 메모리 컨트롤러는 각 RAM 모듈(RAM 칩 묶음)에 주소를 지정할 수 있어야 합니다. 성능 이유로 여러 RAM 모듈에 병렬 접근이 필요하고, 각 RAM 모듈이 30개 이상의 주소선을 별도로 필요로 한다면, 8개의 RAM 모듈에 대해 메모리 컨트롤러는 주소 처리만으로도 무려 240개 이상의 핀이 필요합니다.

이러한 확장성 문제를 해결하기 위해 DRAM 칩은 오래전부터 주소 자체를 다중화(multiplex)해 왔습니다. 즉, 주소를 두 부분으로 나눠 전송합니다. 첫 번째 부분(그림 2.7에서는 a0, a1)이 행을 선택합니다. 이 선택은 취소될 때까지 유지됩니다. 다음으로 두 번째 부분(a2, a3)이 열을 선택합니다. 중요한 차이는 외부 주소선이 두 개만 필요하다는 것입니다. RAS와 CAS 신호가 언제 제공되는지 표시하는 선이 몇 개 더 필요하지만, 주소선 수를 절반으로 줄이는 데 비하면 대가가 작습니다. 다만, 주소 다중화는 또 다른 문제를 낳습니다. 이는 2.2장에서 논의합니다.

2.1.4 결론

이 절의 세부사항이 다소 벅차게 느껴져도 걱정하지 마십시오. 핵심은 다음과 같습니다.

  • 모든 메모리를 SRAM으로 하지 않는 이유가 있다.
  • 메모리 셀은 사용하려면 개별적으로 선택되어야 한다.
  • 주소선 수는 메모리 컨트롤러, 메인보드, DRAM 모듈, DRAM 칩의 비용과 직결된다.
  • 읽기/쓰기 결과가 사용 가능해지기까지 시간이 걸린다.

다음 절에서는 DRAM 메모리에 접근하는 실제 과정의 세부사항을 더 알아봅니다. 보통 직접 주소 지정되는 SRAM 접근의 세부사항은 더 다루지 않습니다. 속도와, SRAM 용량이 제한적이기 때문입니다. SRAM은 현재 CPU 캐시와 다이 내부에서 사용되며, 연결이 작고 CPU 설계자의 완전한 통제 하에 있습니다. CPU 캐시는 나중에 다룰 주제지만, 여기서 필요한 내용은 SRAM 셀에는 최대 속도가 있고, 이는 SRAM에 들이는 노력에 따라 달라진다는 점입니다. 속도는 CPU 코어보다 약간 느린 것부터 한두 자릿수(배) 느린 것까지 다양합니다.

2.2 DRAM 접근 기술 세부사항

DRAM 소개 절에서, 자원 절약을 위해 DRAM 칩이 주소를 다중화한다는 것을 보았습니다. 또한 DRAM 셀의 커패시터가 안정적 신호를 만들기 위해 즉시 방전하지 않으므로 접근에 시간이 걸리며, DRAM 셀은 리프레시가 필요함도 보았습니다. 이제 이 모든 것을 종합해, 이러한 요인들이 DRAM 접근 방식을 어떻게 결정하는지 살펴봅니다.

현재 기술에 집중하겠습니다. 비동기 DRAM과 그 변형은 더 이상 관련성이 낮으므로 다루지 않습니다. 관심 있는 독자는 [highperfdram], [arstechtwo]를 참고하십시오. RDRAM(Rambus DRAM)도 기술적으로는 폐기되지 않았지만, 시스템 메모리로 널리 쓰이지 않으므로 다루지 않겠습니다. 여기서는 SDRAM(Synchronous DRAM)과 그 후속인 DDR(Double Data Rate DRAM)만을 다룹니다.

이름에서 알 수 있듯, SDRAM은 시간 소스에 동기적으로 동작합니다. 메모리 컨트롤러는 클럭을 제공하며, 그 주파수가 FSB(Front Side Bus, DRAM 칩이 사용하는 메모리 컨트롤러 인터페이스)의 속도를 결정합니다. 이 글을 쓰는 시점에 800MHz, 1,066MHz, 심지어 1,333MHz까지 가능하며, 다음 세대에서는 더 높은 주파수(1,600MHz)가 예고되어 있습니다. 이는 버스에서 실제로 사용하는 주파수가 그만큼 높다는 뜻은 아닙니다. 오늘날 버스는 더블/쿼드 펌프드로, 한 사이클에 데이터를 두 번 또는 네 번 전송합니다. 더 큰 숫자가 잘 팔리므로, 제조사는 쿼드 펌프드 200MHz 버스를 “유효” 800MHz 버스로 홍보하길 좋아합니다.

오늘날 SDRAM에서 각 데이터 전송은 64비트—8바이트—입니다. 따라서 FSB의 전송률은 8바이트 × 유효 버스 주파수(쿼드 펌프드 200MHz 버스의 경우 6.4GB/s)입니다. 많아 보이지만, 이는 버스트 속도, 즉 결코 초과할 수 없는 최대 속도입니다. 이제 보겠지만 RAM 모듈과의 통신 프로토콜에는 데이터 전송이 불가능한 유휴 시간이 많습니다. 최적의 성능을 얻으려면 바로 이 유휴 시간을 이해하고 최소화해야 합니다.

2.2.1 읽기 접근 프로토콜

Image 9 그림 2.8: SDRAM 읽기 접근 타이밍

그림 2.8은 DRAM 모듈의 일부 커넥터에서 벌어지는 활동을, 세 가지 색상 영역으로 보여줍니다. 늘 그렇듯 시간은 왼쪽에서 오른쪽으로 흐릅니다. 많은 세부사항은 생략했습니다. 여기서는 버스 클럭, RAS/CAS 신호, 주소/데이터 버스만 다룹니다. 읽기 사이클은 메모리 컨트롤러가 주소 버스에 행 주소를 제공하고 RAS 신호를 내리는 것으로 시작합니다. 모든 신호는 클럭(CLK)의 상승 에지에서 샘플링되므로, 읽는 시점에 안정적이기만 하면 신호가 완전한 직사각형일 필요는 없습니다. 행 주소를 설정하면 RAM 칩은 해당 행을 래치하기 시작합니다.

CAS 신호는 tRCD(RAS-to-CAS Delay) 클럭 사이클 후에 보낼 수 있습니다. 그 다음 열 주소를 주소 버스에 제공하고 CAS 라인을 내립니다. 이로써 주소의 두 부분(대략 반반, 다른 방식은 별 의미가 없음)을 동일한 주소 버스로 전송할 수 있음을 알 수 있습니다.

이제 주소 지정이 완료되었고 데이터를 전송할 수 있습니다. RAM 칩은 이를 준비하는 데 시간이 필요합니다. 이 지연을 보통 CAS 레이턴시(CL)라고 부릅니다. 그림 2.8에서 CAS 레이턴시는 2입니다. 이는 메모리 컨트롤러, 메인보드, DRAM 모듈의 품질에 따라 더 크거나 작을 수 있습니다. 레이턴시는 절반 단위도 가능합니다. CL=2.5라면 파란 영역의 첫 하강 에지에서 첫 데이터가 제공됩니다.

여기까지 데이터를 얻기 위한 준비가 이루어졌는데, 단 한 워드만 전송하는 것은 낭비입니다. 그래서 DRAM 모듈은 메모리 컨트롤러가 전송할 데이터의 양을 지정할 수 있게 합니다. 보통 2, 4, 8 워드 중에서 선택합니다. 이렇게 하면 새로운 RAS/CAS 시퀀스 없이도 캐시의 전체 라인을 채울 수 있습니다. 또한 메모리 컨트롤러가 행 선택을 초기화하지 않고 새로운 CAS 신호를 보낼 수도 있습니다. 이 방식으로 연속적인 메모리 주소를 읽고 쓰면 RAS 신호를 다시 보낼 필요가 없고 행을 비활성화할 필요도 없으므로(아래 참조) 훨씬 빠릅니다. 행을 “열어두는(open)”지는 메모리 컨트롤러가 결정합니다. 항상 추측으로 열어두는 것은 실제 애플리케이션에서 단점이 있습니다([highperfdram] 참조). 새로운 CAS 신호를 보내는 것은 RAM 모듈의 커맨드 레이트(보통 Tx로 표시, x는 1 또는 2와 같은 값; 고성능 DRAM 모듈은 매 사이클 새 명령을 수용하는 T1)를 따릅니다.

이 예시에서 SDRAM은 사이클당 한 워드를 내보냅니다. 1세대가 그렇습니다. DDR은 사이클당 두 워드를 전송할 수 있습니다. 전송 시간은 줄지만 레이턴시는 변하지 않습니다. 원칙적으로 DDR2도 동일하지만 실제 모습은 다릅니다. 여기서 세부사항은 필요 없습니다. DDR2는 더 빠르고 더 저렴하며 더 신뢰할 수 있고 에너지 효율적일 수 있음을 알아두면 충분합니다([ddrtwo] 참조).

2.2.2 프리차지와 활성화

그림 2.8은 전체 사이클을 다 보여주지 않습니다. DRAM 접근의 일부만을 보여줍니다. 새 RAS 신호를 보내기 전에 현재 래치된 행을 비활성화하고 새 행을 프리차지(준비 충전)해야 합니다. 여기서는 명시적 명령으로 이를 수행하는 경우에 집중하겠습니다. 특정 상황에서 이 추가 단계를 피하게 해주는 프로토콜 개선도 있습니다. 하지만 프리차지로 인해 생기는 지연은 여전히 영향을 줍니다.

Image 10 그림 2.9: SDRAM 프리차지와 활성화

그림 2.9는 하나의 CAS 신호에서 다른 행을 위한 CAS 신호까지의 활동을 보여줍니다. 첫 CAS 신호로 요청한 데이터는 이전과 같이 CL 사이클 후에 제공됩니다. 예시에서는 두 워드를 요청했으며, 단순 SDRAM에서는 이를 전송하는 데 두 사이클이 걸립니다. 또는 DDR 칩에서 네 워드를 상상해도 됩니다.

커맨드 레이트가 1인 DRAM 모듈에서도 프리차지 명령을 즉시 발행할 수는 없습니다. 데이터를 전송하는 데 걸리는 시간만큼 기다려야 합니다. 여기서는 두 사이클입니다. 이는 CL과 우연히 같지만, 단지 우연일 뿐입니다. 프리차지 신호에는 전용 라인이 없습니다. 대신 일부 구현에서는 WE(Write Enable)와 RAS 라인을 동시에 내리는 방식으로 발행합니다. 이 조합은 그 자체로 유용한 의미가 없습니다(인코딩 세부사항은 [micronddr] 참조).

프리차지 명령을 발행하고 나면, 행을 선택할 수 있기까지 tRP(Row Precharge time) 사이클이 필요합니다. 그림 2.9에서 그 시간의 많은 부분(보라색)이 메모리 전송(연한 파란색)과 겹칩니다. 좋은 일입니다! 하지만 tRP가 전송 시간보다 길어, 다음 RAS 신호가 한 사이클 지연됩니다.

타임라인을 계속하면, 다음 데이터 전송은 이전 전송이 끝난 뒤 5사이클 후에 일어남을 알게 됩니다. 즉 데이터 버스는 7사이클 중 2사이클만 사용됩니다. 이것을 FSB 속도로 곱하면, 800MHz 버스의 이론적 6.4GB/s는 1.8GB/s가 됩니다. 매우 좋지 않으며 피해야 합니다. 6장에서 설명할 기술은 이 수치를 끌어올리는 데 도움이 됩니다. 하지만 보통은 프로그래머의 몫도 필요합니다.

SDRAM 모듈에는 아직 논의하지 않은 타이밍 값이 하나 더 있습니다. 그림 2.9에서 프리차지 명령은 데이터 전송 시간에 의해서만 제약받았습니다. 또 다른 제약은, SDRAM 모듈이 RAS 신호 후 다른 행을 프리차지하기까지 시간이 필요하다는 것입니다(tRAS로 표시). 이 값은 보통 꽤 높아서 tRP의 두세 배 정도입니다. 이는 RAS 신호 이후 CAS 신호 하나만 따라오고 데이터 전송이 몇 사이클 만에 끝나는 경우 문제입니다. 그림 2.9에서 초기 CAS 신호 직전에 RAS 신호가 있었고 tRAS가 8사이클이라고 가정합시다. 그러면 tRCD + CL + tRP(전송 시간보다 길기 때문에)의 합이 7사이클에 불과하므로, 프리차지 명령을 한 사이클 더 지연해야 합니다.

DDR 모듈은 종종 특수 표기 w-x-y-z-T로 설명됩니다. 예: 2-3-2-8-T1. 이는 다음을 의미합니다.

w 2 CAS 레이턴시(CL) x 3 RAS-to-CAS 지연(t RCD) y 2 RAS 프리차지(t RP) z 8 활성화에서 프리차지까지 지연(t RAS) T T1 커맨드 레이트

명령 발행과 처리에 영향을 미치는 타이밍 상수는 더 많습니다. 하지만 실제로는 이 다섯 상수만으로 모듈의 성능을 가늠하기에 충분합니다.

사용 중인 컴퓨터의 이러한 정보를 알아두면 특정 측정을 해석하는 데 유용할 때가 있습니다. 컴퓨터를 구매할 때도 FSB와 SDRAM 모듈 속도와 함께 컴퓨터 속도를 결정하는 가장 중요한 요소 중 하나이므로, 이 세부사항을 알아두는 것이 확실히 도움이 됩니다.

모험심이 강한 독자는 시스템을 조정해 볼 수도 있습니다. 때로는 BIOS에서 이러한 값 일부 또는 전부를 변경할 수 있습니다. SDRAM 모듈에는 이러한 값을 설정할 수 있는 프로그래머블 레지스터가 있습니다. 보통 BIOS는 최적의 기본값을 선택합니다. RAM 모듈의 품질이 높다면, 컴퓨터 안정성에 영향을 주지 않고 레이턴시를 조금 낮출 수도 있습니다. 인터넷의 수많은 오버클러킹 웹사이트에 관련 문서가 널려 있습니다. 하지만 모든 위험은 본인 책임이며, 경고하지 않았다고 말하지 마십시오.

2.2.3 리차징(재충전)

DRAM 접근에서 대체로 간과되는 주제가 리차징입니다. 2.1.2절에서 설명했듯, DRAM 셀은 지속적으로 리프레시되어야 합니다. 이는 시스템의 나머지 부분에 완전히 투명하게 일어나진 않습니다. 어떤 행이 {[highperfdram] 등 문헌과 달리, [micronddr]에 따르면} 리프레시되는 동안에는 접근이 불가능합니다. [highperfdram] 연구는 “놀랍게도, DRAM 리프레시 조직은 성능에 극적으로 영향을 줄 수 있다”고 발견했습니다.

JEDEC 규격에 따르면 각 DRAM 셀은 64ms마다 리프레시되어야 합니다. DRAM 어레이에 8,192개의 행이 있다면, 메모리 컨트롤러는 평균적으로 7.8125µs마다 리프레시 명령을 발행해야 합니다(리프레시 명령은 큐잉될 수 있으므로, 실제로는 두 요청 사이의 최대 간격이 더 길 수 있습니다). 리프레시 명령 스케줄링은 메모리 컨트롤러의 책임입니다. DRAM 모듈은 마지막으로 리프레시한 행의 주소를 추적하고, 각 새 요청마다 주소 카운터를 자동으로 증가시킵니다.

프로그래머가 리프레시 시점과 명령 발행을 제어할 수 있는 부분은 사실상 거의 없습니다. 하지만 측정을 해석할 때 DRAM 수명 주기의 이 부분을 염두에 두는 것이 중요합니다. 중요한 워드를 가져와야 하는데 그 행이 마침 리프레시 중이라면, 프로세서는 꽤 오랜 시간 정지될 수 있습니다. 각 리프레시에 걸리는 시간은 DRAM 모듈에 따라 다릅니다.

2.2.4 메모리 유형

현재 사용 중이거나 곧 사용될 메모리 유형에 시간을 할애할 가치가 있습니다. SDR(Single Data Rate) SDRAM부터 시작하겠습니다. DDR(Double Data Rate) SDRAM의 기초이기 때문입니다. SDR은 꽤 단순합니다. 메모리 셀과 데이터 전송률이 동일했습니다.

Image 11 그림 2.10: SDR SDRAM 동작

그림 2.10에서 DRAM 셀 어레이는 메모리 버스가 데이터를 전송할 수 있는 것과 같은 속도로 메모리 내용을 출력할 수 있습니다. DRAM 셀 어레이가 100MHz에서 동작하면, 버스의 데이터 전송률은 100Mb/s입니다. 모든 구성요소의 주파수 f는 동일합니다. DRAM 칩의 처리량을 늘리는 것은 비용이 큽니다. 에너지 소비가 주파수와 함께 증가하기 때문입니다. 어레이 셀이 엄청난 수이므로 이는 금전적으로도 불가능합니다. {전력 = 동적 용량 × 전압^2 × 주파수.} 실제로는 더 문제인데, 주파수를 올리면 보통 시스템 안정성을 유지하기 위해 전압도 올려야 하기 때문입니다. DDR SDRAM(사후에 DDR1이라고 부름)은 관련 주파수를 하나도 올리지 않고 처리량을 개선했습니다.

Image 12 그림 2.11: DDR1 SDRAM 동작

SDR과 DDR1의 차이는 그림 2.11에서 볼 수 있듯이, 이름에서 예상할 수 있듯이, 사이클당 데이터 전송량이 두 배라는 점입니다. 즉 DDR1 칩은 상승 하강 에지에서 데이터를 전송합니다. 이를 “더블 펌프드” 버스라고 부르기도 합니다. 셀 어레이의 주파수를 올리지 않고 이를 가능하게 하려면 버퍼가 필요합니다. 이 버퍼는 데이터 라인당 2비트를 가집니다. 이는 그림 2.7의 셀 어레이에서 데이터 버스가 두 라인으로 구성되어야 함을 의미합니다. 구현은 간단합니다. 동일한 열 주소를 두 DRAM 셀에 사용해 병렬로 접근하면 됩니다. 셀 어레이에 필요한 변경도 최소입니다.

SDR DRAM은 단순히 주파수(예: 100MHz SDR의 경우 PC100)로 알려졌습니다. DDR1 DRAM을 더 좋아 보이게 만들기 위해 마케터들은 새로운 명명법이 필요했습니다. 주파수는 변하지 않았기 때문입니다. 그래서 DDR 모듈(64비트 버스)의 바이트 단위 전송률을 이름에 담았습니다.

100MHz × 64bit × 2 = 1,600MB/s

따라서 주파수 100MHz인 DDR 모듈은 PC1600이라고 부릅니다. 1600 > 100이니, 모든 마케팅 요건이 충족됩니다. 개선은 사실 고작 두 배인데도 훨씬 좋아 보입니다. {두 배 개선은 달게 받겠지만, 부풀려진 숫자를 좋아할 필요는 없습니다.}

Image 13 그림 2.12: DDR2 SDRAM 동작

더 많은 성능을 끌어내기 위해 DDR2는 약간의 혁신을 더합니다. 그림 2.12에서 볼 수 있는 가장 눈에 띄는 변화는 버스 주파수를 두 배로 높인 것입니다. 주파수를 두 배로 하면 대역폭도 두 배가 됩니다. 그러나 셀 어레이에 대해 이 주파수 배증은 경제적이지 않으므로, I/O 버퍼가 각 클럭 사이클마다 4비트를 받아 버스로 내보내야 합니다. 따라서 DDR2 모듈의 변경은 DIMM의 I/O 버퍼만 더 높은 속도로 동작하도록 만드는 데 있습니다. 이는 분명 가능하며, 모듈 전체가 아니라 아주 작은 구성요소일 뿐이라 에너지도 눈에 띄게 더 들지 않습니다. 마케터들이 DDR2에 붙인 이름은 DDR1과 비슷하지만, 값 계산에서 두 배 요소가 네 배로 바뀝니다(이제 버스가 쿼드 펌프드이므로). 그림 2.13은 현재 사용 중인 모듈 이름을 보여줍니다.

Array Freq.Bus Freq.Data RateName (Rate)Name (FSB)
133MHz266MHz4,256MB/sPC2-4200DDR2-533
166MHz333MHz5,312MB/sPC2-5300DDR2-667
200MHz400MHz6,400MB/sPC2-6400DDR2-800
250MHz500MHz8,000MB/sPC2-8000DDR2-1000
266MHz533MHz8,512MB/sPC2-8500DDR2-1066

그림 2.13: DDR2 모듈 명칭

명명법에 한 가지 꼬임이 더 있습니다. CPU, 메인보드, DRAM 모듈에서 사용하는 FSB 속도는 유효 주파수로 표기합니다. 즉, 클럭 사이클의 양 에지에서의 전송을 감안하여 숫자가 부풀려집니다. 그러므로 어레이 133MHz, 버스 266MHz인 모듈은 FSB “주파수”가 533MHz입니다.

DDR3(그래픽 카드에서 쓰는 가짜 GDDR3가 아니라 진짜 DDR3)의 규격은 DDR2로의 전환과 비슷한 방향의 더 많은 변화를 예고합니다. 전압이 DDR2의 1.8V에서 DDR3의 1.5V로 낮아집니다. 전력 소비는 전압의 제곱에 비례하므로, 이 변화만으로도 30% 개선입니다. 여기에 다이 크기 축소와 기타 전기적 진전을 더하면, DDR3는 같은 주파수에서 전력 소비를 절반으로 줄일 수 있습니다. 또는 더 높은 주파수에서 동일한 전력 한도를 맞출 수 있습니다. 혹은 용량을 두 배로 하면서도 발열을 동일하게 유지할 수 있습니다.

DDR3 모듈의 셀 어레이는 외부 버스 속도의 1/4로 동작하며, 이에 따라 I/O 버퍼는 DDR2의 4비트에서 8비트를 요구합니다. 개략도는 그림 2.14를 보십시오.

Image 14 그림 2.14: DDR3 SDRAM 동작

초기 DDR3 모듈은 DDR2 기술이 더 성숙했기 때문에 약간 더 높은 CAS 레이턴시를 가질 가능성이 큽니다. 이로 인해 DDR3는 DDR2로 달성 가능한 주파수보다 높은 주파수에서만 유용하며, 그마저도 레이턴시보다는 대역폭이 중요한 경우에 주로 도움이 됩니다. 이미 DDR2와 동일한 CAS 레이턴시를 달성할 수 있는 1.3V 모듈에 대한 얘기도 나옵니다. 어쨌든 더 빠른 버스 덕분에 더 높은 속도를 달성할 가능성이 레이턴시 증가를 상쇄할 것입니다.

DDR3의 잠재적 문제 중 하나는 전송률이 1,600Mb/s 이상이면 채널당 모듈 수가 겨우 하나로 줄어들 수 있다는 점입니다. 규격 초기 버전에서는 모든 주파수에 대해 이 요구사항이 있었기 때문에, 언젠가 모든 주파수에 대해 이 요구가 철회되길 바랄 수밖에 없습니다. 그렇지 않으면 시스템의 용량이 심각하게 제한됩니다.

그림 2.15는 예상되는 DDR3 모듈 명칭을 보여줍니다. JEDEC은 현재까지 처음 네 가지 유형에 합의했습니다. 인텔의 45nm 프로세서가 1,600Mb/s FSB 속도를 가지므로, 오버클러킹 시장을 위해 1,866Mb/s도 필요합니다. DDR3 수명의 말기에 더 많은 유형을 보게 될 것입니다.

Array Freq.Bus Freq.Data RateName (Rate)Name (FSB)
100MHz400MHz6,400MB/sPC3-6400DDR3-800
133MHz533MHz8,512MB/sPC3-8500DDR3-1066
166MHz667MHz10,667MB/sPC3-10667DDR3-1333
200MHz800MHz12,800MB/sPC3-12800DDR3-1600
233MHz933MHz14,933MB/sPC3-14900DDR3-1866

그림 2.15: DDR3 모듈 명칭

모든 DDR 메모리에는 한 가지 문제가 있습니다. 버스 주파수가 증가하면 병렬 데이터 버스를 만들기 어렵습니다. DDR2 모듈에는 240개의 핀이 있습니다. 데이터 및 주소 핀으로 가는 모든 연결은 대략 같은 길이가 되도록 라우팅해야 합니다. 더 큰 문제는, 같은 버스에 두 개 이상의 DDR 모듈을 데이지 체인으로 연결하면 모듈이 하나 추가될 때마다 신호가 점점 더 왜곡된다는 점입니다. DDR2 규격은 버스(채널)당 모듈을 두 개까지만 허용하며, DDR3 규격은 높은 주파수에서는 하나만 허용합니다. 채널당 240핀이라면 단일 노스브리지가 합리적으로 구동할 수 있는 채널은 둘을 넘기 어렵습니다. 대안은 외부 메모리 컨트롤러(그림 2.2처럼)를 쓰는 것이지만 비용이 큽니다.

이는 범용 메인보드가 최대 네 개의 DDR2 또는 DDR3 모듈만 장착할 수 있도록 제한됨을 의미합니다. 이 제한은 시스템이 가질 수 있는 메모리 양을 심각하게 제한합니다. 오래된 32비트 IA-32 프로세서조차 64GB RAM을 처리할 수 있고, 가정용에서도 메모리 수요가 증가하고 있으므로, 무언가 조치가 필요합니다.

한 가지 답은 2장에서 설명했듯 각 프로세서에 메모리 컨트롤러를 넣는 것입니다. AMD는 Opteron 라인에서 그렇고, 인텔은 CSI 기술로 그렇게 할 것입니다. 이는 한 프로세서가 사용하기에 합리적인 양의 메모리를 단일 프로세서에 연결할 수 있는 한 도움이 됩니다. 어떤 상황에서는 그렇지 않으며, 이 설정은 NUMA 아키텍처와 그 부정적 영향을 초래합니다. 다른 상황에서는 또 다른 해법이 필요합니다.

앞으로 몇 년간 대형 서버 머신을 위한 인텔의 답은 FB-DRAM(Fully Buffered DRAM)입니다. FB-DRAM 모듈은 오늘날 DDR2 모듈과 동일한 구성품을 사용하므로 생산 비용이 상대적으로 저렴합니다. 차이는 메모리 컨트롤러와의 연결입니다. 병렬 데이터 버스 대신 FB-DRAM은 직렬 버스를 사용합니다(RDRAM도 예전에 그랬고, PATA의 후속이 SATA인 것처럼, PCI/AGP의 후속이 PCI Express입니다). 직렬 버스는 훨씬 높은 주파수로 구동할 수 있어, 직렬화의 부정적 영향을 상쇄하고 심지어 대역폭을 증가시킵니다. 직렬 버스를 사용하면 다음과 같은 주요 효과가 있습니다.

  1. 채널당 더 많은 모듈을 사용할 수 있다.
  2. 노스브리지/메모리 컨트롤러당 더 많은 채널을 사용할 수 있다.
  3. 직렬 버스는 전이중(두 개의 라인)으로 설계될 수 있다.

FB-DRAM 모듈은 DDR2의 240개와 비교해 핀이 69개뿐입니다. FB-DRAM 모듈을 데이지 체인으로 연결하는 것은 훨씬 쉽습니다. 버스의 전기적 효과를 훨씬 더 잘 처리할 수 있기 때문입니다. FB-DRAM 규격은 채널당 최대 8개의 DRAM 모듈을 허용합니다.

듀얼 채널 노스브리지의 연결 요구와 비교하면, 이제 더 적은 핀으로 FB-DRAM 6개 채널을 구동할 수 있습니다. 2×240핀 대 6×69핀입니다. 각 채널의 라우팅이 훨씬 단순해져 메인보드 비용 절감에도 도움이 될 수 있습니다.

완전 이중 병렬 버스는 전통 DRAM 모듈에는 비용이 지나치게 많이 듭니다. 모든 라인을 복제하는 것은 너무 비쌉니다. 반면 직렬 라인(비록 FB-DRAM이 요구하는 차동 신호라 하더라도)에서는 그렇지 않아서, 직렬 버스는 전이중으로 설계됩니다. 상황에 따라 이 사실만으로도 이론적으로 대역폭이 두 배가 됩니다. 하지만 대역폭 증가를 위한 병렬성은 이뿐만이 아닙니다. FB-DRAM 컨트롤러는 최대 6개 채널을 동시에 구동할 수 있으므로, RAM 용량이 적은 시스템에서도 FB-DRAM을 사용하면 대역폭을 높일 수 있습니다. DDR2 시스템이 모듈 4개에서 채널 2개라면, 동일한 용량을 보통의 FB-DRAM 컨트롤러로 채널 4개를 통해 처리할 수 있습니다. 직렬 버스의 실제 대역폭은 FB-DRAM 모듈에 사용된 DDR2(혹은 DDR3) 칩의 종류에 따라 달라집니다.

장점을 요약하면 다음과 같습니다.

DDR2 FB-DRAM


핀 수 240 69 채널 수 2 6 채널당 DIMM 2 8 최대 메모리 16GB 192GB 처리량 ~10GB/s ~40GB/s

한 채널에 여러 DIMM을 사용할 경우 FB-DRAM에는 몇 가지 단점도 있습니다. 체인상의 각 DIMM에서 신호에 아주 조금씩 지연이 추가되므로 레이턴시가 증가합니다. 하지만 동일한 용량과 동일한 주파수라면, 채널당 DIMM을 하나만 쓰면 되므로 FB-DRAM은 언제나 DDR2와 DDR3보다 더 빠를 수 있습니다. 대규모 메모리 시스템에서는 범용 부품만으로 DDR 방식에 해답이 없습니다.

2.2.5 결론

이 절은 DRAM 접근이 임의로 빠른 과정이 아님을 보여주었을 것입니다. 적어도 프로세서가 동작하는 속도와 레지스터/캐시에 접근하는 속도와 비교하면 그렇습니다. CPU와 메모리 주파수의 차이를 염두에 두는 것이 중요합니다. 2.933GHz로 동작하는 Intel Core 2 프로세서와 1.066GHz FSB는 클럭 비가 11:1입니다(참고: 1.066GHz 버스는 쿼드 펌프드). 메모리 버스에서 한 사이클 정지는 프로세서에 11사이클 정지를 의미합니다. 대부분의 머신은 실제 DRAM이 더 느리므로 지연은 더 늘어납니다. 다음 절에서 정지(stall)에 대해 논할 때 이 숫자를 기억해 두십시오.

읽기 명령의 타이밍 차트는 DRAM 모듈이 높은 지속 전송률을 제공할 수 있음을 보여줍니다. 전체 DRAM 행을 단 한 번의 정지 없이 전송할 수 있습니다. 데이터 버스를 100% 점유할 수 있습니다. DDR 모듈에서는 사이클마다 64비트 워드 두 개가 전송됩니다. DDR2-800 모듈과 두 채널이라면 초당 12.8GB의 속도입니다.

하지만 DRAM 접근은 설계하지 않는 한 항상 순차적이지 않습니다. 불연속적인 메모리 영역을 사용하면 프리차지와 새로운 RAS 신호가 필요합니다. 이때 속도가 느려지고 DRAM 모듈이 도움이 필요해집니다. 가능한 한 빨리 프리차지가 이뤄지고 RAS 신호가 보내질수록, 해당 행을 실제로 사용할 때 패널티가 작아집니다.

하드웨어 및 소프트웨어 프리패칭(6.3절 참조)을 사용해 타이밍의 오버랩을 늘리고 정지를 줄일 수 있습니다. 프리패칭은 또한 메모리 연산의 시간을 이동시켜, 데이터가 실제로 필요해지기 직전에 경합을 줄여줍니다. 이는 한 라운드에서 생성된 데이터를 저장하고 다음 라운드에 필요한 데이터를 읽어야 할 때 자주 발생하는 문제입니다. 읽기를 시간상 앞당기면, 쓰기와 읽기 명령을 거의 동시에 발행하지 않아도 됩니다.

2.3 다른 주기억장치 사용자들

CPU 외에도 주기억장치에 접근할 수 있는 시스템 구성요소가 있습니다. 네트워크/대용량 저장장치 컨트롤러 같은 고성능 카드는 필요한 모든 데이터를 CPU를 통해 주고받을 여유가 없습니다. 대신 메인 메모리에서 직접 읽고/메인 메모리에 직접 씁니다(DMA, Direct Memory Access). 그림 2.1에서 카드가 사우스브리지와 노스브리지를 통해 메모리와 직접 통신할 수 있음을 볼 수 있습니다. USB 같은 다른 버스도 DMA를 사용하지 않더라도 FSB 대역폭을 필요로 합니다. 사우스브리지가 역시 FSB를 통해 노스브리지에 연결되어 있기 때문입니다.

DMA는 분명 이롭지만, FSB 대역폭에 대한 경쟁이 커진다는 의미입니다. DMA 트래픽이 많은 시기에는 CPU가 주기억장치에서 데이터를 기다리며 평소보다 더 자주 정지될 수 있습니다. 적절한 하드웨어가 있다면 이를 피하는 방법이 있습니다. 그림 2.3 같은 아키텍처에서는, 연산이 DMA의 영향을 받지 않는 노드의 메모리를 사용하도록 할 수 있습니다. 각 노드에 사우스브리지를 부착해 모든 노드의 FSB에 부하를 고르게 분산할 수도 있습니다. 수많은 가능성이 있습니다. 6장에서 소프트웨어로 가능한 개선을 달성하는 데 도움이 되는 기법과 프로그래밍 인터페이스를 소개합니다.

마지막으로, 일부 저가 시스템은 별도의 전용 비디오 RAM 없이 그래픽 시스템을 탑재합니다. 이들 시스템은 주기억장치의 일부를 비디오 RAM으로 사용합니다. 비디오 RAM에의 접근은 빈번합니다(예: 1024×768, 16bpp, 60Hz 디스플레이는 94MB/s). 그리고 시스템 메모리는 그래픽 카드의 RAM과 달리 듀얼 포트가 아니므로, 시스템 성능 특히 레이턴시에 상당한 영향을 줄 수 있습니다. 성능이 우선이라면 이런 시스템은 무시하는 것이 최선입니다. 가치보다 문제가 큽니다. 이런 머신을 사는 사람은 최고의 성능을 기대하지 않는다는 사실을 알고 있습니다.

계속 읽기:

  • 2부 (CPU 캐시)
  • 3부 (가상 메모리)
  • 4부 (NUMA 시스템)
  • 5부 (프로그래머가 할 수 있는 것 - 캐시 최적화)
  • 6부 (프로그래머가 할 수 있는 것 - 멀티스레드 최적화)
  • 7부 (메모리 성능 도구)
  • 8부 (향후 기술)
  • 9부 (부록과 참고문헌)
이 글의 색인 항목
GuestArticles