본문 바로가기

Research Log/Tracing

The PMCs of EC2: Measuring IPC

... as with the increasing scale of processors and speed of storage devices, the common bottleneck is moving from disks to the memory subsystem. CPU caches, the MMU, memory busses, and CPU interconnects. These can only be analyzed with PMCs.

PMC Usage

PMC는 Counting, Sampling 두개의 방법으로 사용될 수 있다.

  • Counting: 발생하는 개수를 집계
  • Sampling: 이벤트의 개수를 기반으로 인터럽트를 발생시킴 (Interrupt는 stack trace, PC(Program Counter) sampling 등을 위해 사용됨)

Sampling의 오버헤드는 인터럽트를 발생시키는 threshold와 이어지는 동작에 따라 변할 수는 있지만, counting의 오버헤드보다는 크다.

Measuring IPC

Instruction-per-cycle(IPC)는 자동차의 연비(miles-per-gallon: how much bang for your buck)처럼 CPU의 성능 평가를 하기 위해 사용된다. 하지만 자동차의 연비가 자동차 고유의 성능 뿐만 아니라 오르막길을 오르는 등 주행 경로의 영향을 받는 것처럼, IPC는 spin lock contention의 개수가 많으면 높은 것처럼 보이는 오해가 생길 수 있다. (Spin lock contention은 매우 적은 cycle을 소모함)

아래는 일련의 NOP(no op) instruction을 반복하는 프로그램을 _perf_를 통해 측정한 결과이다.

실험이 진행된 프로세서는 4-wide (instruction prefetch/decode width)이기 때문에, 매 CPU cycle 마다 최대 4 개의 instruction을 수행할 수 있다.
NOP는 아무런 동작도 하지 않으므로 가장 빠른 instruction 이다, 그러므로 실험에서 IPC rate는 4에 근접하게 나온다.

<not supported>로 명시된 메트릭의 경우 실험한 프로세서에서는 지원하지 않는 메트릭이라는 의미이다.

Interpreting IPC

  • IPC < 1: Stall cycle bound, memory bound 일 가능성이 있음. Stall cylce은 CPU가 메모리 I/O를 기다리고 있기 때문에 task의 progress는 진행되고 있지 않다는 의미임. 이 경우 메모리 사용량을 조정하는 것을 고려해야함. (더 적은 object를 할당, zero copy를 사용, NUMA를 보고 memtory placement 정책을 수정) CPU flame graph는 이러한 stall cycle들이 발생하는 동안 CPU에서 실행되고 있는 코드를 보여주며 메모리 사용량이 많은 곳을 찾아내는 단서가 됨.
  • IPC > 1: instruction bound 일 가능성이 있음. Instruction 을 조정해야함. CPU flame graph는 CPU에서 instruction이 수행되고 있는 코드를 보여주며 실행되는 코드를 줄일 곳을 알려주는 단서가 됨.

CPI flame graph를 통해서 IPC와 flame graph의 특징을 한눈에 볼 수 있다. CPI flame graph를 그리기 위해서 PMC를 sampling 모드로 사용하여 stack trace를 파악해야 한다. 하지만 이러한 방식에도 단점은 있다. (다른 글에 설명한다고 함)

Note: There was a problem on older kernels (3.x) where PMCs would be measured incorrectly, leading to a bogus IPC measurement.

RxNetty Study

클라이언트가 주는 부하가 증가함에 따라 발생하는 RxNetty와 Tomcat 간의 성능 차이를 이해하는 데는 PMC가 중요하다는 것을 발견했다. Tomcat은 각 연결에 대한 스레드를 사용하여 요청을 처리하는 반면 RxNetty는 event loop thread를 사용한다. Tomcat에서는 request 당 CPU cycle 사용량이 크게 변경되지 않은 반면 RxNetty는 클라이언트가 증가함에 따라 더 효율적으로 동작하며 더 적은 CPU cycle을 소비했다. 클라이언트에서 주는 부하(x축)가 증가함에 따라 rxnetty(주황), tomcat(빨강)선을 각각 보면 CPU에서의 시간(ms)가 점차 줄어드는 것을 확인알 수 있다. 이러한 이유가 짐작이 되는가?

위의 그림은 해당 연구를 정리해둔 WSPerfLab repository에서 만들어졌으며 slides 25-27에서 설명된 적이 있다. RxNetty가 46% 정도의 더 높은 request rate을 얻을 수 있었기 때문에 그 이유를 식별하고 정량화하기 위한 연구를 시작했다. 5%는 X에 의해, 3%는 Y로 인해 발생하였다... 등등 몇 주간의 연구 끝에 많은 것을 밝혔지만, 46% 중 10% 이상이 설명되지 않은 채로 남아 있었다.

I checked and rechecked our numbers, but fell short every time. It was driving me nuts, and casting doubt on everything we'd found so far. - ㅠㅠ

