/
memplot.go
111 lines (97 loc) · 2.79 KB
/
memplot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package main
import (
"flag"
"fmt"
"github.com/0x0f0f0f/memplot"
"gonum.org/v1/plot/vg"
"os"
"os/exec"
"time"
)
// Simply panic on error
func check(err error) {
if err != nil {
panic(err)
}
}
// Simply exit on error
func checke(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
}
func main() {
opts := memplot.PlotOptions{
PlotRss: true,
PlotVsz: false,
}
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
fmt.Fprintf(os.Stderr, "Arguments following options will be"+
" interpreted as the command to spawn and sample\n")
flag.PrintDefaults()
}
// Default sample duration time
defaultSd, err := time.ParseDuration("5ms")
check(err)
// Total sampling time
defaultDur, err := time.ParseDuration("0s")
check(err)
defaultFilename := "output-plot.png"
pidPtr := flag.Int("pid", -1, "pid of the process to analyze")
filenamePtr := flag.String("o", defaultFilename, "output image file name. "+
"supported extensions are:\n.eps, .jpg, .jpeg, .pdf, "+
".png, .svg, .tex, .tif and .tiff\n")
sdPtr := flag.Duration("sd", defaultSd, "sample size in time")
durPtr := flag.Duration("dur", defaultDur, "total profiling time. a value of 0 means"+
" that the program\nwill be sampled until it is no longer running")
// To plot or not VSZ
flag.BoolVar(&opts.PlotVsz, "vsz", false, "plot virtual size")
widthStr := flag.String("width", "16cm", "plot image width (can be cm or in)")
heightStr := flag.String("height", "12cm", "plot image height (can be cm or in)")
flag.Parse()
// Parse the image size
widthImage, err := vg.ParseLength(*widthStr)
checke(err)
heightImage, err := vg.ParseLength(*heightStr)
checke(err)
// Run the PID passed with the -pid flag or the arguments following options
if *pidPtr <= 0 {
args := flag.Args()
if len(args) == 0 {
fmt.Fprintf(os.Stderr,
"Invalid PID. Please specify PID using -pid flag"+
" or specify a command to exec and sample\n")
flag.Usage()
os.Exit(1)
}
pidChan := make(chan int, 1)
go func() {
cmd := exec.Command(args[0], args[1:]...)
err := cmd.Start()
check(err)
pidChan <- cmd.Process.Pid
err = cmd.Wait()
check(err)
}()
*pidPtr = <-pidChan
} else {
if len(flag.Args()) > 0 {
fmt.Println("A pid was specified. Ignoring additional arguments")
}
}
// Create and sample
fmt.Fprintln(os.Stderr, "Collecting data from PID", *pidPtr, "...")
if *durPtr == 0 {
fmt.Fprintln(os.Stderr, "Warning: sampling will continue"+
"until program is no longer running")
}
coll, err := memplot.NewCollection(int32(*pidPtr), *sdPtr, *durPtr)
check(err)
fmt.Fprintln(os.Stderr, "Generating plot...")
plot, err := coll.Plot(opts)
check(err)
fmt.Fprintln(os.Stderr, "Saving plot..")
memplot.SavePlot(plot, widthImage, heightImage, *filenamePtr)
}