perfmonger 0.10.2 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.travis.yml +9 -8
  4. data/HOWTO.md +0 -1
  5. data/NEWS +49 -5
  6. data/README.md +77 -27
  7. data/Rakefile +33 -11
  8. data/core/Makefile +22 -31
  9. data/core/build.sh +6 -8
  10. data/core/cmd/perfmonger-player/perfmonger-player.go +247 -0
  11. data/core/{perfmonger-plot-formatter.go → cmd/perfmonger-plot-formatter/perfmonger-plot-formatter.go} +20 -5
  12. data/core/{perfmonger-recorder.go → cmd/perfmonger-recorder/perfmonger-recorder.go} +22 -2
  13. data/core/{perfmonger-summarizer.go → cmd/perfmonger-summarizer/perfmonger-summarizer.go} +22 -15
  14. data/core/cmd/perfmonger-viewer/perfmonger-viewer.go +164 -0
  15. data/core/go.mod +10 -0
  16. data/core/go.sum +17 -0
  17. data/core/subsystem/Makefile +4 -0
  18. data/core/subsystem/perfmonger_linux.go +95 -0
  19. data/core/subsystem/perfmonger_linux_test.go +40 -0
  20. data/core/subsystem/stat.go +70 -0
  21. data/core/subsystem/stat_test.go +9 -0
  22. data/core/subsystem/usage.go +223 -66
  23. data/core/subsystem/usage_test.go +62 -32
  24. data/core/utils.go +2 -2
  25. data/{bin → exe}/perfmonger +0 -0
  26. data/lib/exec/perfmonger-player_darwin_amd64 +0 -0
  27. data/lib/exec/perfmonger-player_linux_amd64 +0 -0
  28. data/lib/exec/perfmonger-plot-formatter_darwin_amd64 +0 -0
  29. data/lib/exec/perfmonger-plot-formatter_linux_amd64 +0 -0
  30. data/lib/exec/perfmonger-recorder_darwin_amd64 +0 -0
  31. data/lib/exec/perfmonger-recorder_linux_amd64 +0 -0
  32. data/lib/exec/perfmonger-summarizer_darwin_amd64 +0 -0
  33. data/lib/exec/perfmonger-summarizer_linux_amd64 +0 -0
  34. data/lib/exec/perfmonger-viewer_darwin_amd64 +0 -0
  35. data/lib/exec/perfmonger-viewer_linux_amd64 +0 -0
  36. data/lib/perfmonger/command/fingerprint.rb +26 -1
  37. data/lib/perfmonger/command/live.rb +19 -0
  38. data/lib/perfmonger/command/play.rb +16 -0
  39. data/lib/perfmonger/command/plot.rb +23 -9
  40. data/lib/perfmonger/command/record.rb +24 -3
  41. data/lib/perfmonger/command/record_option.rb +16 -0
  42. data/lib/perfmonger/command/server.rb +1 -1
  43. data/lib/perfmonger/version.rb +1 -1
  44. data/misc/werker-box/Dockerfile +34 -0
  45. data/misc/werker-box/build-push.sh +7 -0
  46. data/perfmonger.gemspec +2 -1
  47. data/spec/data/busy100.pgr.played +3 -3
  48. data/spec/fingerprint_spec.rb +1 -1
  49. data/spec/live_spec.rb +2 -3
  50. data/spec/perfmonger_spec.rb +1 -1
  51. data/spec/play_spec.rb +1 -1
  52. data/spec/plot_spec.rb +16 -1
  53. data/spec/record_spec.rb +10 -1
  54. data/spec/spec_helper.rb +28 -3
  55. data/spec/stat_spec.rb +2 -2
  56. data/spec/summary_spec.rb +1 -1
  57. data/wercker.yml +29 -16
  58. metadata +34 -14
  59. data/core/perfmonger-player.go +0 -196
  60. data/lib/exec/perfmonger-player_linux_386 +0 -0
  61. data/lib/exec/perfmonger-plot-formatter_linux_386 +0 -0
  62. data/lib/exec/perfmonger-recorder_linux_386 +0 -0
  63. data/lib/exec/perfmonger-summarizer_linux_386 +0 -0
