Search code examples
gowebserverbenchmarkingpprof

pprof profile with julienschmidtrouter and benchmarks not profiling handler


I am trying to profile my web server I wrote, but my pprof does not contain any data about the handler func.
I am using the httprouter package by julienschmidt, and want to simply benchmark one of my handlers and see the pprof profile for that. For the benchmarking, I am using go-wrk

I set up my web server and pprof like this:

// Configure the server
server := &http.Server{
    Addr:    ":4000",
    Handler: router,
}

go func() {
    log.Println(http.ListenAndServe(":6060", nil))
}()

// Start the server
err = server.ListenAndServe()
if err != nil {
    panic(err)
}

The router is initialized like this:

// Create the httprouter
router := httprouter.New()
// Register all handlers
router.GET("/entities/:type/map", h.UseHandler(&h.ApiGetEntitiesMapRequest{}, p))

And my handler looks like this:

func (req ApiGetEntitiesMapRequest) Handle(r *http.Request, hrp httprouter.Params, p Params) (interface{}, error) {
    test := make([]string, 0)
    for i := 0; i < 1000; i++ {
        test = append(test, "1")
        test = append(test, "2")
        // Ensure pprof has some time to collect its data
        time.Sleep(10)
    }
    return test, nil
}

This handler is just a test, where I dynamically append a lot of elements to a slice. The reason for that is, I wanted to test whether these dynamic allocations are represented in the heap profile of pprof.

Now, what I did was:

The request works and my benchmark also reports everything correctly. However, when I type png in the pprof terminal, I get this graphenter image description here.

The graph does not contain any information about my handler and the costly heap allocations I did in my handler. What am I doing wrong?


Solution

  • So, I finally found the problem!

    If you are using a custom mux for handling your requests, you need to register the pprof handler to your mux, in order to get the profiling right:

    router.HandlerFunc(http.MethodGet, "/debug/pprof/", pprof.Index)
    router.HandlerFunc(http.MethodGet, "/debug/pprof/cmdline", pprof.Cmdline)
    router.HandlerFunc(http.MethodGet, "/debug/pprof/profile", pprof.Profile)
    router.HandlerFunc(http.MethodGet, "/debug/pprof/symbol", pprof.Symbol)
    router.HandlerFunc(http.MethodGet, "/debug/pprof/trace", pprof.Trace)
    router.Handler(http.MethodGet, "/debug/pprof/goroutine", pprof.Handler("goroutine"))
    router.Handler(http.MethodGet, "/debug/pprof/heap", pprof.Handler("heap"))
    router.Handler(http.MethodGet,"/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
    router.Handler(http.MethodGet,"/debug/pprof/block", pprof.Handler("block"))
    

    Now I got my desired result!