File: pprof.go

package info (click to toggle)
golang-golang-x-tools 1%3A0.25.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental, sid, trixie
  • size: 22,724 kB
  • sloc: javascript: 2,027; asm: 1,645; sh: 166; yacc: 155; makefile: 49; ansic: 8
file content (89 lines) | stat: -rw-r--r-- 2,054 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package pprof provides minimalistic routines for extracting
// information from profiles.
package pprof

import (
	"fmt"
	"time"
)

// TotalTime parses the profile data and returns the accumulated time.
// The input should not be gzipped.
func TotalTime(data []byte) (total time.Duration, err error) {
	defer func() {
		if x := recover(); x != nil {
			err = fmt.Errorf("error parsing pprof profile: %v", x)
		}
	}()
	decode(&total, data, msgProfile)
	return
}

// All errors are handled by panicking.
// Constants are copied below to avoid dependency on protobufs or pprof.

// protobuf wire types, from https://developers.google.com/protocol-buffers/docs/encoding
const (
	wireVarint = 0
	wireBytes  = 2
)

// pprof field numbers, from https://github.com/google/pprof/blob/master/proto/profile.proto
const (
	fldProfileSample = 2 // repeated Sample
	fldSampleValue   = 2 // repeated int64
)

// arbitrary numbering of message types
const (
	msgProfile = 0
	msgSample  = 1
)

func decode(total *time.Duration, data []byte, msg int) {
	for len(data) > 0 {
		// Read tag (wire type and field number).
		tag := varint(&data)

		// Read wire value (int or bytes).
		wire := tag & 7
		var ival uint64
		var sval []byte
		switch wire {
		case wireVarint:
			ival = varint(&data)

		case wireBytes:
			n := varint(&data)
			sval, data = data[:n], data[n:]

		default:
			panic(fmt.Sprintf("unexpected wire type: %d", wire))
		}

		// Process field of msg.
		fld := tag >> 3
		switch {
		case msg == msgProfile && fld == fldProfileSample:
			decode(total, sval, msgSample) // recursively decode Sample message

		case msg == msgSample, fld == fldSampleValue:
			*total += time.Duration(ival) // accumulate time
		}
	}
}

func varint(data *[]byte) (v uint64) {
	for i := 0; ; i++ {
		b := uint64((*data)[i])
		v += (b & 0x7f) << (7 * i)
		if b < 0x80 {
			*data = (*data)[i+1:]
			return v
		}
	}
}