@@ -0,0 +1,247 @@
1
+ //usr/bin/env go run $0 $@ ; exit
2
+
3
+ package main
4
+
5
+ import (
6
+ "bufio"
7
+ "encoding/gob"
8
+ "flag"
9
+ "fmt"
10
+ "io"
11
+ "os"
12
+
13
+ projson "github.com/hayamiz/go-projson"
14
+ ss "github.com/hayamiz/perfmonger/core/subsystem"
15
+ core "github.com/hayamiz/perfmonger/core"
16
+ )
17
+
18
+ type PlayerOption struct {
19
+ logfile string
20
+ color bool
21
+ pretty bool
22
+ }
23
+
24
+ var option PlayerOption
25
+ var init_rec ss.StatRecord
26
+
27
+ func showCpuStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
28
+ cusage, err := ss.GetCpuUsage(prev_rec.Cpu, cur_rec.Cpu)
29
+ if err != nil {
30
+ return err
31
+ }
32
+
33
+ printer.PutKey("cpu")
34
+ cusage.WriteJsonTo(printer)
35
+
36
+ return nil
37
+ }
38
+
39
+ func showInterruptStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
40
+ intr_usage, err := ss.GetInterruptUsage(
41
+ prev_rec.Time, prev_rec.Interrupt,
42
+ cur_rec.Time, cur_rec.Interrupt)
43
+ if err != nil {
44
+ return err
45
+ }
46
+
47
+ printer.PutKey("intr")
48
+ intr_usage.WriteJsonTo(printer)
49
+
50
+ return nil
51
+ }
52
+
53
+ func showDiskStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
54
+ dusage, err := ss.GetDiskUsage(
55
+ prev_rec.Time, prev_rec.Disk,
56
+ cur_rec.Time, cur_rec.Disk)
57
+ if err != nil {
58
+ return err
59
+ }
60
+
61
+ printer.PutKey("disk")
62
+
63
+ dusage.WriteJsonTo(printer)
64
+
65
+ return nil
66
+ }
67
+
68
+ func showNetStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
69
+ dusage, err := ss.GetNetUsage(
70
+ prev_rec.Time, prev_rec.Net,
71
+ cur_rec.Time, cur_rec.Net,
72
+ )
73
+ if err != nil {
74
+ return err
75
+ }
76
+
77
+ printer.PutKey("net")
78
+
79
+ dusage.WriteJsonTo(printer)
80
+
81
+ return nil
82
+ }
83
+
84
+ func showMemStat(printer *projson.JsonPrinter, cur_rec *ss.StatRecord) error {
85
+ musage, err := ss.GetMemUsage(cur_rec.Mem)
86
+ if err != nil {
87
+ return err
88
+ }
89
+
90
+ printer.PutKey("mem")
91
+
92
+ musage.WriteJsonTo(printer)
93
+
94
+ return nil
95
+ }
96
+
97
+ func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
98
+ printer.Reset()
99
+ if option.pretty {
100
+ printer.SetStyle(projson.SmartStyle)
101
+ }
102
+ if option.color {
103
+ printer.SetColor(true)
104
+ }
105
+ printer.BeginObject()
106
+ printer.PutKey("time")
107
+ printer.PutFloatFmt(float64(cur_rec.Time.UnixNano())/1e9, "%.3f")
108
+ printer.PutKey("elapsed_time")
109
+ printer.PutFloatFmt((float64(cur_rec.Time.UnixNano())-float64(init_rec.Time.UnixNano()))/1e9,
110
+ "%.3f")
111
+
112
+ if cur_rec.Cpu != nil {
113
+ err := showCpuStat(printer, prev_rec, cur_rec)
114
+ if err != nil {
115
+ return err
116
+ }
117
+ }
118
+ if cur_rec.Interrupt != nil {
119
+ err := showInterruptStat(printer, prev_rec, cur_rec)
120
+ if err != nil {
121
+ return err
122
+ }
123
+ }
124
+ if cur_rec.Disk != nil {
125
+ err := showDiskStat(printer, prev_rec, cur_rec)
126
+ if err != nil {
127
+ return err
128
+ }
129
+ }
130
+ if cur_rec.Net != nil {
131
+ err := showNetStat(printer, prev_rec, cur_rec)
132
+ if err != nil {
133
+ return err
134
+ }
135
+ }
136
+ if cur_rec.Mem != nil {
137
+ err := showMemStat(printer, cur_rec)
138
+ if err != nil {
139
+ return err
140
+ }
141
+ }
142
+
143
+ printer.FinishObject()
144
+
145
+ return nil
146
+ }
147
+
148
+ func parseArgs() {
149
+ flag.BoolVar(&option.color, "color", false, "Use colored JSON output")
150
+ flag.BoolVar(&option.pretty, "pretty", false, "Use human readable JSON output")
151
+
152
+ flag.Parse()
153
+
154
+ option.logfile = flag.Arg(0)
155
+ }
156
+
157
+ func main() {
158
+ var in *os.File
159
+ var out *bufio.Writer
160
+
161
+ parseArgs()
162
+
163
+ if option.logfile == "" {
164
+ in = os.Stdin
165
+ } else {
166
+ f, err := os.Open(option.logfile)
167
+ if err != nil {
168
+ panic(err)
169
+ }
170
+ in = f
171
+ defer f.Close()
172
+ }
173
+ input_reader := core.NewPerfmongerLogReader(in)
174
+ dec := gob.NewDecoder(input_reader)
175
+
176
+ out = bufio.NewWriter(os.Stdout)
177
+
178
+ var cheader ss.CommonHeader
179
+ var pheader ss.PlatformHeader
180
+ var records = make([]ss.StatRecord, 2)
181
+ curr := 0
182
+
183
+ var err error
184
+
185
+ err = dec.Decode(&cheader)
186
+ if err == io.EOF {
187
+ return
188
+ }
189
+ if err != nil {
190
+ panic(err)
191
+ }
192
+ err = dec.Decode(&pheader)
193
+ if err == io.EOF {
194
+ return
195
+ }
196
+ if err != nil {
197
+ panic(err)
198
+ }
199
+
200
+ // read first record
201
+ err = dec.Decode(&records[curr])
202
+ if err == io.EOF {
203
+ return
204
+ } else if err != nil {
205
+ panic(err)
206
+ }
207
+ init_rec = records[curr]
208
+ curr ^= 1
209
+
210
+ printer := projson.NewPrinter()
211
+ for {
212
+ prev_rec := &records[curr^1]
213
+ cur_rec := &records[curr]
214
+
215
+ err = dec.Decode(cur_rec)
216
+ if err == io.EOF {
217
+ break
218
+ } else if err != nil {
219
+ panic(err)
220
+ }
221
+
222
+ err = showStat(printer, prev_rec, cur_rec)
223
+ if err != nil {
224
+ printer.Reset()
225
+ fmt.Fprintln(os.Stderr, "skip by err")
226
+ continue
227
+ }
228
+
229
+ if str, err := printer.String(); err != nil {
230
+ fmt.Println("error", err)
231
+ fmt.Println(str)
232
+ } else {
233
+ _, err = out.WriteString(str + "\n")
234
+ }
235
+ err = out.Flush()
236
+ if err != nil {
237
+ // stdout is closed
238
+ break
239
+ }
240
+
241
+ printer.Reset()
242
+
243
+ curr ^= 1
244
+ }
245
+
246
+ return
247
+ }
@@ -11,23 +11,31 @@ import (
11
11
  "io"
12
12
  "io/ioutil"
13
13
  "os"
14
+ "regexp"
14
15
  "sort"
15
16
 
16
17
  ss "github.com/hayamiz/perfmonger/core/subsystem"
18
+ "github.com/hayamiz/perfmonger/core"
17
19
  )
18
20
 
19
21
  type CmdOption struct {
20
- DiskFile string
21
- CpuFile string
22
- PerfmongerFile string
22
+ DiskFile string
23
+ CpuFile string
24
+ PerfmongerFile string
25
+ disk_only string
26
+ disk_only_regex *regexp.Regexp
23
27
  }
24
28
 
25
29
  func parseArgs() *CmdOption {
30
+ var err error
31
+
26
32
  opt := new(CmdOption)
27
33
 
28
34
  flag.StringVar(&opt.DiskFile, "diskfile", "./disk.dat", "Disk performance data file")
29
35
  flag.StringVar(&opt.CpuFile, "cpufile", "./cpu.dat", "CPU performance data file")
30
36
  flag.StringVar(&opt.PerfmongerFile, "perfmonger", "", "Perfmonger log file")
37
+ flag.StringVar(&opt.disk_only, "disk-only",
38
+ "", "Select disk devices by regex")
31
39
 
32
40
  flag.Parse()
33
41
 
@@ -36,6 +44,11 @@ func parseArgs() *CmdOption {
36
44
  os.Exit(1)
37
45
  }
38
46
 
47
+ opt.disk_only_regex, err = regexp.Compile(opt.disk_only)
48
+ if err != nil {
49
+ panic(err)
50
+ }
51
+
39
52
  return opt
40
53
  }
