Memory Model – (1)

3가지 메모리 모델

리눅스는 FLATMEM, DISCONTIGMEM 및 SPARSEMEM의 3가지 모델을 제공하며 아키텍처 머신들은 이 중 하나 이상을 지원하며 커널 빌드 시 지원되는 메모리 모델 중 하나를 선택하여 빌드한다.

mm-1b

 

메모리 모델별 특징

FLATMEM

  • 설치된 메모리 뱅크들의 주소가 연속된다.
  • UMA에서만 사용

 

DISCONTIGMEM

  • 설치된 메모리 뱅크들의 간격이 발생된다. 홀(hole) 발생 가능.
  • UMA 및 NUMA에서 사용 가능
  • ARM은 2010년 이 옵션을 삭제하였다.

 

SPARSEMEM

  • 설치된 메모리 뱅크들의 간격이 발생된다. 홀(hole) 발생 가능.
  • DISCONTIGMEM 보다 성능이 떨어질 수 있지만 hotplug memory 기능이 지원된다.
    • 그러나 특정 아키텍처에 구현된 SPARSEMEM_VMEMMAP을 사용하는 경우 DISCONTIGMEM 보다 더 빠르고 FLATMEM에 필적하는 성능을 보여 64비트 시스템에서는 점점 Sparsemem으로 이전하고 있음.
    • 참고: x86_64: Make sparsemem/vmemmap the default memory model
  • 섹션 단위로 online/offline(hotplug memory) 관리가 되며 사이즈는 수십MB~수G로 아키텍처별로 다르다.
  • UMA에서 사용하는 경우
    • ARM의 경우 SA1100(xscale 아키텍처), ARCH-RPC 및 일부 ARM 머신(RealView-PBX)에서 두 개의 메모리 뱅크가 떨어져 있어서 default로 메모리 모델로 사용한다.
    • 또한 메인스트림에 적용된 코드는 아니지만 ARM에서 MULTI_PLATFORM 커널 옵션을 사용하는 경우에도 사용할 수 있도록 패치가 준비되어 있다.

 

ARM with NUMA

  • arm 및 arm64 모두 현재 커널에서는 지원되지 않는다.
  • 2012년 RFC 패치에 arm에서 NUMA를 지원하였었고, linaro 커널도 arm에서 NUMA를 지원하지만 절대적인 필요성이 없어서인지 메인스트림에는 포함되지 않고 있다.
  • 2014년 패치에 NUMA를 지원하는 arm64가 나왔다.
mm-2a

메모리 모델 주요 커널 옵션

mm-4

메모리 모델 부가 커널 옵션

