Add go tool pprof import support (#165)

This PR adds support for importing from Google's pprof format, which is a gzipped, protobuf encoded file format (that's incredibly well documented!) The [pprof http library](https://golang.org/pkg/net/http/pprof/) also offers an output of the trace file format, which continues to not be supported in speedscope to date (See #77). This will allow importing of profiles generated by the standard library go profiler for analysis of profiles containing heap allocation information, CPU profile information, and a few other things like coroutine creation information.

In order to add support for that a number of dependent bits of functionality were added, which should each provide an easier path for future binary input sources

- A protobuf decoding library was included ([protobufjs](https://www.npmjs.com/package/protobufjs)) which includes both a protobuf parser generator based on a .proto file & TypeScript definition generation from the resulting generated JavaScript file
- More generic binary file import. Before this PR, all supported sources were plaintext, with the exception of Instruments 10 support, which takes a totally different codepath. Now binary file import should work when files are dropped, opened via file browsing, or opened via invocation of the speedscope CLI.
- Transparent gzip decoding of imported files (this means that if you were to gzip compress another JSON file, then importing it should still work fine)

Fixes #60.

--

This is a [donation motivated](https://github.com/jlfwong/speedscope/issues/60#issuecomment-419660710) PR motivated by donations by @davecheney & @jmoiron to [/dev/color](https://www.devcolor.org/welcome) 🎉
This commit is contained in:
Jamie Wong
2018-09-26 11:33:34 -07:00
committed by GitHub
parent c70171836c
commit 3f205ec3e9
21 changed files with 5748 additions and 81 deletions
+2
View File
@@ -0,0 +1,2 @@
simple
server
+15
View File
@@ -0,0 +1,15 @@
.PHONY: all clean linux-perf
all: simple server
clean:
rm -f simple server
simple: simple.go
go build $<
server: server.go
go build $<
simple.prof: simple
./$< -cpuprofile=$@
+71
View File
@@ -0,0 +1,71 @@
package main
import (
"log"
"fmt"
"sync"
"time"
"net/http"
)
import _ "net/http/pprof"
// See https://golang.org/pkg/net/http/pprof/ for details
func alpha() {
z := 3
for i := 0; i < 100000; i++ {
z *= 3
}
}
func beta() {
z := 3
for i := 0; i < 100000; i++ {
z *= 3
}
}
func delta() {
z := 3
for i := 0; i < 100000; i++ {
z *= 3
}
alpha()
beta()
}
func gamma() {
z := 3
for i := 0; i < 100000; i++ {
z *= 3
}
}
func main() {
// we need a webserver to get the pprof webserver
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
fmt.Println("hello world")
var wg sync.WaitGroup
wg.Add(1)
go leakyFunction(wg)
wg.Wait()
}
func leakyFunction(wg sync.WaitGroup) {
defer wg.Done()
s := make([]string, 3)
for i:= 0; i < 10000000; i++{
alpha()
beta()
delta()
gamma()
s = append(s, "magical pandas")
if (i % 100000) == 0 {
time.Sleep(50 * time.Millisecond)
}
}
}
+53
View File
@@ -0,0 +1,53 @@
package main
import "flag"
import "runtime/pprof"
import "os"
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func alpha() {
z := 3
for i := 0; i < 100000; i++ {
z *= 3
}
}
func beta() {
z := 3
for i := 0; i < 100000; i++ {
z *= 3
}
}
func delta() {
z := 3
for i := 0; i < 100000; i++ {
z *= 3
}
alpha()
beta()
}
func gamma() {
z := 3
for i := 0; i < 100000; i++ {
z *= 3
}
}
func main() {
flag.Parse()
if *cpuprofile != "" {
f, _ := os.Create(*cpuprofile)
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
for i := 0; i < 10000; i++ {
alpha()
beta()
delta()
gamma()
}
}