하지만 PMC를 사용하여 46%의 차이를 세분화하여 모든 포인트를 설명할 수 있었다. CPU 차이점을 이해하는 것은 우리 업계에서 반드시 필요한 작업이며 PMC가 없으면 항상 퍼즐의 중요한 부분을 놓치게 된다. 이 연구는 수십 개의 PMC를 측정하고 연구한 EC2가 아닌 물리적 시스템에서 수행되었지만 분석에 필요했던 중요한 PMC는 현재 EC2에서 사용할 수 있는 아키텍처의 PMC로 가능한 IPC 및 LLC의 측정값이었기 때문에 현재 EC2에서 제공하는 PMC들로도 충분히 성능을 분석할 수 있다.

How is this even possible in the cloud?

클라우드의 guest가 어떻게 PMC를 읽을 수 있게 하기 위해서 다음과 같은 작업이 필요했다. PMC는 설정을 위한 RDMSR, WRMSR 그리고 읽기를 위한 RDPMC와 같은 privileged instruction를 통해 관리된다.

Hypervisor에서 처리되는 guest는 기본적으로 privileged instruction을 사용하면 종료된다. 그러므로 hypervisor는 자체적으로 코드를 실행하고 실제 하드웨어가 허용하는 경우에만 PMC를 설정하도록 하고 guest 간에 context switch가 발생할 때마다 guest의 상태를 저장 및 복원하는 방식을 사용해야한다.

Mainstream Xen은 몇 년 전에 자체적인 virtual Performance Monitoring Unit(vPMU)를 사용하여 이를 지원하였다. 이는 Xen boot line에서 vpmu=on을 사용하면 설정할 수 있다. 그러나 vpmu=on은 하드웨어에 있는 수백 개의 PMC들을 모두 노출시키기 때문에 거의 대부분은 이 옵션을 켜지는 않는다.
노출된 PMC 중 일부는 PMC side-channel attack(알려진 대상 프로그램에 입력을 보내는 동안 특정 PMC를 측정하면 결국 대상 어플리케이션 상태와 관련된 bit를 누출시킴)에 취약하여 보안 위험을 초래할 수 있다는 여러 연구 결과들이 있었다. 실제로 이러한 공격은 가능성이 낮고 이러한 공격이 PMC에 국한되지 않지만(e.g. timing attack도 있음) 기본적으로 모든 PMC를 활성화하지 않으려는 편집증적인 보안 정책이 필요하다는 것을 이해해야 한다.
클라우드에서는 Xen 컨텍스트가 guest 간에 전환될 때 PMC도 전환하므로 이러한 공격을 수행하는 것은 훨씬 더 어렵다. 그러나 모든 PMC가 필요하지 않은 경우 모든 PMC를 활성화 해야할 이유는 없기 때문에 Brendan Gregg은 보안을 위해 PMC의 화이트리스트를 생성하겠다는 아이디어를 제시하였고 이것은 결국 x86/VPMU: implement ipc and arch filter flags로 contribute 되었다. 이 patch에서는 vpmu boot flag로 두 개의 화이트리스트를 옵션으로 제공한다. 또한 필요하다면 더 많은 whitelist set을 추가할 수 있도록 하였다. (e.g. Intel vTune 분석을 허용하는 set)

  • ipc: IPC만 측정하기에 충분한 PMC. 최소 구성.
  • arch: 7개의 아키텍처 PMC(위 표 참조). IPC 포함.

AWS는 architectural PMC 만을 활성화했다. x86/VPMU patch set은 이러한 화이트리스트를 구현하는 방법에 대한 유용한 예일 수 있지만 EC2에서는 이를 구현하는 방법은 다를 수 있다.

Conclusion

PMC는 시스템에서 발생하는 병목 지점을 분석하기 위해 매우 중요한 역할을 한다.
현재 memory I/O 문제를 분석하기에 충분한 종류의 PMC가 EC2 cloud의 dedicated host(즉, 가상 인스턴스에서는 사용 불가)에서 사용가능 하다.
이번 글에서는 IPC를 통해 실행되고 있는 코드가 memory bound, instruction bound인지 파악하여 수정이 필요한 부분을 보여주는 방법을 제안하였다.

Brendan Gregg은 PMC를 사용하여 코드를 분석하는 작업을 통해 최대 2배까지 성능 개선을 이룰 수 있었다고 한다.
PMC를 사용하여 이러한 성능 향상을 찾을 수 있기 때문에 Netflix는 EC2에서 워크로드를 더욱 빠르게 실행시킬 수 있었다.
그러므로 Micro-benchmarking 만으로 클라우드에서 제공한 시스템의 성능을 비교하는 것은 매우 단편적인 생각이다.
중요한 것은 시스템에서 제공하는 성능 뿐만 아니라 시스템에서 실행되는 어플리케이션을 관찰하고 조정(tuning)할 수 있는 능력이다.

A cloud you can't analyze is a slower cloud. - 어떤 의미로 해석해야 하지..?

References

'Research Log > Tracing' 카테고리의 다른 글

Intel PMU  (0) 2022.03.06
Advanced profiling topics. PEBS and LBR.  (0) 2022.03.06
Perf Events  (0) 2022.03.06
CPU cycle에 대한 고찰  (0) 2022.03.06
BTF, CO-RE  (0) 2022.03.06