Skip to content

Instantly share code, notes, and snippets.

@NaniteFactory
Last active May 17, 2021 23:44
Show Gist options
  • Save NaniteFactory/30db17027785382ae8d9693ab2009dc9 to your computer and use it in GitHub Desktop.
Save NaniteFactory/30db17027785382ae8d9693ab2009dc9 to your computer and use it in GitHub Desktop.

pprof 사용법

1. pprof의 구분

  1. go tool pprof 프로그램:
    • pprof 데이터를 분석하여 보여 주는 pprof 바이너리다.
  2. runtime/pprof 패키지:
    • Go 프로그램으로부터 pprof 데이터를 생성하여 내보내는 일을 하는 패키지다.
  3. net/http/pprof 패키지:
    • runtime/pprof 패키지가 하고 있는 것을 (ServeHTTP로) 웹으로 내보내거나 프로그램의 pprof 데이터를 분석하여 웹 인터페이스로 보여 주는 일을 하는 패키지다.

2. go tool pprof 사용법

runtime/pprof 또는 net/http/pprof 를 이용하여 생성한 pprof 데이터go tool pprof에 제공하면 go tool pprof가 가공하여 출력한다.

데이터를 그래프로 시각화하여 pdf로 내보내는 명령어 예제:

go tool pprof -pdf your_raw_pprof_data_name > out.pdf

30초 간의 CPU 프로파일을 받아보기:

go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30

go tool pprof와 비슷한 것으로 go tool trace라는 툴도 있다:

go tool trace http://localhost:6060/debug/pprof/trace?seconds=5

자세한 것은 go tool pprof -h에서 찾는다.


3. runtime/pprof 패키지 사용법

  1. 프로그램에 현존하는 모든 프로파일을 받아오는 함수

    func runtime.pprof.Profiles() []*Profile
  2. 프로그램에 현존하는 프로파일 하나를 이름으로 지정하여 받아오는 함수

    func runtime.pprof.Lookup(name string) *Profile
  3. 프로파일 객체

    • func (p *Profile) Count() int // 항목의 실행 스택 수. 가령 "goroutine"의 프로파일이라면 고루틴의 수가 됨.
    • func (p *Profile) Name() string // 작성 시점 기준으로 "allocs", "block", "goroutine", "heap", "mutex", "threadcreate" 가운데 하나.
    • func (p *Profile) WriteTo(w io.Writer, debug int) error // 프로파일의 내용을 써서 내보냄. 두 번째 인자로 넘기는 것은 '디버그 수준'이라고 하는데 아래에 이어서 적음.

    프로파일의 '디버그 수준'은 내보내는 데이터의 형식을 지정함. (자작 변수명 nDebugLevel)

    • 0이면 gz로 압축된 프로토버프 형식. (이 형식이어야 실행 프로그램의 원본 바이너리 제공 없이 go tool pprof로 바로 분석할 수 있다.)
    • 1이면 프로그래머가 편하게 읽어볼 수 있는 비교적 간결한 텍스트 형식. (몇 번째 코드에서 몇 번이나 일어났다는 점을 중복 없이 짧게 적음.)
    • 2이면 런타임 패닉 로그 수준으로 스택 트레이스가 자세히 기술된 텍스트 형식이다. (0이나 1의 그것에 비해 별로 쓸모 없음.)
    • 0, 1, 2 이외의 수는 작성 시점을 기준으로 무효하며 무의미함.
  4. 헷갈리게 하는 쓸모 없는 함수

    func runtime.pprof.WriteHeapProfile(w io.Writer) error
    • 하위 호환성을 위해 유지되고 있는 pprof.WriteHeapProfile이라는 쓸모 없는 함수가 있다.
    • pprof.WriteHeapProfile(w) 의 호출은 pprof.Lookup("heap").WriteTo(w, 0) 와 동일하다.
    • 힙 프로파일은 메모리 프로파일이라고도 하는데 특별하게 다뤄지는 모양이다.
  5. 측정 함수

    위에서 언급한 프로파일들처럼 프로그램의 한 순간의 상태를 담은 데이터가 아닌 일정 기간 동안 이어진 행위에 대한 프로파일링을 별도로 한다.

    func runtime.pprof.StartCPUProfile(w io.Writer) error
    func runtime.pprof.StopCPUProfile()

4. net/http/pprof 패키지 사용법

net/http/pprof는 모든 pprof 데이터를 시각화하여 웹 브라우저 상에서 확인할 수 있게 한다.

func init() {
	http.HandleFunc("/debug/pprof/", Index)
	http.HandleFunc("/debug/pprof/cmdline", Cmdline)
	http.HandleFunc("/debug/pprof/profile", Profile)
	http.HandleFunc("/debug/pprof/symbol", Symbol)
	http.HandleFunc("/debug/pprof/trace", Trace)
}

아래처럼 임포트하면 DefaultServeMuxnet.http.pprof.init() 함수가 핸들러를 등록한다.

import _ "net/http/pprof"

그리고 다음과 같이 웹서버를 실행한다.

http.ListenAndServe("localhost:8080", nil) // nil 또는 http.DefaultServeMux

그러면 아래 주소에서 프로파일링 데이터를 확인할 수 있다.

http://localhost:8080/debug/pprof/

다음과 같은 프로파일 객체를 시각화하거나 압축된 프로토버프 형식으로 제공한다.

  • "allocs", "block", "goroutine", "heap", "mutex", "threadcreate"
  • "profile": 주어진 몇 초 동안의 CPU 프로파일
  • "trace": 주어진 몇 초 동안의 전체 스택 트레이스 (go tool pprof가 아닌 go tool trace로 분석하는 full stack trace)
  • "cmdline": 명령줄 프로그램 인스턴스 나열 (필자는 인스턴스가 하나 있는 것밖에 못 봄)
  • "symbol": 심볼인 듯함

net.http.pprof 패키지 자체는 핸들러 함수를 등록하고 그것을 내보낼 뿐이다. 아래 나열된 것이 패키지의 모든 수출(export) 함수다.

  • func Handler(name string) http.Handler // "allocs", "block", "goroutine", "heap", "mutex", "threadcreate" 등 이름을 지정해서 해당 핸들러를 받아올 수 있음
  • func Index(w http.ResponseWriter, r *http.Request) // "allocs", "block", "goroutine", "heap", "mutex", "threadcreate" 로 넘어가기 직전의 인덱스 페이지
  • func Profile(w http.ResponseWriter, r *http.Request) // 30초 또는 N초 간의 CPU 프로파일을 제공하는 페이지
  • func Trace(w http.ResponseWriter, r *http.Request) // 주어진 몇 초 동안의 전체 스택 트레이스 (go tool pprof가 아닌 go tool trace로 분석하는 full stack trace)
  • func Cmdline(w http.ResponseWriter, r *http.Request) // 명령줄 프로그램 인스턴스 나열하는 페이지
  • func Symbol(w http.ResponseWriter, r *http.Request) // "symbol" 프로파일 페이지

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment