Skip to content

플레임 그래프

플레임 그래프는 어디에 유용한가?

플레임 그래프는 함수에서 소비된 CPU 시간을 시각화하는 방법입니다. 동기 연산을 수행하는 데 너무 많은 시간을 소비하는 위치를 파악하는 데 도움이 될 수 있습니다.

플레임 그래프 생성 방법

Node.js에 대한 플레임 그래프를 만드는 것이 어렵다는 말을 들어봤을 수도 있지만, 더 이상 그렇지 않습니다. 플레임 그래프에 Solaris VM은 더 이상 필요하지 않습니다!

플레임 그래프는 노드 특정 도구가 아닌 perf 출력에서 생성됩니다. CPU 사용 시간을 시각화하는 가장 강력한 방법이지만 Node.js 8 이상에서 JavaScript 코드가 최적화되는 방식에 문제가 있을 수 있습니다. 아래의 perf 출력 문제 섹션을 참조하십시오.

미리 패키지된 도구 사용

로컬에서 플레임 그래프를 생성하는 단계를 한 번에 처리하고 싶다면 0x를 사용해 보십시오.

프로덕션 배포 진단을 위해서는 다음 참고 사항을 읽어보십시오: 0x 프로덕션 서버.

시스템 perf 도구로 플레임 그래프 생성

이 가이드의 목적은 플레임 그래프를 만드는 데 관련된 단계를 보여주고 각 단계를 제어할 수 있도록 하는 것입니다.

각 단계를 더 잘 이해하고 싶다면 자세히 설명하는 다음 섹션을 살펴보십시오.

이제 시작해 보겠습니다.

  1. perf를 설치합니다 (아직 설치되지 않은 경우 일반적으로 linux-tools-common 패키지를 통해 사용할 수 있음).
  2. perf를 실행해 봅니다. 누락된 커널 모듈에 대해 불평할 수 있습니다. 함께 설치하십시오.
  3. perf를 활성화한 상태에서 노드를 실행합니다 (Node.js 버전에 대한 팁은 perf 출력 문제 참조).
bash
perf record -e cycles:u -g -- node --perf-basic-prof app.js
  1. 누락된 패키지로 인해 perf를 실행할 수 없다는 경고가 아니면 경고를 무시합니다. 커널 모듈 샘플에 액세스할 수 없다는 경고가 표시될 수 있지만 어쨌든 필요하지 않습니다.
  2. perf script > perfs.out을 실행하여 잠시 후 시각화할 데이터 파일을 생성합니다. 더 읽기 쉬운 그래프를 위해 몇 가지 정리를 적용하는 것이 유용합니다.
  3. 아직 설치하지 않았다면 stackvis를 설치합니다. npm i -g stackvis
  4. stackvis perf < perfs.out > flamegraph.htm을 실행합니다.

이제 즐겨 사용하는 브라우저에서 플레임 그래프 파일을 열고 활활 타오르는 모습을 지켜보십시오. 색상으로 구분되어 있으므로 가장 포화된 주황색 막대에 먼저 집중할 수 있습니다. 이는 CPU를 많이 사용하는 함수를 나타낼 가능성이 높습니다.

언급할 가치가 있습니다. 플레임 그래프의 요소를 클릭하면 그래프 위에 해당 주변 영역의 확대가 표시됩니다.

실행 중인 프로세스를 샘플링하기 위해 perf 사용

이는 중단하고 싶지 않은 이미 실행 중인 프로세스에서 플레임 그래프 데이터를 기록하는 데 유용합니다. 재현하기 어려운 문제가 있는 프로덕션 프로세스를 상상해 보세요.

bash
perf record -F99 -p `pgrep -n node` -- sleep 3

sleep 3은 무엇을 위한 것일까요? -p 옵션이 다른 pid를 가리키고 있음에도 불구하고 perf가 계속 실행되도록 하기 위한 것입니다. 이 명령어는 프로세스에서 실행되어야 하고 프로세스와 함께 종료되어야 합니다. perf는 실제로 해당 명령어를 프로파일링하는지 여부에 관계없이 전달하는 명령어의 수명 동안 실행됩니다. sleep 3은 perf가 3초 동안 실행되도록 합니다.

