같은 아키텍처의 CPU라도 모델에 따라 지원 인스트럭션 셋이나 세부 기능이 다르다. /proc/cpuinfo 출력 결과의 “flags” 행에서 지원 기능들을 볼 수 있는데 커널 소스의 다음 파일에 대응하는 항목들이 있다.

linux/arch/x86/include/asm/cpufeatures.h:

...
/* Intel-defined CPU features, CPUID level 0x00000001 (EDX), word 0 */
#define X86_FEATURE_FPU                 ( 0*32+ 0) /* Onboard FPU */
#define X86_FEATURE_VME                 ( 0*32+ 1) /* Virtual Mode Extensions */
...
#define X86_FEATURE_CLFLUSH             ( 0*32+19) /* CLFLUSH instruction */
...
#define X86_FEATURE_CAT_L3              ( 7*32+ 4) /* Cache Allocation Technology L3 */
#define X86_FEATURE_CAT_L2              ( 7*32+ 5) /* Cache Allocation Technology L2 */
#define X86_FEATURE_CDP_L3              ( 7*32+ 6) /* Code and Data Prioritization L3 */
...
#define X86_FEATURE_CDP_L2              ( 7*32+15) /* Code and Data Prioritization L2 */

#define X86_FEATURE_MBA                 ( 7*32+18) /* Memory Bandwidth Allocation */
...
#define X86_FEATURE_CQM                 ( 9*32+12) /* Cache QoS Monitoring */
...

/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (EDX), word 11 */
#define X86_FEATURE_CQM_LLC             (11*32+ 1) /* LLC QoS if 1 */

/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (EDX), word 12 */
#define X86_FEATURE_CQM_OCCUP_LLC       (12*32+ 0) /* LLC occupancy monitoring */
#define X86_FEATURE_CQM_MBM_TOTAL       (12*32+ 1) /* LLC Total MBM monitoring */
#define X86_FEATURE_CQM_MBM_LOCAL       (12*32+ 2) /* LLC Local MBM monitoring */

...
#define X86_BUG_CPU_MELTDOWN            X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */
#define X86_BUG_SPECTRE_V1              X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */
#define X86_BUG_SPECTRE_V2              X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */
...

시작은 FPU인데 부동소수점 코프로세서가 따로 있는 걸 마지막으로 본 게 언제인지 가물가물하다. 마지막은 여진이 이어지고 있는 멜트다운과 스펙터. 그런데 중간에 QoS 어쩌고 하는 게 있다. 막 인스트럭션들을 큐에 집어넣어서 넘치는 건 버리고 그러는 걸까?

두문자어가 난무하는데, 일단 LLC는 Last Level Cache이고 MBM은 Memory Bandwidth Monitoring이다. LLC는 보통 L3 캐시일 텐데, 핵심은 여러 코어가 공유하는 캐시라는 점이다. 한편 CQM(Cache QoS Monitoring)의 최신 이름은 CMT(Cache Monitoring Technology)다. 등장인물을 요약하면 다음과 같다.

뭘 \ 어떻게 모니터링 제어
캐시 공간 CMT CAT (CDP)
메모리 대역폭 MBM MBA

(메모리 대역폭은 LLC와 그 하위 계층 저장소(메인 메모리) 사이 통신에 대한 것이다. 결국 캐시 얘기다.)

이 모두를 포괄하는 이름이 RDT(Resource Director Technology)다. 이를 그대로 공유 자원 사용 방식을 지정하는 기술이다. 최근 수년 안에 나온 제온들에서 지원하며 모델에 따라 지원하는 세부 기능이 다르다. (하드웨어 지원 표 참고.)

목표는 여러 프로세스가 도는 구성에서 중요한 프로세스의 성능을 최적화하는 것이다. 최적 성능을 얻는 데 장애가 될 수 있는 요소로 여러 가지가 있을 텐데, RDT에서 다루는 곳은 LLC 근방이다. 스케줄링 알고리즘은 커녕 프로세스라는 개념조차 거의 닿지 않는 영역이고, 그래서 다양한 우선도의 프로세스들(VM 포함)이 공유 자원을 두고 무차별적으로 경쟁한다. 거기에 얼마간 질서를 주려는 시도이다.

