Post

PCID

Context Switching 퍼포먼스 개선

PCID

요약

구분PCID/ASID 도입 이전도입 이후
컨텍스트 스위칭 시 TLB전체 무효화(flush)현재 프로세스의 PCID만 구분해 유지
프로세스 재개 직후TLB miss 폭증, page walk 반복이전에 캐싱된 자신의 매핑 재사용 가능
A → B → A 빠른 전환각 전환마다 무효화되어 이득 없음A의 매핑이 남아 있으면 즉시 히트 가능
대표적 활용 사례-KPTI/KVA Shadow(Meltdown 대응) 성능 손실 상쇄

이전에는 프로세스 컨텍스트 스위칭을 수행할 때, TLB에 있는 데이터가 무효화되는 것으로 알고 있었습니다. 하지만, 2010년도부터 PCID(Process-Context Identifier, 또는 ASID)가 도입되면서, 부분적으로 해결하고 퍼포먼스를 향상시킬 수 있었다고 합니다. 오늘은 이에 대해서 정리해보려고 합니다.

TLB (Translation Lookaside Buffer, 변환 색인 버퍼)

가상 주소를 물리 주소로 변환하려면 원래 페이지 테이블을 여러 단계(x86-64 기준 4단계)에 걸쳐 순회해야 합니다. 이 과정을 Page Walk라고 부르며, 메모리 접근이 여러번 필요하기 때문에 상대적으로 느립니다.

TLB는 이 변환 결과를 캐싱해두는 메모리로, CPU 코어 내부에 MMU에 위치합니다. TLB에서 매핑을 찾으면 이를 TLB Hit라고 하고, Page Walk 없이 즉시 물리 주소를 얻을 수 있는 것입니다. 반대로 TLB Miss가 발생하면 Page Walk를 다시 수행해야 합니다.

PCID 이전

PCID가 없던 시절 TLB 엔트리에는 이 매핑이 어느 프로세스의 것인지 구분하는 정보가 없었습니다. 각 프로세스는 독립된 가상 주소를 가졌기 때문입니다. 덕분에 서로 다른 프로세스가 동일한 가상 주소를 사용함에도 전혀 다른 물리 주소를 매핑해서 사용할 수 있었습니다. 그러나, 그 가상 주소가 어떤 프로세스의 것인지는 확인할 수 있는 방법이 없었습니다. 따라서, 다른 프로세스의 물리 주소가 매핑되있는 참조할 수 있는 사고가 발생하는 것을 막기 위해 캐시 무효화(flush)가 강제되었습니다.

여기서 flush는 TLB 엔트리를 회로에서 물리적으로 지우는 것이 아니라, 각 엔트리의 valid bit를 0으로 끄는 것에 가깝습니다.

이 때문에 프로세스 A → B → A처럼 아주 짧은 시간 안에 다시 원래 프로세스로 돌아오더라도, 그 사이 TLB가 통째로 플러시되었다면 A의 매핑은 다시 무효화된 상태이므로 재사용할 수 없고 처음부터 page walk를 다시 수행해야 했습니다.

PCID 이후

이 문제를 해결하기 위해 TLB 엔트리에 “이 매핑이 어느 프로세스의 주소 공간에 속하는지”를 나타내는 태그를 추가했습니다. 이를 PCID(Intel 명칭) 또는 ASID(AMD 및 일반 명칭, Address Space Identifier)라고 합니다.

Intel SDM은 PCID를 하나의 논리 프로세서가 여러 선형 주소 공간에 대한 정보를 동시에 캐싱할 수 있게 해주는 기능으로 정의합니다.

1
2
PCID 없는 TLB 엔트리:  [Valid] [가상주소] → [물리주소] [권한]
PCID 있는 TLB 엔트리:  [Valid] [PCID] [가상주소] → [물리주소] [권한]

https://www.felixcloutier.com/x86/invpcid

덕분에 같은 가상 주소라도 PCID가 다르면 서로 다른 엔트리로 취급할 수 있게 되었고, TLB에 동시에 공존할 수 있게 됐습니다. 컨텍스트 스위칭이 일어나도 TLB를 비울 필요 없이, 그저 조회 시 현재 프로세스의 PCID와 일치하는 엔트리만 사용하면 되는 것이죠.

MOV to CR3 명령어의 동작도 이에 맞춰 정의되어 있습니다. CR4.PCIDE = 1이고 소스 오퍼랜드의 63번 비트가 0이면, 해당 명령어는 오퍼랜드에 지정된 PCID와 연관된 TLB 엔트리만 무효화하며 글로벌 페이지에 대한 엔트리는 그대로 유지합니다. 즉, PCID가 활성화된 상태에서는 CR3를 교체해도 다른 PCID에 속한 엔트리는 그대로 살아남습니다.

단점?

PCID가 추가되면서, 컨텍스트 스위칭 퍼포먼스는 개선되었지만, 엔트리 크기와 복잡도가 증가할 것이고, 이에 따른 트레이드오프가 발생할 것입니다. 이는 다음과 같습니다.

  • TLB 용량 경쟁 및 유효 용량 감소 (TLB Pollution)
    • TLB 하드웨어 엔트리 개수는 물리적으로 제한(수십~수천 개)
    • 여러 프로세스의 주소 변환 엔트리가 동시에 머물기 때문에, 서로 다른 프로세스들이 한정된 TLB 캐시 라인을 두고 밀어내기(Eviction) 경쟁을 벌여 단일 프로세스 관점에서는 오히려 캐시 미스(Miss)가 증가할 수 있음
  • 운영체제 커널의 복잡도 및 동기화 오버헤드 증가
    • 식별자 고갈 관리: 하드웨어 PCID는 12비트($0 \sim 4095$)로 최대 4,096개까지만 지원함
    • 시스템 내 스레드나 프로세스 수가 이를 초과하면 OS 커널이 LRU 등의 알고리즘으로 PCID 재할당 및 엔트리 무효화 로직을 직접 관리해야 함
    • 멀티코어 TLB 슛다운(Shootdown) 비용 증가: 특정 프로세스의 메모리 매핑이 해제(Unmap)될 때, 다른 코어에 남아있는 해당 프로세스의 엔트리를 찾아서 정밀하게 날려주기 위한 처리 로직이 훨씬 복잡해짐
  • INVPCID 명령어 자체의 지연 시간(Latency)
    • INVPCID: TLB와 페이징 구조 캐시를 정밀 탐색해 무효화하는 직렬화 성격의 무거운 마이크로코드 명령어
    • 프로세스 생성/종료가 빈번하거나 메모리 매핑 변경이 잦은 환경에서는 단순 MOV CR3로 한 번에 날리는 것보다 개별 무효화 비용이 더 커질 수 있음
This post is licensed under CC BY 4.0 by the author.