]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/trace: generate new pprof profiles
authorDmitry Vyukov <dvyukov@google.com>
Tue, 12 Apr 2016 18:50:59 +0000 (20:50 +0200)
committerDmitry Vyukov <dvyukov@google.com>
Fri, 22 Apr 2016 19:54:24 +0000 (19:54 +0000)
Generate new protobuf pprof profiles with embed symbol info.
This makes program binary unnecessary.

Change-Id: Ie628439c13c5e34199782031138102c83ea50621
Reviewed-on: https://go-review.googlesource.com/21873
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Dmitry Vyukov <dvyukov@google.com>

src/cmd/trace/pprof.go

index eaddf63ee82f73306a2332a5a6a7cc3a637af02c..fdda6d89beec0322e0ba9f016b4be3a6d3ab3804 100644 (file)
@@ -8,6 +8,7 @@ package main
 
 import (
        "bufio"
+       "cmd/internal/pprof/profile"
        "fmt"
        "internal/trace"
        "io/ioutil"
@@ -133,34 +134,79 @@ func serveSVGProfile(w http.ResponseWriter, r *http.Request, prof map[uint64]Rec
                http.Error(w, fmt.Sprintf("failed to create temp file: %v", err), http.StatusInternalServerError)
                return
        }
-       defer os.Remove(blockf.Name())
+       defer func() {
+               blockf.Close()
+               os.Remove(blockf.Name())
+       }()
        blockb := bufio.NewWriter(blockf)
-       fmt.Fprintf(blockb, "--- contention:\ncycles/second=1000000000\n")
-       for _, rec := range prof {
-               fmt.Fprintf(blockb, "%v %v @", rec.time, rec.n)
-               for _, f := range rec.stk {
-                       fmt.Fprintf(blockb, " 0x%x", f.PC)
-               }
-               fmt.Fprintf(blockb, "\n")
+       if err := buildProfile(prof).Write(blockb); err != nil {
+               http.Error(w, fmt.Sprintf("failed to write profile: %v", err), http.StatusInternalServerError)
+               return
        }
-       err = blockb.Flush()
-       if err != nil {
+       if err := blockb.Flush(); err != nil {
                http.Error(w, fmt.Sprintf("failed to flush temp file: %v", err), http.StatusInternalServerError)
                return
        }
-       err = blockf.Close()
-       if err != nil {
+       if err := blockf.Close(); err != nil {
                http.Error(w, fmt.Sprintf("failed to close temp file: %v", err), http.StatusInternalServerError)
                return
        }
-
        svgFilename := blockf.Name() + ".svg"
-       _, err = exec.Command("go", "tool", "pprof", "-svg", "-output", svgFilename, programBinary, blockf.Name()).CombinedOutput()
-       if err != nil {
-               http.Error(w, fmt.Sprintf("failed to execute go tool pprof: %v", err), http.StatusInternalServerError)
+       if output, err := exec.Command("go", "tool", "pprof", "-svg", "-output", svgFilename, blockf.Name()).CombinedOutput(); err != nil {
+               http.Error(w, fmt.Sprintf("failed to execute go tool pprof: %v\n%s", err, output), http.StatusInternalServerError)
                return
        }
        defer os.Remove(svgFilename)
        w.Header().Set("Content-Type", "image/svg+xml")
        http.ServeFile(w, r, svgFilename)
 }
+
+func buildProfile(prof map[uint64]Record) *profile.Profile {
+       p := &profile.Profile{
+               PeriodType: &profile.ValueType{Type: "trace", Unit: "count"},
+               Period:     1,
+               SampleType: []*profile.ValueType{
+                       {Type: "contentions", Unit: "count"},
+                       {Type: "delay", Unit: "nanoseconds"},
+               },
+       }
+       locs := make(map[uint64]*profile.Location)
+       funcs := make(map[string]*profile.Function)
+       for _, rec := range prof {
+               var sloc []*profile.Location
+               for _, frame := range rec.stk {
+                       loc := locs[frame.PC]
+                       if loc == nil {
+                               fn := funcs[frame.File+frame.Fn]
+                               if fn == nil {
+                                       fn = &profile.Function{
+                                               ID:         uint64(len(p.Function) + 1),
+                                               Name:       frame.Fn,
+                                               SystemName: frame.Fn,
+                                               Filename:   frame.File,
+                                       }
+                                       p.Function = append(p.Function, fn)
+                                       funcs[frame.File+frame.Fn] = fn
+                               }
+                               loc = &profile.Location{
+                                       ID:      uint64(len(p.Location) + 1),
+                                       Address: frame.PC,
+                                       Line: []profile.Line{
+                                               profile.Line{
+                                                       Function: fn,
+                                                       Line:     int64(frame.Line),
+                                               },
+                                       },
+                               }
+                               p.Location = append(p.Location, loc)
+                               locs[frame.PC] = loc
+                       }
+                       sloc = append(sloc, loc)
+               }
+               p.Sample = append(p.Sample, &profile.Sample{
+                       Value:    []int64{int64(rec.n), rec.time},
+                       Location: sloc,
+               })
+       }
+       return p
+}