예를 들어 워킹 세트가 LLC 크기보다 큰 낮은 우선도의 프로세스가 이웃 코어에서 돌면 높은 우선도의 프로세스가 캐시 미스 때문에 성능이 뚝뚝 떨어질 수 있다. 또 수다스런 프로세스가 끊임없이 메모리 접근을 하고 있으면 버스를 공유하는 다른 프로세스의 메모리 접근에 지연이 생긴다. CPU 친연성을 지정해 프로세스들을 격리할 수 있겠지만 항상 가능한 게 아니고, 덜 중요한 프로세스가 sched_yield() 하듯 자발적으로 CLFLUSH 인스트럭션으로 캐시를 정리하고 메모리 접근을 알아서(…) 늦추는 건 잠깐 생각해 봐도 현실적인 해법이 아니다. 다중 프로세스 환경에서 운영 체제에 의한 선점형 스케줄링이 일반적 해법이듯 여기서도 기반 계층에서 우선도 정책을 강제하는 게 답일 수 있다.

개별 프로세스 내지 그룹, 개별 논리 프로세서(스레드) 내지 그룹을 대상으로 할 수 있다. 모니터링 내지 제어 정책 데이터를 저장하는 테이블이 따로 있고, 정해진 레지스터에 그 테이블 인덱스 역할을 하는 ID를 기록하면 해당 항목에 따라 모니터링 내지 제어를 하는 식이다. ID를 저장해 두고 가만 있으면 논리 프로세서 단위로 기능을 적용하는 것이고 문맥 전환 때마다 ID를 요래조래 바꿔 주면 프로세스 단위로 적용하는 식이다. 쓸 수 있는 ID 개수는 기능 및 CPU 모델마다 다른데, 보통 4개에서 16개까지다.

각 기능을 하나씩 보자면,

  • CMT (Cache Monitoring Technology): 현재 LLC 점유 크기를 측정하는 기능이다.

  • CAT (Cache Allocation Technology): 사용할 수 있는 LLC 영역을 제한하는 기능이다. LLC 공간을 몇 개에서 몇십 개로 (N-way 캐시면 최대 N개까지) 나누고, “여기부터 저기까지만 사용”이라고 지정할 수 있다. CDP(Code and Data Prioritization)는 확장 기능이다. 코드와 데이터에 따로 구간을 지정할 수 있다. CDP 소개 글의 그림을 보면 이해가 쉽다. 어떻게 코드와 데이터를 구별할까? 모르겠다.

  • MBM (Memory Bandwidth Monitoring): LLC의 다음 계층 저장소, 즉 메인 메모리로 보내는 접근 요청들의 크기를 측정한다. 로컬 메모리 (in NUMA) 접근을 따로 측정할 수도 있다.

  • MBA (Memory Bandwidth Allocation): 메모리 접근 속도를 제한하는 기능이다. 사용자 인터페이스에서 주로 백분율로 설정하는데, 내부에서는 메모리 접근 요청에 일부러 지연을 주는 식으로 동작한다. 즉 메모리 버스 대역폭이 아니라 가능한 최대 성능에 대한 (선형적으로 비례하지는 않는) 백분율이라고 생각하면 된다.

이쯤에서 RDT 소개 글의 그림을 보면 도움이 된다.

CAT는 최소 보장이 아니라 최대 제한 방식으로 동작한다. 그래서 잘못 구성하면 도리어 성능을 떨어뜨릴 수도 있다. 그리고 MBA는 netem과 좀 비슷하게 동작한다. 이래저래 네트워크 트래픽 제어와 비슷한 면이 있으니 이름에 QoS를 썼던 것도 이해가 간다.

인텔에서 RDT 기능을 위한 유틸리티들을 제공한다. (사용 예시 참고.) 여러 리눅스 배포판에 패키지가 올라가 있다. 또 리눅스에서 제공하는 resctrl 타입 가상 파일 시스템을 통해 RDT 기능을 제어할 수도 있다. (인텔 문서도 참고.)

그래서 성능 최적화 효과가 얼마나 있는지 한번 확인해 보려 했는데… 노트북에도 있는 제온이 곤궁한 내 PC엔 달려 있지 않으니 슬픈 일이다, 흑.