-F(프로파일링 빈도)가 99로 설정된 이유는 무엇일까요? 이것은 합리적인 기본값입니다. 원하면 조정할 수 있습니다. -F99는 perf에게 초당 99개의 샘플을 가져오라고 지시하며, 더 정밀하게 하려면 값을 높이세요. 값이 낮을수록 덜 정확한 결과로 출력이 줄어들 것입니다. 필요한 정밀도는 CPU를 많이 사용하는 함수의 실제 실행 시간에 따라 다릅니다. 눈에 띄는 속도 저하의 원인을 찾고 있다면 초당 99 프레임으로 충분할 것입니다.

3초 동안의 perf 레코드를 얻은 후 위에서 나온 마지막 두 단계로 플레임 그래프를 생성합니다.

Node.js 내부 함수 필터링

일반적으로는 호출 성능만 보고 싶으므로 Node.js 및 V8 내부 함수를 필터링하면 그래프를 훨씬 더 쉽게 읽을 수 있습니다. 다음 명령어를 사용하여 perf 파일을 정리할 수 있습니다.

bash
sed -i -r \
    -e '/(_libc_start|LazyCompile) |v8::internal::BuiltIn|Stub|LoadIC:\\[\\[' \
    -e '/^$/d' \
    perf.data > perf.out

플레임 그래프를 읽고 이상하게 보인다면, 즉 가장 많은 시간을 소비하는 키 함수에서 뭔가 누락된 것처럼 보인다면 필터 없이 플레임 그래프를 생성해 보세요. 어쩌면 Node.js 자체에 문제가 있는 드문 경우일 수도 있습니다.

Node.js의 프로파일링 옵션

--perf-basic-prof-only-functions--perf-basic-prof는 JavaScript 코드를 디버깅하는 데 유용한 두 가지 옵션입니다. 다른 옵션은 Node.js 자체를 프로파일링하는 데 사용되며 이 가이드의 범위를 벗어납니다.

--perf-basic-prof-only-functions는 출력이 더 적으므로 오버헤드가 가장 적은 옵션입니다.

왜 이런 옵션이 필요할까요?

이러한 옵션이 없으면 여전히 플레임 그래프를 얻을 수 있지만 대부분의 막대는 v8::Function::Call로 레이블됩니다.

Perf 출력 문제

Node.js 8.x V8 파이프라인 변경 사항

Node.js 8.x 이상은 V8 엔진의 JavaScript 컴파일 파이프라인에 대한 새로운 최적화 기능을 제공하므로 경우에 따라 perf에서 함수 이름/참조에 접근할 수 없게 됩니다. (Turbofan이라고 함)

그 결과 플레임 그래프에서 함수 이름을 올바르게 가져오지 못할 수 있습니다.

함수 이름이 있어야 할 자리에 ByteCodeHandler:가 표시될 것입니다.

0x에는 이러한 문제를 완화하기 위한 몇 가지 기능이 내장되어 있습니다.

자세한 내용은 다음을 참조하십시오.

Node.js 10+

Node.js 10.x는 --interpreted-frames-native-stack 플래그를 사용하여 Turbofan 문제를 해결합니다.

node --interpreted-frames-native-stack --perf-basic-prof-only-functions를 실행하여 V8이 JavaScript를 컴파일하는 데 어떤 파이프라인을 사용했든 관계없이 플레임 그래프에서 함수 이름을 가져올 수 있습니다.

플레임 그래프에서 레이블 깨짐

다음과 같은 레이블이 표시된다면

bash
node`_ZN2v88internal11interpreter17BytecodeGenerator15VisitStatementsEPMS0_8Zone

사용 중인 Linux perf가 demangle 지원 기능이 없는 상태로 컴파일되었음을 의미합니다. 예를 들어 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1396654를 참조하십시오.

예시

플레임 그래프 연습을 통해 직접 플레임 그래프를 캡처하는 연습을 해보십시오!