41
54
 
@@ -129,7 +142,7 @@ func main() {
129
142
  }
130
143
  defer f.Close()
131
144
 
132
- input_reader := newPerfmongerLogReader(f)
145
+ input_reader := core.NewPerfmongerLogReader(f)
133
146
  dec := gob.NewDecoder(input_reader)
134
147
 
135
148
  var cheader ss.CommonHeader
@@ -192,7 +205,9 @@ func main() {
192
205
  }
193
206
 
194
207
  // Disk usage
195
- dusage, err := ss.GetDiskUsage(prev_rec.Time, prev_rec.Disk, cur_rec.Time, cur_rec.Disk)
208
+ dusage, err := ss.GetDiskUsage1(prev_rec.Time, prev_rec.Disk,
209
+ cur_rec.Time, cur_rec.Disk,
210
+ opt.disk_only_regex)
196
211
  if err != nil {
197
212
  panic(err)
198
213
  }
@@ -36,6 +36,7 @@ type RecorderOption struct {
36
36
  no_intr bool
37
37
  no_disk bool
38
38
  no_net bool
39
+ no_mem bool
39
40
  debug bool
40
41
  listDevices bool
41
42
  player_bin string
@@ -43,6 +44,8 @@ type RecorderOption struct {
43
44
  targetDisks *map[string]bool
44
45
  background bool
45
46
  gzip bool
47
+ color bool
48
+ pretty bool
46
49
  }
47
50
 
48
51
  var option RecorderOption
@@ -74,6 +77,8 @@ func parseArgs() {
74
77
  false, "Do not record disk usage")
75
78
  flag.BoolVar(&option.no_net, "no-net",
76
79
  false, "Do not record net usage")
80
+ flag.BoolVar(&option.no_mem, "no-mem",
81
+ false, "Do not record memory usage")
77
82
  flag.BoolVar(&option.debug, "debug",
78
83
  false, "Enable debug mode")
79
84
  flag.BoolVar(&option.listDevices, "list-devices",
@@ -86,6 +91,10 @@ func parseArgs() {
86
91
  "", "Run perfmonger-player to show JSON output")
87
92
  flag.BoolVar(&option.gzip, "gzip",
88
93
  false, "Save a logfile in gzipped format")
94
+ flag.BoolVar(&option.color, "color",
95
+ false, "Colored output (for live subcmd)")
96
+ flag.BoolVar(&option.pretty, "pretty",
97
+ false, "Pretty output (for live subcmd)")
89
98
 
90
99
  flag.Parse()
91
100
 
@@ -190,7 +199,7 @@ func main() {
190
199
  parseArgs()
191
200
 
192
201
  hostname, _ := os.Hostname()
193
- cheader := &ss.CommonHeader{ss.Linux, hostname, time.Now()}
202
+ cheader := &ss.CommonHeader{Platform: ss.Linux, Hostname: hostname, StartTime: time.Now()}
194
203
 
195
204
  platform_header := ss.NewPlatformHeader()
196
205
 
@@ -206,7 +215,15 @@ func main() {
206
215
  var player_stdout io.ReadCloser = nil
207
216
 
208
217
  if option.player_bin != "" {
209
- player_cmd = exec.Command(option.player_bin)
218
+ if option.color {
219
+ if option.pretty {
220
+ player_cmd = exec.Command(option.player_bin, "-color", "-pretty")
221
+ } else {
222
+ player_cmd = exec.Command(option.player_bin, "-color")
223
+ }
224
+ } else {
225
+ player_cmd = exec.Command(option.player_bin)
226
+ }
210
227
  player_stdin, err = player_cmd.StdinPipe()
211
228
  if err != nil {
212
229
  fmt.Fprintf(os.Stderr, "Failed to get stdin of %s", option.player_bin)
@@ -326,6 +343,9 @@ func main() {
326
343
  if !option.no_net {
327
344
  ss.ReadNetStat(record)
328
345
  }
346
+ if !option.no_mem {
347
+ ss.ReadMemStat(record)
348
+ }
329
349
 
330
350
  err = enc.Encode(record)
331
351
  if err != nil {
@@ -3,7 +3,6 @@
3
3
  package main
4
4
 
5
5
  import (
6
- "bytes"
7
6
  "encoding/gob"
8
7
  "flag"
9
8
  "fmt"
@@ -12,7 +11,9 @@ import (
12
11
  "regexp"
13
12
  "sort"
14
13
 
14
+ projson "github.com/hayamiz/go-projson"
15
15
  ss "github.com/hayamiz/perfmonger/core/subsystem"
16
+ "github.com/hayamiz/perfmonger/core"
16
17
  )
17
18
 
18
19
  type SummaryOption struct {
@@ -61,7 +62,7 @@ func main() {
61
62
  }
62
63
  defer f.Close()
63
64
 
64
- input_reader := newPerfmongerLogReader(f)
65
+ input_reader := core.NewPerfmongerLogReader(f)
65
66
  dec := gob.NewDecoder(input_reader)
66
67
 
67
68
  err = dec.Decode(&cheader)
@@ -128,7 +129,7 @@ func main() {
128
129
  option.disk_only_regex)
129
130
  }
130
131
 
131
- if fst_record.Disk != nil && lst_record.Disk != nil {
132
+ if fst_record.Net != nil && lst_record.Net != nil {
132
133
  net_usage, err = ss.GetNetUsage(
133
134
  fst_record.Time, fst_record.Net,
134
135
  lst_record.Time, lst_record.Net)
@@ -137,32 +138,38 @@ func main() {
137
138
  interval := lst_record.Time.Sub(fst_record.Time)
138
139
 
139
140
  if option.json {
140
- buf := bytes.NewBuffer([]byte{})
141
+ printer := projson.NewPrinter()
141
142
 
142
- buf.WriteString(fmt.Sprintf(`{"exectime":%.3f`, interval.Seconds()))
143
+ printer.BeginObject()
144
+ printer.PutKey("exectime")
145
+ printer.PutFloatFmt(interval.Seconds(), "%.3f")
143
146
  if cpu_usage != nil {
144
- buf.WriteString(`,"cpu":`)
145
- cpu_usage.WriteJsonTo(buf)
147
+ printer.PutKey("cpu")
148
+ cpu_usage.WriteJsonTo(printer)
146
149
  }
147
150
 
148
151
  if intr_usage != nil {
149
- buf.WriteString(`,"intr":`)
150
- intr_usage.WriteJsonTo(buf)
152
+ printer.PutKey("intr")
153
+ intr_usage.WriteJsonTo(printer)
151
154
  }
152
155
 
153
156
  if disk_usage != nil {
154
- buf.WriteString(`,"disk":`)
155
- disk_usage.WriteJsonTo(buf)
157
+ printer.PutKey("disk")
158
+ disk_usage.WriteJsonTo(printer)
156
159
  }
157
160
 
158
161
  if net_usage != nil {
159
- buf.WriteString(`,"net":`)
160
- net_usage.WriteJsonTo(buf)
162
+ printer.PutKey("net")
163
+ net_usage.WriteJsonTo(printer)
161
164
  }
162
165
 
163
- buf.WriteByte('}')
166
+ printer.FinishObject()
164
167
 
165
- fmt.Println(buf.String())
168
+ if str, err := printer.String(); err != nil {
169
+ fmt.Println("skip by err")
170
+ } else {
171
+ fmt.Println(str)
172
+ }
166
173
  } else {
167
174
  if option.title == "" {
168
175
  fmt.Println("== performance summary ==")