1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package protopprof converts the runtime's raw profile logs
6 // to Profile structs containing a representation of the pprof
7 // protocol buffer profile format.
17 "internal/pprof/profile"
20 // TranslateCPUProfile parses binary CPU profiling stack trace data
21 // generated by runtime.CPUProfile() into a profile struct.
22 func TranslateCPUProfile(b
[]byte, startTime time
.Time
) (*profile
.Profile
, error
) {
23 const wordSize
= unsafe
.Sizeof(uintptr(0))
24 const minRawProfile
= 5 * wordSize
// Need a minimum of 5 words.
25 if uintptr(len(b
)) < minRawProfile
{
26 return nil, fmt
.Errorf("truncated profile")
28 n
:= int(uintptr(len(b
)) / wordSize
)
29 data
:= ((*[1 << 28]uintptr)(unsafe
.Pointer(&b
[0])))[:n
:n
]
31 data
= data
[5:] // skip header
33 // profile initialization taken from pprof tool
34 p
:= &profile
.Profile
{
35 Period
: int64(period
) * 1000,
36 PeriodType
: &profile
.ValueType
{Type
: "cpu", Unit
: "nanoseconds"},
37 SampleType
: []*profile
.ValueType
{
38 {Type
: "samples", Unit
: "count"},
39 {Type
: "cpu", Unit
: "nanoseconds"},
41 TimeNanos
: int64(startTime
.UnixNano()),
42 DurationNanos
: time
.Since(startTime
).Nanoseconds(),
44 // Parse CPU samples from the profile.
45 locs
:= make(map[uint64]*profile
.Location
)
47 if len(data
) < 2 ||
uintptr(len(data
)) < 2+data
[1] {
48 return nil, fmt
.Errorf("truncated profile")
52 if uintptr(len(data
)) < 2+nstk
{
53 return nil, fmt
.Errorf("truncated profile")
55 stk
:= data
[2 : 2+nstk
]
58 if count
== 0 && nstk
== 1 && stk
[0] == 0 {
63 sloc
:= make([]*profile
.Location
, len(stk
))
64 for i
, addr
:= range stk
{
66 // Addresses from stack traces point to the next instruction after
67 // each call. Adjust by -1 to land somewhere on the actual call
68 // (except for the leaf, which is not a call).
74 loc
= &profile
.Location
{
75 ID
: uint64(len(p
.Location
) + 1),
79 p
.Location
= append(p
.Location
, loc
)
83 p
.Sample
= append(p
.Sample
, &profile
.Sample
{
84 Value
: []int64{int64(count
), int64(count
) * int64(p
.Period
)},
89 if runtime
.GOOS
== "linux" {
90 if err
:= addMappings(p
); err
!= nil {
97 func addMappings(p
*profile
.Profile
) error
{
98 // Parse memory map from /proc/self/maps
99 f
, err
:= os
.Open("/proc/self/maps")
104 return p
.ParseMemoryMap(f
)