Open15

goのechoでpprofを扱ってみる

yuucuyuucu

documentのこのサンプルがわかりやすい

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
var memprofile = flag.String("memprofile", "", "write memory profile to `file`")

func main() {
    flag.Parse()
    if *cpuprofile != "" {
        f, err := os.Create(*cpuprofile)
        if err != nil {
            log.Fatal("could not create CPU profile: ", err)
        }
        defer f.Close() // error handling omitted for example
        if err := pprof.StartCPUProfile(f); err != nil {
            log.Fatal("could not start CPU profile: ", err)
        }
        defer pprof.StopCPUProfile()
    }

    // ... rest of the program ...

    if *memprofile != "" {
        f, err := os.Create(*memprofile)
        if err != nil {
            log.Fatal("could not create memory profile: ", err)
        }
        defer f.Close() // error handling omitted for example
        runtime.GC() // get up-to-date statistics
        if err := pprof.WriteHeapProfile(f); err != nil {
            log.Fatal("could not write memory profile: ", err)
        }
    }
}

他参考
https://tech.fusic.co.jp/posts/2019-07-07-go-profiling-using-runtime-pprof/

yuucuyuucu

runtimeとhttpの2つがある

  • runtime
    • プログラムの個別部分をprofileできる
  • http
    • プログラム全体
    • サーバーのプログラムなど
yuucuyuucu

シンプル

package main

import (
	"net/http"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo-contrib/pprof"

)

func main() {
	e := echo.New()
	pprof.Register(e)
    ......
	e.Logger.Fatal(e.Start(":1323"))
}
yuucuyuucu

Goのnet/http/pprofパッケージは、DefaultServeMuxにデバッグ用のハンドラを登録するため、
DefaultServeMuxを使用していないechoでは別に処理が必要になる

yuucuyuucu

https://pkg.go.dev/net/http/pprof

documentで以下のようにimportするだけで動くのは、DefaultServeMuxにハンドラが登録されるから

import _ "net/http/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)
}

yuucuyuucu

計測してみる

package main

import (
	"net/http"

	"github.com/labstack/echo-contrib/pprof"
	"github.com/labstack/echo/v4"
	"golang.org/x/crypto/bcrypt"
)

func handler(c echo.Context) error {
	for i := 0; i < 3; i++ {
		bcrypt.GenerateFromPassword([]byte("PASSWORD"), bcrypt.DefaultCost)
	}
	arr := []int{}
	for i := 0; i < 10000; i++ {
		arr = append(arr, i)
	}
	return c.String(http.StatusOK, "ok")
}

func main() {
	e := echo.New()
	pprof.Register(e)
	e.GET("/test", handler)
	e.Start(":8080")
}