Beispiel #1
0
// locateFile opens a local file for symbolization on the search path
// at $PPROF_BINARY_PATH. Looks inside these directories for files
// named $BUILDID/$BASENAME and $BASENAME (if build id is available).
func locateFile(obj plugin.ObjTool, file, buildID string, start uint64) (plugin.ObjFile, error) {
	// 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")
	}

	// Collect names to search: {buildid/basename, basename}
	var fileNames []string
	if baseName := filepath.Base(file); buildID != "" {
		fileNames = []string{filepath.Join(buildID, baseName), baseName}
	} else {
		fileNames = []string{baseName}
	}
	for _, path := range filepath.SplitList(searchPath) {
		for nameIndex, name := range fileNames {
			file := filepath.Join(path, name)
			if f, err := obj.Open(file, start); err == nil {
				fileBuildID := f.BuildID()
				if buildID == "" || buildID == fileBuildID {
					return f, nil
				}
				f.Close()
				if nameIndex == 0 {
					// If this is the first name, the path includes the build id. Report inconsistency.
					return nil, fmt.Errorf("found file %s with inconsistent build id %s", file, fileBuildID)
				}
			}
		}
	}
	// Try original file name
	f, err := obj.Open(file, start)
	if err == nil && buildID != "" {
		if fileBuildID := f.BuildID(); fileBuildID != "" && fileBuildID != buildID {
			// Mismatched build IDs, ignore
			f.Close()
			return nil, fmt.Errorf("mismatched build ids %s != %s", fileBuildID, buildID)
		}
	}
	return f, err
}
Beispiel #2
0
// PProf acquires a profile, and symbolizes it using a profile
// manager. Then it generates a report formatted according to the
// options selected through the flags package.
func PProf(flagset plugin.FlagSet, fetch plugin.Fetcher, sym plugin.Symbolizer, obj plugin.ObjTool, ui plugin.UI, overrides commands.Commands) error {
	// Remove any temporary files created during pprof processing.
	defer tempfile.Cleanup()

	f, err := getFlags(flagset, overrides, ui)
	if err != nil {
		return err
	}

	obj.SetConfig(*f.flagTools)

	sources := f.profileSource
	if len(sources) > 1 {
		source := sources[0]
		// If the first argument is a supported object file, treat as executable.
		if file, err := obj.Open(source, 0); err == nil {
			file.Close()
			f.profileExecName = source
			sources = sources[1:]
		} else if *f.flagBuildID == "" && isBuildID(source) {
			f.flagBuildID = &source
			sources = sources[1:]
		}
	}

	// errMu protects concurrent accesses to errset and err. errset is set if an
	// error is encountered by one of the goroutines grabbing a profile.
	errMu, errset := sync.Mutex{}, false

	// Fetch profiles.
	wg := sync.WaitGroup{}
	profs := make([]*profile.Profile, len(sources))
	for i, source := range sources {
		wg.Add(1)
		go func(i int, src string) {
			defer wg.Done()
			p, grabErr := grabProfile(src, f.profileExecName, *f.flagBuildID, fetch, sym, obj, ui, f)
			if grabErr != nil {
				errMu.Lock()
				defer errMu.Unlock()
				errset, err = true, grabErr
				return
			}
			profs[i] = p
		}(i, source)
	}
	wg.Wait()
	if errset {
		return err
	}

	// Merge profiles.
	prof := profs[0]
	for _, p := range profs[1:] {
		if err = prof.Merge(p, 1); err != nil {
			return err
		}
	}

	if *f.flagBase != "" {
		// Fetch base profile and subtract from current profile.
		base, err := grabProfile(*f.flagBase, f.profileExecName, *f.flagBuildID, fetch, sym, obj, ui, f)
		if err != nil {
			return err
		}

		if err = prof.Merge(base, -1); err != nil {
			return err
		}
	}

	if err := processFlags(prof, ui, f); err != nil {
		return err
	}

	if !*f.flagRuntime {
		prof.RemoveUninteresting()
	}

	if *f.flagInteractive {
		return interactive(prof, obj, ui, f)
	}

	return generate(false, prof, obj, ui, f)
}