aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/pprof/pprof.go
diff options
context:
space:
mode:
authorMichael Matloob <matloob@golang.org>2016-11-10 13:31:41 -0500
committerMichael Matloob <matloob@golang.org>2016-11-10 21:07:48 +0000
commit76f12cdaa2be0b96d314762ff5b2e403d1359cd8 (patch)
tree951799799bb57d41a3f767200f37088dfbeabe88 /src/runtime/pprof/pprof.go
parent7448eb4172bfc8f704b9ea39d77d0113a042b9dc (diff)
downloadgo-76f12cdaa2be0b96d314762ff5b2e403d1359cd8.tar.xz
runtime/pprof: output CPU profiles in pprof protobuf format
This change buffers the entire profile and converts in one shot in the profile writer, and could use more memory than necessary to output protocol buffer formatted profiles. It should be possible to convert each chunk in a stream (maybe maintaining some minimal state to output in the end) which could save on memory usage. Fixes #16093 Change-Id: I946c6a2b044ae644c72c8bb2d3bd82c415b1a847 Reviewed-on: https://go-review.googlesource.com/33071 Run-TryBot: Michael Matloob <matloob@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/runtime/pprof/pprof.go')
-rw-r--r--src/runtime/pprof/pprof.go51
1 files changed, 16 insertions, 35 deletions
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index 20ccb51b00..70544acde1 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -74,12 +74,13 @@ import (
"bytes"
"fmt"
"io"
- "os"
"runtime"
+ "runtime/pprof/internal/protopprof"
"sort"
"strings"
"sync"
"text/tabwriter"
+ "time"
)
// BUG(rsc): Profiles are only as good as the kernel support used to generate them.
@@ -670,49 +671,29 @@ func StartCPUProfile(w io.Writer) error {
}
func profileWriter(w io.Writer) {
+ startTime := time.Now()
+ // This will buffer the entire profile into buf and then
+ // translate it into a profile.Profile structure. This will
+ // create two copies of all the data in the profile in memory.
+ // TODO(matloob): Convert each chunk of the proto output and
+ // stream it out instead of converting the entire profile.
+ var buf bytes.Buffer
for {
data := runtime.CPUProfile()
if data == nil {
break
}
- w.Write(data)
+ buf.Write(data)
}
- // We are emitting the legacy profiling format, which permits
- // a memory map following the CPU samples. The memory map is
- // simply a copy of the GNU/Linux /proc/self/maps file. The
- // profiler uses the memory map to map PC values in shared
- // libraries to a shared library in the filesystem, in order
- // to report the correct function and, if the shared library
- // has debug info, file/line. This is particularly useful for
- // PIE (position independent executables) as on ELF systems a
- // PIE is simply an executable shared library.
- //
- // Because the profiling format expects the memory map in
- // GNU/Linux format, we only do this on GNU/Linux for now. To
- // add support for profiling PIE on other ELF-based systems,
- // it may be necessary to map the system-specific mapping
- // information to the GNU/Linux format. For a reasonably
- // portable C++ version, see the FillProcSelfMaps function in
- // https://github.com/gperftools/gperftools/blob/master/src/base/sysinfo.cc
- //
- // The code that parses this mapping for the pprof tool is
- // ParseMemoryMap in cmd/internal/pprof/legacy_profile.go, but
- // don't change that code, as similar code exists in other
- // (non-Go) pprof readers. Change this code so that that code works.
- //
- // We ignore errors reading or copying the memory map; the
- // profile is likely usable without it, and we have no good way
- // to report errors.
- if runtime.GOOS == "linux" {
- f, err := os.Open("/proc/self/maps")
- if err == nil {
- io.WriteString(w, "\nMAPPED_LIBRARIES:\n")
- io.Copy(w, f)
- f.Close()
- }
+ profile, err := protopprof.TranslateCPUProfile(buf.Bytes(), startTime)
+ if err != nil {
+ // The runtime should never produce an invalid or truncated profile.
+ // It drops records that can't fit into its log buffers.
+ panic(fmt.Errorf("could not translate binary profile to proto format: %v", err))
}
+ profile.Write(w)
cpu.done <- true
}