Exemple #1
0
func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, visualizers []string) PostProcessor {
	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
		tempFile, err := tempfile.New(os.Getenv("PPROF_TMPDIR"), "pprof", "."+suffix)
		if err != nil {
			return err
		}
		tempfile.DeferDelete(tempFile.Name())
		if err = format(input, tempFile, ui); err != nil {
			return err
		}
		// Try visualizers until one is successful
		for _, v := range visualizers {
			// Separate command and arguments for exec.Command.
			args := strings.Split(v, " ")
			if len(args) == 0 {
				continue
			}
			viewer := exec.Command(args[0], append(args[1:], tempFile.Name())...)
			viewer.Stderr = os.Stderr
			if err = viewer.Start(); err == nil {
				if !**interactive {
					// In command-line mode, wait for the viewer to be closed
					// before proceeding
					return viewer.Wait()
				}
				return nil
			}
		}
		return err
	}
}
Exemple #2
0
// awayFromTTY saves the output in a file if it would otherwise go to
// the terminal screen. This is used to avoid dumping binary data on
// the screen.
func awayFromTTY(format string) PostProcessor {
	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
		if output == os.Stdout && ui.IsTerminal() {
			tempFile, err := tempfile.New("", "profile", "."+format)
			if err != nil {
				return err
			}
			ui.PrintErr("Generating report in ", tempFile.Name())
			_, err = fmt.Fprint(tempFile, input)
			return err
		}
		_, err := fmt.Fprint(output, input)
		return err
	}
}
Exemple #3
0
// grabProfile fetches and symbolizes a profile.
func grabProfile(source, exec, buildid string, fetch plugin.Fetcher, sym plugin.Symbolizer, obj plugin.ObjTool, ui plugin.UI, f *flags) (*profile.Profile, error) {
	source, host, duration := adjustURL(source, *f.flagSeconds, ui)
	remote := host != ""

	if remote {
		ui.Print("Fetching profile from ", source)
		if duration != 0 {
			ui.Print("Please wait... (" + duration.String() + ")")
		}
	}

	now := time.Now()
	// Fetch profile from source.
	// Give 50% slack on the timeout.
	p, err := fetch(source, duration+duration/2, ui)
	if err != nil {
		return nil, err
	}

	// Update the time/duration if the profile source doesn't include it.
	// TODO(rsilvera): Remove this when we remove support for legacy profiles.
	if remote {
		if p.TimeNanos == 0 {
			p.TimeNanos = now.UnixNano()
		}
		if duration != 0 && p.DurationNanos == 0 {
			p.DurationNanos = int64(duration)
		}
	}

	// Replace executable/buildID with the options provided in the
	// command line. Assume the executable is the first Mapping entry.
	if exec != "" || buildid != "" {
		if len(p.Mapping) == 0 {
			// Create a fake mapping to hold the user option, and associate
			// all samples to it.
			m := &profile.Mapping{
				ID: 1,
			}
			for _, l := range p.Location {
				l.Mapping = m
			}
			p.Mapping = []*profile.Mapping{m}
		}
		if exec != "" {
			p.Mapping[0].File = exec
		}
		if buildid != "" {
			p.Mapping[0].BuildID = buildid
		}
	}

	if err := sym(*f.flagSymbolize, source, p, obj, ui); err != nil {
		return nil, err
	}

	// Save a copy of any remote profiles, unless the user is explicitly
	// saving it.
	if remote && !f.isFormat("proto") {
		prefix := "pprof."
		if len(p.Mapping) > 0 && p.Mapping[0].File != "" {
			prefix = prefix + filepath.Base(p.Mapping[0].File) + "."
		}
		if !strings.ContainsRune(host, os.PathSeparator) {
			prefix = prefix + host + "."
		}
		for _, s := range p.SampleType {
			prefix = prefix + s.Type + "."
		}

		dir := os.Getenv("PPROF_TMPDIR")
		tempFile, err := tempfile.New(dir, prefix, ".pb.gz")
		if err == nil {
			if err = p.Write(tempFile); err == nil {
				ui.PrintErr("Saved profile in ", tempFile.Name())
			}
		}
		if err != nil {
			ui.PrintErr("Could not save profile: ", err)
		}
	}

	if err := p.Demangle(obj.Demangle); err != nil {
		ui.PrintErr("Failed to demangle profile: ", err)
	}

	if err := p.CheckValid(); err != nil {
		return nil, fmt.Errorf("Grab %s: %v", source, err)
	}

	return p, nil
}