Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(358)

Delta Between Two Patch Sets: src/cmd/pprof/internal/commands/commands.go

Issue 153750043: code review 153750043: cmd/pprof: add Go implementation (Closed)
Left Patch Set: Created 9 years, 6 months ago
Right Patch Set: diff -r 2e467bc60e64def06419194f48fe0d6c8b56765d https://code.google.com/p/go/ Created 9 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | src/cmd/pprof/internal/driver/driver.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package commands defines and manages the basic pprof commands
6 package commands
7
8 import (
9 "bytes"
10 "fmt"
11 "io"
12 "os"
13 "os/exec"
14 "strings"
15
16 "cmd/pprof/internal/plugin"
17 "cmd/pprof/internal/report"
18 "cmd/pprof/internal/svg"
19 "cmd/pprof/internal/tempfile"
20 )
21
22 // Commands describes the commands accepted by pprof.
23 type Commands map[string]*Command
24
25 // Command describes the actions for a pprof command. Includes a
26 // function for command-line completion, the report format to use
27 // during report generation, any postprocessing functions, and whether
28 // the command expects a regexp parameter (typically a function name).
29 type Command struct {
30 Complete Completer // autocomplete for interactive mode
31 Format int // report format to generate
32 PostProcess PostProcessor // postprocessing to run on report
33 HasParam bool // Collect a parameter from the CLI
34 Usage string // Help text
35 }
36
37 // Completer is a function for command-line autocompletion
38 type Completer func(prefix string) string
39
40 // PostProcessor is a function that applies post-processing to the report output
41 type PostProcessor func(input *bytes.Buffer, output io.Writer, ui plugin.UI) err or
42
43 // PProf returns the basic pprof report-generation commands
44 func PProf(c Completer, interactive **bool, svgpan **string) Commands {
45 return Commands{
46 // Commands that require no post-processing.
47 "tags": {nil, report.Tags, nil, false, "Outputs all tags in th e profile"},
48 "raw": {c, report.Raw, nil, false, "Outputs a text representa tion of the raw profile"},
49 "dot": {c, report.Dot, nil, false, "Outputs a graph in DOT fo rmat"},
50 "top": {c, report.Text, nil, false, "Outputs top entries in t ext form"},
51 "tree": {c, report.Tree, nil, false, "Outputs a text rendering of call graph"},
52 "text": {c, report.Text, nil, false, "Outputs top entries in t ext form"},
53 "disasm": {c, report.Dis, nil, true, "Output annotated assembly for functions matching regexp or address"},
54 "list": {c, report.List, nil, true, "Output annotated source f or functions matching regexp"},
55 "peek": {c, report.Tree, nil, true, "Output callers/callees of functions matching regexp"},
56
57 // Save binary formats to a file
58 "callgrind": {c, report.Callgrind, awayFromTTY("callgraph.out"), false, "Outputs a graph in callgrind format"},
59 "proto": {c, report.Proto, awayFromTTY("pb.gz"), false, "Out puts the profile in compressed protobuf format"},
60
61 // Generate report in DOT format and postprocess with dot
62 "gif": {c, report.Dot, invokeDot("gif"), false, "Outputs a graph image in GIF format"},
63 "pdf": {c, report.Dot, invokeDot("pdf"), false, "Outputs a graph in PDF format"},
64 "png": {c, report.Dot, invokeDot("png"), false, "Outputs a graph image in PNG format"},
65 "ps": {c, report.Dot, invokeDot("ps"), false, "Outputs a graph in PS format"},
66
67 // Save SVG output into a file after including svgpan library
68 "svg": {c, report.Dot, saveSVGToFile(svgpan), false, "Outputs a graph in SVG format"},
69
70 // Visualize postprocessed dot output
71 "eog": {c, report.Dot, invokeVisualizer(interactive, invokeDo t("svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"},
72 "evince": {c, report.Dot, invokeVisualizer(interactive, invokeDo t("pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"},
73 "gv": {c, report.Dot, invokeVisualizer(interactive, invokeDo t("ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv "},
74 "web": {c, report.Dot, invokeVisualizer(interactive, saveSVGT oFile(svgpan), "svg", browsers), false, "Visualize graph through web browser"},
75
76 // Visualize HTML directly generated by report.
77 "weblist": {c, report.WebList, invokeVisualizer(interactive, awa yFromTTY("html"), "html", browsers), true, "Output annotated source in HTML for functions matching regexp or address"},
78 }
79 }
80
81 // List of web browsers to attempt for web visualization
82 var browsers = []string{"chrome", "google-chrome", "firefox", "/usr/bin/open"}
83
84 // NewCompleter creates an autocompletion function for a set of commands.
85 func NewCompleter(cs Commands) Completer {
86 return func(line string) string {
87 switch tokens := strings.Fields(line); len(tokens) {
88 case 0:
89 // Nothing to complete
90 case 1:
91 // Single token -- complete command name
92 found := ""
93 for c := range cs {
94 if strings.HasPrefix(c, tokens[0]) {
95 if found != "" {
96 return line
97 }
98 found = c
99 }
100 }
101 if found != "" {
102 return found
103 }
104 default:
105 // Multiple tokens -- complete using command completer
106 if c, ok := cs[tokens[0]]; ok {
107 if c.Complete != nil {
108 lastTokenIdx := len(tokens) - 1
109 lastToken := tokens[lastTokenIdx]
110 if strings.HasPrefix(lastToken, "-") {
111 lastToken = "-" + c.Complete(las tToken[1:])
112 } else {
113 lastToken = c.Complete(lastToken )
114 }
115 return strings.Join(append(tokens[:lastT okenIdx], lastToken), " ")
116 }
117 }
118 }
119 return line
120 }
121 }
122
123 // awayFromTTY saves the output in a file if it would otherwise go to
124 // the terminal screen. This is used to avoid dumping binary data on
125 // the screen.
126 func awayFromTTY(format string) PostProcessor {
127 return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
128 if output == os.Stdout && ui.IsTerminal() {
129 tempFile, err := tempfile.New("", "profile", "."+format)
130 if err != nil {
131 return err
132 }
133 ui.PrintErr("Generating report in ", tempFile.Name())
134 _, err = fmt.Fprint(tempFile, input)
135 return err
136 }
137 _, err := fmt.Fprint(output, input)
138 return err
139 }
140 }
141
142 func invokeDot(format string) PostProcessor {
143 divert := awayFromTTY(format)
144 return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
145 cmd := exec.Command("dot", "-T"+format)
146 var buf bytes.Buffer
147 cmd.Stdin, cmd.Stdout, cmd.Stderr = input, &buf, os.Stderr
148 if err := cmd.Run(); err != nil {
149 return err
150 }
151 return divert(&buf, output, ui)
152 }
153 }
154
155 func saveSVGToFile(svgpan **string) PostProcessor {
156 generateSVG := invokeDot("svg")
157 divert := awayFromTTY("svg")
158 return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
159 baseSVG := &bytes.Buffer{}
160 generateSVG(input, baseSVG, ui)
161 massaged := &bytes.Buffer{}
162 fmt.Fprint(massaged, svg.Massage(*baseSVG, **svgpan))
163 return divert(massaged, output, ui)
164 }
165 }
166
167 func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, v isualizers []string) PostProcessor {
168 return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
169 tempFile, err := tempfile.New(os.Getenv("PPROF_TMPDIR"), "pprof" , "."+suffix)
170 if err != nil {
171 return err
172 }
173 tempfile.DeferDelete(tempFile.Name())
174 if err = format(input, tempFile, ui); err != nil {
175 return err
176 }
177 // Try visualizers until one is successful
178 for _, v := range visualizers {
179 // Separate command and arguments for exec.Command.
180 args := strings.Split(v, " ")
181 if len(args) == 0 {
182 continue
183 }
184 viewer := exec.Command(args[0], append(args[1:], tempFil e.Name())...)
185 viewer.Stderr = os.Stderr
186 if err = viewer.Start(); err == nil {
187 if !**interactive {
188 // In command-line mode, wait for the vi ewer to be closed
189 // before proceeding
190 return viewer.Wait()
191 }
192 return nil
193 }
194 }
195 return err
196 }
197 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b