mm-5
  • NEED_MULTIPLE_NODES
    • DISCONTIGMEM 메모리 모델을 사용하거나 NUMA 시스템인 경우 사용할 수 있다.
    • NODE_DATA() 매크로를 사용하여 각 노드의 mem_map을 가리킬 수 있게 한다.
    • 전역 node_data[] 배열을 사용하여 노드별로 mem_map에 접근한다.
  •  FLAT_NODE_MEM_MAP
    • FLATMEM 또는 DISCONTIGMEM 메모리 모델에서 사용할 수 있다.
    • 노드 정보를 기술해 놓은 pglist_data 구조체의 멤버 변수 node_mem_map을 통해 mem_map에 접근한다.
  • HAVE_MEMORY_PRESENT
    • SPARSEMEM 메모리 모델을 위해 요청한 범위에 hole이 발생할 수 있으므로 각 섹션 별로 메모리 존재 여부를 관리할 수 있도록 한다.
  • SPARSEMEM_EXTREME
    • mem_section[] 배열을 dynamic 하게 할당 받아 사용하려고 할 때 사용
    • 주로 생성해야 할 섹션 수가 많은 시스템에서 사용한다.
  • SPARSEMEM_STATIC
    • 컴파일 시 static하게 할당해둔 mem_section[]을 사용한다.
    • 주로 생성해야 할 섹션 수가 적은 시스템에서 사용한다.
  • SPARSEMEM_VMEMMAP
    • vmemmap을 사용하여 빠르게 pfn과 page descriptor 주소를 변환할 수 있다.
    • vmalloc 주소 범위가 큰 64비트 시스템에서 사용한다.
  • MEMORY_HOTREMOVE
    • 메모리를 시스템 동작 중에 제거할 수 있다.
    • MEMORY_HOTPLUG, ARCH_ENABLE_MEMORY_HOTREMOVE, MIGRATION 옵션이 있을 때 선택할 수 있다.
  • MOVABLE_NODE
    • ◦X86_64 누마 시스템에서만 사용가능하며 메모리 단편화 지원을 위해 사용한다.
    • 한 노드를 movable 메모리로만 사용할 수 있게 할당할 수 있다.
    • HAVE_MEMBLOCK, NO_BOOTMEM 커널 옵션과 같이 사용된다.
  • MEMORY_HOTPLUG_SPARSE
    • SPARSEMEM && MEMORY_HOTPLUG에서 선택할 수 있다.
  • NO_BOOTMEM
    • 기존 커널에서 사용하였던 BOOTMEM early 메모리 할당자를 사용하지 않는다.
    • ARM은 기본적으로 BOOTMEM을 사용하지 않고 memblock으로 대체되었다. 대부분의 아키텍처에서도 점점 사용하지 않는 추세이다.
  • HAVE_MEMBLOCK
    • memblock early 메모리 할당자를 사용한다.
    • ARM은 기본적으로 사용하고 대부분의 아키텍처도 BOOTMEM 대신 early 메모리 할당자로 사용한다.
  • HIGHMEM
    • 32bit에서 커널에 미리 1:1 매핑되지 않아 커널이 직접 access를 해야 할 때마다 매핑하여 사용해야 하는 메모리 범위이다.
    • 32bit 시스템에서 시스템 메모리가 커널 공간보다 큰 경우 HIGHMEM 옵션을 사용하여 더 많은 메모리를 활용할 수 있게 한다.
  • HIGHPTE
    • 32bit 시스템에서 2차 PTE를 highmem에 할당한다.
    • 32bit 시스템에 수 기가 이상의 메모리를 사용하는 경우 2차 PTE를 highmem에 로드하게 하여 lowmem 메모리를 소모하지 않게 유도한다.
  • NODE_NOT_IN_PAGE_FLAGS
    • page 구조체의 flags 멤버변수에 노드 번호를 기록하지 못하는 경우 노드 번호를 별도로 섹션에 대해 1:1로 매핑하여 저장한다
    • 32비트 시스템에서 비트 자리가 부족하여 노드 번호를 기록하지 못하는 경우 사용

메모리 모델과 페이지 관리맵(mem_map)

전체 물리 메모리의 페이지 프레임 만큼 page 구조체 배열이 mem_map이라하는데 다음과 같이 각 메모리 모델별로 mem_map을 관리한다.
  • FLATMEM
    • *mem_map 포인터가 page[] 구조체 배열을 가리킨다.
    • 노드가 하나 이므로 전역 구조체 contig_page_data를 사용하는데 이 구조체의 멤버 변수 node_mem_map 역시 page[] 구조체 배열을 가리킨다.
  • DISCONTIGMEM
    • 노드가 두 개 이상이므로 node_data[] 배열을 사용하는데 이 구조체의 멤버 변수 node_mem_map은 각 노드와 관련된 page[] 구조체 배열을 가리킨다.
  • SPARSEMEM
    • 두 가지 방법을 사용한다.
      • SPARSEMEM_STATIC
        • 섹션 수 만큼 mem_section[] 배열을 컴파일 타임에 정적 메모리에 두고 각 섹션 엔트리의 멤버 변수 section_mem_map이 해당 섹션 크기 만큼의 페이지를 관리하는 page[] 구조체 배열을 가리킨다.
      • SPARSEMEM_EXTREAM
        • 섹션 수 만큼 *mem_section[] 포인터 배열을 정적 메모리에 두고 실제 각 mem_section[] 배열은 커널 초기화를 진행할 때 mem_section[] 배열을 dynamic하게 할당받아 메모리를 사용하고 mem_section[]의 사용은 SPARSEMEM_STATIC과 같다.
mm-3b

참고

 

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.