Exemple #1
0
// commandHelp displays help and usage information for all Commands
// and Variables or a specific Command or Variable.
func commandHelp(args string, ui plugin.UI) {
	if args == "" {
		help := usage(false)
		help = help + `
  :   Clear focus/ignore/hide/tagfocus/tagignore

  type "help <cmd|option>" for more information
`

		ui.Print(help)
		return
	}

	if c := pprofCommands[args]; c != nil {
		ui.Print(c.help(args))
		return
	}

	if v := pprofVariables[args]; v != nil {
		ui.Print(v.help + "\n")
		return
	}

	ui.PrintErr("Unknown command: " + args)
}
Exemple #2
0
func sampleIndex(flag *bool, si string, sampleType, option string, ui plugin.UI) string {
	if *flag {
		if si == "" {
			return sampleType
		}
		ui.PrintErr("Multiple value selections, ignoring ", option)
	}
	return si
}
Exemple #3
0
// setTmpDir prepares the directory to use to save profiles retrieved
// remotely. It is selected from PPROF_TMPDIR, defaults to $HOME/pprof.
func setTmpDir(ui plugin.UI) (string, error) {
	if profileDir := os.Getenv("PPROF_TMPDIR"); profileDir != "" {
		return profileDir, nil
	}
	for _, tmpDir := range []string{os.Getenv("HOME") + "/pprof", os.TempDir()} {
		if err := os.MkdirAll(tmpDir, 0755); err != nil {
			ui.PrintErr("Could not use temp dir ", tmpDir, ": ", err.Error())
			continue
		}
		return tmpDir, nil
	}
	return "", fmt.Errorf("failed to identify temp dir")
}
Exemple #4
0
// locateBinaries searches for binary files listed in the profile and, if found,
// updates the profile accordingly.
func locateBinaries(p *profile.Profile, s *source, obj plugin.ObjTool, ui plugin.UI) {
	// Construct search path to examine
	searchPath := os.Getenv("PPROF_BINARY_PATH")
	if searchPath == "" {
		// Use $HOME/pprof/binaries as default directory for local symbolization binaries
		searchPath = filepath.Join(os.Getenv("HOME"), "pprof", "binaries")
	}

mapping:
	for i, m := range p.Mapping {
		var baseName string
		// Replace executable filename/buildID with the overrides from source.
		// Assumes the executable is the first Mapping entry.
		if i == 0 {
			if s.ExecName != "" {
				m.File = s.ExecName
			}
			if s.BuildID != "" {
				m.BuildID = s.BuildID
			}
		}
		if m.File != "" {
			baseName = filepath.Base(m.File)
		}

		for _, path := range filepath.SplitList(searchPath) {
			var fileNames []string
			if m.BuildID != "" {
				fileNames = []string{filepath.Join(path, m.BuildID, baseName)}
				if matches, err := filepath.Glob(filepath.Join(path, m.BuildID, "*")); err == nil {
					fileNames = append(fileNames, matches...)
				}
			}
			if baseName != "" {
				fileNames = append(fileNames, filepath.Join(path, baseName))
			}
			for _, name := range fileNames {
				if f, err := obj.Open(name, m.Start, m.Limit, m.Offset); err == nil {
					defer f.Close()
					fileBuildID := f.BuildID()
					if m.BuildID != "" && m.BuildID != fileBuildID {
						ui.PrintErr("Ignoring local file " + name + ": build-id mismatch (" + m.BuildID + " != " + fileBuildID + ")")
					} else {
						m.File = name
						continue mapping
					}
				}
			}
		}
	}
}
Exemple #5
0
// newMapping creates a mappingTable for a profile.
func newMapping(prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, force bool) (*mappingTable, error) {
	mt := &mappingTable{
		prof:     prof,
		segments: make(map[*profile.Mapping]plugin.ObjFile),
	}

	// Identify used mappings
	mappings := make(map[*profile.Mapping]bool)
	for _, l := range prof.Location {
		mappings[l.Mapping] = true
	}

	for _, m := range prof.Mapping {
		if !mappings[m] {
			continue
		}

		// Do not attempt to re-symbolize a mapping that has already been symbolized.
		if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) {
			continue
		}

		// Skip well-known system mappings
		name := filepath.Base(m.File)
		if name == "" || name == "[vdso]" || strings.HasPrefix(name, "linux-vdso") {
			continue
		}

		f, err := obj.Open(m.File, m.Start, m.Limit, m.Offset)
		if err != nil {
			ui.PrintErr("Local symbolization failed for ", name, ": ", err)
			continue
		}
		if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
			ui.PrintErr("Local symbolization failed for ", name, ": build ID mismatch")
			f.Close()
			continue
		}

		mt.segments[m] = f
	}

	return mt, nil
}
func compileTagFilter(name, value string, ui plugin.UI, err error) (func(*profile.Sample) bool, error) {
	if value == "" || err != nil {
		return nil, err
	}
	if numFilter := parseTagFilterRange(value); numFilter != nil {
		ui.PrintErr(name, ":Interpreted '", value, "' as range, not regexp")
		return func(s *profile.Sample) bool {
			for key, vals := range s.NumLabel {
				for _, val := range vals {
					if numFilter(val, key) {
						return true
					}
				}
			}
			return false
		}, nil
	}
	var rfx []*regexp.Regexp
	for _, tagf := range strings.Split(value, ",") {
		fx, err := regexp.Compile(tagf)
		if err != nil {
			return nil, fmt.Errorf("parsing %s regexp: %v", name, err)
		}
		rfx = append(rfx, fx)
	}
	return func(s *profile.Sample) bool {
	matchedrx:
		for _, rx := range rfx {
			for key, vals := range s.Label {
				for _, val := range vals {
					if rx.MatchString(key + ":" + val) {
						continue matchedrx
					}
				}
			}
			return false
		}
		return true
	}, nil
}
Exemple #7
0
// concurrentGrab fetches multiple profiles concurrently
func concurrentGrab(sources []profileSource, fetch plugin.Fetcher, obj plugin.ObjTool, ui plugin.UI) (*profile.Profile, plugin.MappingSources, bool, int, error) {
	wg := sync.WaitGroup{}
	wg.Add(len(sources))
	for i := range sources {
		go func(s *profileSource) {
			defer wg.Done()
			s.p, s.msrc, s.remote, s.err = grabProfile(s.source, s.addr, s.scale, fetch, obj, ui)
		}(&sources[i])
	}
	wg.Wait()

	var save bool
	profiles := make([]*profile.Profile, 0, len(sources))
	msrcs := make([]plugin.MappingSources, 0, len(sources))
	for i := range sources {
		s := &sources[i]
		if err := s.err; err != nil {
			ui.PrintErr(s.addr + ": " + err.Error())
			continue
		}
		save = save || s.remote
		profiles = append(profiles, s.p)
		msrcs = append(msrcs, s.msrc)
		*s = profileSource{}
	}

	if len(profiles) == 0 {
		return nil, nil, false, 0, nil
	}

	p, msrc, err := combineProfiles(profiles, msrcs)
	if err != nil {
		return nil, nil, false, 0, err
	}
	return p, msrc, save, len(profiles), nil
}
func warnNoMatches(match bool, option string, ui plugin.UI) {
	if !match {
		ui.PrintErr(option + " expression matched no samples")
	}
}
Exemple #9
0
// newMapping creates a mappingTable for a profile.
func newMapping(prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, force bool) (*mappingTable, error) {
	mt := &mappingTable{
		prof:     prof,
		segments: make(map[*profile.Mapping]plugin.ObjFile),
	}

	// Identify used mappings
	mappings := make(map[*profile.Mapping]bool)
	for _, l := range prof.Location {
		mappings[l.Mapping] = true
	}

	missingBinaries := false
	for midx, m := range prof.Mapping {
		if !mappings[m] {
			continue
		}

		// Do not attempt to re-symbolize a mapping that has already been symbolized.
		if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) {
			continue
		}

		if m.File == "" {
			if midx == 0 {
				ui.PrintErr("Main binary filename not available.\n" +
					"Try passing the path to the main binary before the profile.")
				continue
			}
			missingBinaries = true
			continue
		}

		// Skip well-known system mappings
		name := filepath.Base(m.File)
		if name == "[vdso]" || strings.HasPrefix(name, "linux-vdso") {
			continue
		}

		// Skip mappings pointing to a source URL
		if m.BuildID == "" {
			if u, err := url.Parse(m.File); err == nil && u.IsAbs() {
				continue
			}
		}

		f, err := obj.Open(m.File, m.Start, m.Limit, m.Offset)
		if err != nil {
			ui.PrintErr("Local symbolization failed for ", name, ": ", err)
			continue
		}
		if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
			ui.PrintErr("Local symbolization failed for ", name, ": build ID mismatch")
			f.Close()
			continue
		}

		mt.segments[m] = f
	}
	if missingBinaries {
		ui.PrintErr("Some binary filenames not available. Symbolization may be incomplete.")
	}
	return mt, nil
}
Exemple #10
0
// concurrentGrab fetches multiple profiles concurrently
func concurrentGrab(s *source, fetch plugin.Fetcher, obj plugin.ObjTool, ui plugin.UI) (*profile.Profile, plugin.MappingSources, bool, error) {
	wg := sync.WaitGroup{}
	numprofs := len(s.Sources) + len(s.Base)
	profs := make([]*profile.Profile, numprofs)
	msrcs := make([]plugin.MappingSources, numprofs)
	remote := make([]bool, numprofs)
	errs := make([]error, numprofs)
	for i, source := range s.Sources {
		wg.Add(1)
		go func(i int, src string) {
			defer wg.Done()
			profs[i], msrcs[i], remote[i], errs[i] = grabProfile(s, src, 1, fetch, obj, ui)
		}(i, source)
	}
	for i, source := range s.Base {
		wg.Add(1)
		go func(i int, src string) {
			defer wg.Done()
			profs[i], msrcs[i], remote[i], errs[i] = grabProfile(s, src, -1, fetch, obj, ui)
		}(i+len(s.Sources), source)
	}
	wg.Wait()
	var save bool
	var numFailed = 0
	for i, src := range s.Sources {
		if errs[i] != nil {
			ui.PrintErr(src + ": " + errs[i].Error())
			numFailed++
		}
		save = save || remote[i]
	}
	for i, src := range s.Base {
		b := i + len(s.Sources)
		if errs[b] != nil {
			ui.PrintErr(src + ": " + errs[b].Error())
			numFailed++
		}
		save = save || remote[b]
	}
	if numFailed == numprofs {
		return nil, nil, false, fmt.Errorf("failed to fetch any profiles")
	}
	if numFailed > 0 {
		ui.PrintErr(fmt.Sprintf("fetched %d profiles out of %d", numprofs-numFailed, numprofs))
	}

	scaled := make([]*profile.Profile, 0, numprofs)
	for _, p := range profs {
		if p != nil {
			scaled = append(scaled, p)
		}
	}

	// Merge profiles.
	if err := measurement.ScaleProfiles(scaled); err != nil {
		return nil, nil, false, err
	}

	p, err := profile.Merge(scaled)
	if err != nil {
		return nil, nil, false, err
	}

	// Combine mapping sources.
	msrc := make(plugin.MappingSources)
	for _, ms := range msrcs {
		for m, s := range ms {
			msrc[m] = append(msrc[m], s...)
		}
	}

	return p, msrc, save, nil
}