cmd/pprof: update vendored github.com/google/pprof

Pull in the latest published version of github.com/google/pprof
as part of the continuous process of keeping Go's dependencies
up to date.

For #36905.

[git-generate]
cd src/cmd
go get github.com/google/pprof@v0.0.0-20250630185457-6e76a2b096b5
go mod tidy
go mod vendor

Change-Id: Icfa35291f629fcffae67238704e59e17ee05e0b5
Reviewed-on: https://go-review.googlesource.com/c/go/+/696015
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
Dmitri Shuralyov 2025-08-13 16:48:59 -04:00 committed by Gopher Robot
parent 674c5f0edd
commit de9b6f9875
21 changed files with 67 additions and 89 deletions

View file

@ -3,7 +3,7 @@ module cmd
go 1.26
require (
github.com/google/pprof v0.0.0-20250208200701-d0013a598941
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5
golang.org/x/arch v0.20.1-0.20250808194827-46ba08e3ae58
golang.org/x/build v0.0.0-20250806225920-b7c66c047964
golang.org/x/mod v0.27.0
@ -15,7 +15,7 @@ require (
)
require (
github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd // indirect
github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b // indirect
golang.org/x/text v0.28.0 // indirect
rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef // indirect
)

View file

@ -1,9 +1,9 @@
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd h1:EVX1s+XNss9jkRW9K6XGJn2jL2lB1h5H804oKPsxOec=
github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 h1:xhMrHhTJ6zxu3gA4enFM9MLn9AY7613teCdFnlUVbSQ=
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b h1:ogbOPx86mIhFy764gGkqnkFC8m5PJA7sPzlk9ppLVQA=
github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/arch v0.20.1-0.20250808194827-46ba08e3ae58 h1:uxPa6+/WsUfzikIAPMqpTho10y4qtYpINBurU+6NrHE=

View file

@ -17,6 +17,7 @@ package driver
import (
"io"
"maps"
"net/http"
"regexp"
"time"
@ -293,8 +294,6 @@ type internalSymbolizer struct {
func (s *internalSymbolizer) Symbolize(mode string, srcs plugin.MappingSources, prof *profile.Profile) error {
isrcs := MappingSources{}
for m, s := range srcs {
isrcs[m] = s
}
maps.Copy(isrcs, srcs)
return s.Symbolizer.Symbolize(mode, isrcs, prof)
}

View file

@ -4,6 +4,7 @@ import (
"fmt"
"net/url"
"reflect"
"slices"
"strconv"
"strings"
"sync"
@ -226,11 +227,9 @@ func (cfg *config) set(f configField, value string) error {
case *string:
if len(f.choices) > 0 {
// Verify that value is one of the allowed choices.
for _, choice := range f.choices {
if choice == value {
*ptr = value
return nil
}
if slices.Contains(f.choices, value) {
*ptr = value
return nil
}
return fmt.Errorf("invalid %q value %q", f.name, value)
}

View file

@ -17,6 +17,7 @@ package driver
import (
"fmt"
"regexp"
"slices"
"strconv"
"strings"
@ -148,10 +149,8 @@ func compileTagFilter(name, value string, numLabelUnits map[string]string, ui pl
return func(s *profile.Sample) bool {
if vals, ok := s.Label[wantKey]; ok {
for _, rx := range rfx {
for _, val := range vals {
if rx.MatchString(val) {
return true
}
if slices.ContainsFunc(vals, rx.MatchString) {
return true
}
}
}

View file

@ -174,10 +174,7 @@ func chunkedGrab(sources []profileSource, fetch plugin.Fetcher, obj plugin.ObjTo
var count int
for start := 0; start < len(sources); start += chunkSize {
end := start + chunkSize
if end > len(sources) {
end = len(sources)
}
end := min(start+chunkSize, len(sources))
chunkP, chunkMsrc, chunkSave, chunkCount, chunkErr := concurrentGrab(sources[start:end], fetch, obj, ui, tr)
switch {
case chunkErr != nil:

View file

@ -218,10 +218,12 @@ a {
}
#graph {
overflow: hidden;
width: 100%;
height: 100%;
}
#graph svg {
width: 100%;
height: auto;
height: 100%;
padding: 10px;
}
#content.source .filename {

View file

@ -579,7 +579,7 @@ function stackViewer(stacks, nodes) {
}
// percentText returns text that displays v in appropriate units alongside its
// percentange.
// percentage.
function percentText(v) {
function percent(v, total) {
return Number(((100.0 * v) / total).toFixed(1)) + '%';

View file

@ -19,11 +19,13 @@ import (
"fmt"
"html/template"
"io"
"maps"
"net"
"net/http"
gourl "net/url"
"os"
"os/exec"
"slices"
"strconv"
"strings"
"time"
@ -107,9 +109,7 @@ func serveWebInterface(hostport string, p *profile.Profile, o *plugin.Options, d
for n, c := range pprofCommands {
ui.help[n] = c.description
}
for n, help := range configHelp {
ui.help[n] = help
}
maps.Copy(ui.help, configHelp)
ui.help["details"] = "Show information about the profile and this view"
ui.help["graph"] = "Display profile as a directed graph"
ui.help["flamegraph"] = "Display profile as a flame graph"
@ -227,12 +227,7 @@ func redirectWithQuery(path string, code int) http.HandlerFunc {
}
func isLocalhost(host string) bool {
for _, v := range []string{"localhost", "127.0.0.1", "[::1]", "::1"} {
if host == v {
return true
}
}
return false
return slices.Contains([]string{"localhost", "127.0.0.1", "[::1]", "::1"}, host)
}
func openBrowser(url string, o *plugin.Options) {

View file

@ -230,7 +230,7 @@ func GetBase(fh *elf.FileHeader, loadSegment *elf.ProgHeader, stextOffset *uint6
}
if stextOffset == nil && start > 0 && start < 0x8000000000000000 {
// A regular user-mode executable. Compute the base offset using same
// arithmetics as in ET_DYN case below, see the explanation there.
// arithmetic as in ET_DYN case below, see the explanation there.
// Ideally, the condition would just be "stextOffset == nil" as that
// represents the address of _stext symbol in the vmlinux image. Alas,
// the caller may skip reading it from the binary (it's expensive to scan
@ -313,7 +313,7 @@ func ProgramHeadersForMapping(phdrs []elf.ProgHeader, mapOff, mapSz uint64) []*e
// value is dependent on the memory management unit of the CPU. The page
// size is 4KB virtually on all the architectures that we care about, so we
// define this metric as a constant. If we encounter architectures where
// page sie is not 4KB, we must try to guess the page size on the system
// page size is not 4KB, we must try to guess the page size on the system
// where the profile was collected, possibly using the architecture
// specified in the ELF file header.
pageSize = 4096

View file

@ -336,12 +336,8 @@ func newGraph(prof *profile.Profile, o *Options) (*Graph, map[uint64]Nodes) {
if dw == 0 && w == 0 {
continue
}
for k := range seenNode {
delete(seenNode, k)
}
for k := range seenEdge {
delete(seenEdge, k)
}
clear(seenNode)
clear(seenEdge)
var parent *Node
// A residual edge goes over one or more nodes that were not kept.
residual := false
@ -850,10 +846,7 @@ func (g *Graph) selectTopNodes(maxNodes int, visualMode bool) Nodes {
// If generating a visual graph, count tags as nodes. Update
// maxNodes to account for them.
for i, n := range g.Nodes {
tags := countTags(n)
if tags > maxNodelets {
tags = maxNodelets
}
tags := min(countTags(n), maxNodelets)
if count += tags + 1; count >= maxNodes {
maxNodes = i + 1
break

View file

@ -18,6 +18,7 @@ package measurement
import (
"fmt"
"math"
"slices"
"strings"
"time"
@ -197,16 +198,14 @@ type UnitType struct {
// nil if the unit with such alias is not found.
func (ut UnitType) findByAlias(alias string) *Unit {
for _, u := range ut.Units {
for _, a := range u.aliases {
if alias == a {
return &u
}
if slices.Contains(u.aliases, alias) {
return &u
}
}
return nil
}
// sniffUnit simpifies the input alias and returns the unit associated with the
// sniffUnit simplifies the input alias and returns the unit associated with the
// specified alias. It returns nil if the unit with such alias is not found.
func (ut UnitType) sniffUnit(unit string) *Unit {
unit = strings.ToLower(unit)

View file

@ -569,7 +569,7 @@ func symbolsFromBinaries(prof *profile.Profile, g *graph.Graph, rx *regexp.Regex
return objSyms
}
// objSym represents a symbol identified from a binary. It includes
// objSymbol represents a symbol identified from a binary. It includes
// the SymbolInfo from the disasm package and the base that must be
// added to correspond to sample addresses
type objSymbol struct {

View file

@ -25,6 +25,7 @@ import (
"os"
"path/filepath"
"regexp"
"slices"
"sort"
"strconv"
"strings"
@ -490,7 +491,7 @@ func (sp *sourcePrinter) addStack(addr uint64, frames []plugin.Frame) {
file.lines[f.Line] = append(file.lines[f.Line], sourceInst{addr, stack})
// Remember the first function name encountered per source line
// and assume that that line belongs to that function.
// and assume that line belongs to that function.
if _, ok := file.funcName[f.Line]; !ok {
file.funcName[f.Line] = f.Func
}
@ -553,7 +554,7 @@ func (sp *sourcePrinter) splitIntoRanges(prof *profile.Profile, addrMap map[uint
unprocessed = append(unprocessed, addr)
}
}
sort.Slice(addrs, func(i, j int) bool { return addrs[i] < addrs[j] })
slices.Sort(addrs)
const expand = 500 // How much to expand range to pick up nearby addresses.
var result []addressRange
@ -769,10 +770,7 @@ func (sp *sourcePrinter) functions(f *sourceFile) []sourceFunction {
}
} else {
// Find gap from predecessor and divide between predecessor and f.
halfGap := (f.begin - funcs[i-1].end) / 2
if halfGap > expand {
halfGap = expand
}
halfGap := min((f.begin-funcs[i-1].end)/2, expand)
funcs[i-1].end += halfGap
f.begin -= halfGap
}

View file

@ -281,14 +281,11 @@ func demanglerModeToOptions(demanglerMode string) []demangle.Option {
panic(fmt.Sprintf("unknown demanglerMode %s", demanglerMode))
}
func demangleSingleFunction(fn *profile.Function, options []demangle.Option) {
func demangleSingleFunction(fn *profile.Function, opts []demangle.Option) {
if fn.Name != "" && fn.SystemName != fn.Name {
return // Already demangled.
}
// Copy the options because they may be updated by the call.
o := make([]demangle.Option, len(options))
copy(o, options)
if demangled := demangle.Filter(fn.SystemName, o...); demangled != fn.SystemName {
if demangled := demangle.Filter(fn.SystemName, opts...); demangled != fn.SystemName {
fn.Name = demangled
return
}
@ -296,7 +293,7 @@ func demangleSingleFunction(fn *profile.Function, options []demangle.Option) {
// OSX has all the symbols prefixed with extra '_' so lets try
// once more without it
if strings.HasPrefix(fn.SystemName, "_") {
if demangled := demangle.Filter(fn.SystemName[1:], o...); demangled != fn.SystemName {
if demangled := demangle.Filter(fn.SystemName[1:], opts...); demangled != fn.SystemName[1:] {
fn.Name = demangled
return
}
@ -306,7 +303,7 @@ func demangleSingleFunction(fn *profile.Function, options []demangle.Option) {
// already demangled.
name := fn.SystemName
if looksLikeDemangledCPlusPlus(name) {
for _, o := range options {
for _, o := range opts {
switch o {
case demangle.NoParams:
name = removeMatching(name, '(', ')')

View file

@ -17,6 +17,7 @@ package profile
import (
"encoding/binary"
"fmt"
"slices"
"sort"
"strconv"
"strings"
@ -78,12 +79,10 @@ func Merge(srcs []*Profile) (*Profile, error) {
}
}
for _, s := range p.Sample {
if isZeroSample(s) {
// If there are any zero samples, re-merge the profile to GC
// them.
return Merge([]*Profile{p})
}
if slices.ContainsFunc(p.Sample, isZeroSample) {
// If there are any zero samples, re-merge the profile to GC
// them.
return Merge([]*Profile{p})
}
return p, nil

View file

@ -24,6 +24,7 @@ import (
"math"
"path/filepath"
"regexp"
"slices"
"sort"
"strings"
"sync"
@ -734,12 +735,7 @@ func (p *Profile) RemoveLabel(key string) {
// HasLabel returns true if a sample has a label with indicated key and value.
func (s *Sample) HasLabel(key, value string) bool {
for _, v := range s.Label[key] {
if v == value {
return true
}
}
return false
return slices.Contains(s.Label[key], value)
}
// SetNumLabel sets the specified key to the specified value for all samples in the
@ -852,7 +848,17 @@ func (p *Profile) HasFileLines() bool {
// "[vdso]", "[vsyscall]" and some others, see the code.
func (m *Mapping) Unsymbolizable() bool {
name := filepath.Base(m.File)
return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/") || m.File == "//anon"
switch {
case strings.HasPrefix(name, "["):
case strings.HasPrefix(name, "linux-vdso"):
case strings.HasPrefix(m.File, "/dev/dri/"):
case m.File == "//anon":
case m.File == "":
case strings.HasPrefix(m.File, "/memfd:"):
default:
return false
}
return true
}
// Copy makes a fully independent copy of a profile.

View file

@ -19,6 +19,7 @@ package profile
import (
"fmt"
"regexp"
"slices"
"strings"
)
@ -40,13 +41,7 @@ func simplifyFunc(f string) string {
// Account for unsimplified names -- try to remove the argument list by trimming
// starting from the first '(', but skipping reserved names that have '('.
for _, ind := range bracketRx.FindAllStringSubmatchIndex(funcName, -1) {
foundReserved := false
for _, res := range reservedNames {
if funcName[ind[0]:ind[1]] == res {
foundReserved = true
break
}
}
foundReserved := slices.Contains(reservedNames, funcName[ind[0]:ind[1]])
if !foundReserved {
funcName = funcName[:ind[0]]
break

View file

@ -3,7 +3,7 @@
* ======================
*
* Given an unique existing element with id "viewport" (or when missing, the
* first g-element), including the the library into any SVG adds the following
* first g-element), including the library into any SVG adds the following
* capabilities:
*
* - Mouse panning

View file

@ -186,7 +186,7 @@ func ToAST(name string, options ...Option) (AST, error) {
i := 0
for i < len(options) {
if options[i] == NoParams {
options = append(options[:i], options[i+1:]...)
options = append(options[:i:i], options[i+1:]...)
} else {
i++
}

View file

@ -1,5 +1,5 @@
# github.com/google/pprof v0.0.0-20250208200701-d0013a598941
## explicit; go 1.22
# github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5
## explicit; go 1.23.0
github.com/google/pprof/driver
github.com/google/pprof/internal/binutils
github.com/google/pprof/internal/driver
@ -13,7 +13,7 @@ github.com/google/pprof/internal/symbolz
github.com/google/pprof/internal/transport
github.com/google/pprof/profile
github.com/google/pprof/third_party/svgpan
# github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd
# github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b
## explicit; go 1.13
github.com/ianlancetaylor/demangle
# golang.org/x/arch v0.20.1-0.20250808194827-46ba08e3ae58