perfmonger 0.11.1 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +6 -9
  3. data/NEWS +36 -0
  4. data/README.md +1 -1
  5. data/Rakefile +20 -7
  6. data/core/Makefile +26 -19
  7. data/core/build.sh +5 -7
  8. data/core/{perfmonger-player.go → cmd/perfmonger-player/perfmonger-player.go} +53 -10
  9. data/core/{perfmonger-plot-formatter.go → cmd/perfmonger-plot-formatter/perfmonger-plot-formatter.go} +2 -1
  10. data/core/{perfmonger-recorder.go → cmd/perfmonger-recorder/perfmonger-recorder.go} +6 -0
  11. data/core/{perfmonger-summarizer.go → cmd/perfmonger-summarizer/perfmonger-summarizer.go} +4 -2
  12. data/core/cmd/perfmonger-viewer/perfmonger-viewer.go +164 -0
  13. data/core/go.mod +10 -0
  14. data/core/go.sum +17 -0
  15. data/core/subsystem/Makefile +4 -0
  16. data/core/subsystem/perfmonger_linux.go +95 -0
  17. data/core/subsystem/perfmonger_linux_test.go +40 -0
  18. data/core/subsystem/stat.go +70 -0
  19. data/core/subsystem/stat_test.go +9 -0
  20. data/core/subsystem/usage.go +80 -0
  21. data/core/utils.go +2 -2
  22. data/lib/exec/perfmonger-player_darwin_amd64 +0 -0
  23. data/lib/exec/perfmonger-player_linux_amd64 +0 -0
  24. data/lib/exec/perfmonger-plot-formatter_darwin_amd64 +0 -0
  25. data/lib/exec/perfmonger-plot-formatter_linux_amd64 +0 -0
  26. data/lib/exec/perfmonger-recorder_darwin_amd64 +0 -0
  27. data/lib/exec/perfmonger-recorder_linux_amd64 +0 -0
  28. data/lib/exec/perfmonger-summarizer_darwin_amd64 +0 -0
  29. data/lib/exec/perfmonger-summarizer_linux_amd64 +0 -0
  30. data/lib/exec/perfmonger-viewer_darwin_amd64 +0 -0
  31. data/lib/exec/perfmonger-viewer_linux_amd64 +0 -0
  32. data/lib/perfmonger/command/play.rb +10 -0
  33. data/lib/perfmonger/command/plot.rb +9 -1
  34. data/lib/perfmonger/command/record.rb +23 -2
  35. data/lib/perfmonger/command/record_option.rb +16 -0
  36. data/lib/perfmonger/version.rb +1 -1
  37. data/misc/werker-box/Dockerfile +16 -17
  38. data/misc/werker-box/build-push.sh +4 -2
  39. data/wercker.yml +12 -30
  40. metadata +13 -26
@@ -0,0 +1,164 @@
1
+ //usr/bin/env go run $0 $@ ; exit
2
+
3
+ package main
4
+
5
+ import (
6
+ "fmt"
7
+ "log"
8
+ "math"
9
+ "math/rand"
10
+ "time"
11
+
12
+ gocui "github.com/jroimartin/gocui"
13
+ termbox "github.com/nsf/termbox-go"
14
+ )
15
+
16
+ func main() {
17
+ g, err := gocui.NewGui(gocui.OutputNormal)
18
+ if err != nil {
19
+ log.Panicln(err)
20
+ }
21
+ defer g.Close()
22
+
23
+ g.SetManagerFunc(layout)
24
+
25
+ setupKeybind(g)
26
+
27
+ go func() {
28
+ for {
29
+ time.Sleep(1 * time.Second)
30
+ g.Update(layout)
31
+ }
32
+ }()
33
+
34
+ if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
35
+ log.Panicln(err)
36
+ }
37
+ }
38
+
39
+ func setupKeybind(g *gocui.Gui) {
40
+ if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
41
+ log.Panicln(err)
42
+ }
43
+
44
+ if err := g.SetKeybinding("", 'c', gocui.ModNone, changeColor); err != nil {
45
+ log.Panicln(err)
46
+ }
47
+
48
+ if err := g.SetKeybinding("", 'q', gocui.ModNone, quit); err != nil {
49
+ log.Panicln(err)
50
+ }
51
+ }
52
+
53
+ var colmode bool = false
54
+
55
+ func changeColor(g *gocui.Gui, v *gocui.View) error {
56
+ if colmode {
57
+ colmode = false
58
+ } else {
59
+ colmode = true
60
+ }
61
+ return nil
62
+ }
63
+
64
+ // Vertical bar characters
65
+ // ' ': \u0020
66
+ // '▁': \u2581
67
+ // '▂': \u2582
68
+ // '▃': \u2583
69
+ // '▄': \u2584
70
+ // '▅': \u2585
71
+ // '▆': \u2586
72
+ // '▇': \u2587
73
+ // '█': \u2588
74
+ var vbar_runes []rune = []rune(" ▁▂▃▄▅▆▇█")
75
+
76
+ func drawPercent(g *gocui.Gui, x int, y int, height int, pct float64, fg, bg termbox.Attribute) {
77
+ pct = math.Max(0.0, math.Min(100.0, pct))
78
+ pct_ndiv := 9
79
+ if height > 1 {
80
+ pct_ndiv += 8 * (height - 1)
81
+ }
82
+ pct_class := int(pct / (100.0 / float64(pct_ndiv)))
83
+
84
+ col := termbox.ColorBlue
85
+ if 25 <= pct && pct < 50 {
86
+ col = termbox.ColorGreen
87
+ } else if 50 <= pct && pct < 75 {
88
+ col = termbox.ColorYellow
89
+ } else if 75 <= pct {
90
+ col = termbox.ColorRed
91
+ }
92
+
93
+ if !colmode {
94
+ col = termbox.ColorWhite
95
+ }
96
+
97
+ for cell_pos := height - 1; cell_pos >= 0; cell_pos-- {
98
+ vbar_idx := intMin(pct_class, len(vbar_runes)-1)
99
+ termbox.SetCell(x, y+cell_pos, vbar_runes[vbar_idx], col, bg)
100
+ pct_class -= vbar_idx
101
+ }
102
+
103
+ // termbox.SetCell(x, y, vbar_runes[pct_class], fg, bg)
104
+ }
105
+
106
+ func drawRunes(g *gocui.Gui, x int, y int, runes []rune) {
107
+ for _, r := range runes {
108
+ termbox.SetCell(x, y, r, termbox.ColorDefault, termbox.ColorDefault)
109
+ x += 1
110
+ }
111
+ }
112
+
113
+ func intMin(x, y int) int {
114
+ if x > y {
115
+ return y
116
+ } else {
117
+ return x
118
+ }
119
+ }
120
+
121
+ var start_time int64 = time.Now().Unix()
122
+
123
+ func layout(g *gocui.Gui) error {
124
+ // maxX, maxY := g.Size()
125
+ // if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2); err != nil {
126
+ // if err != gocui.ErrUnknownView {
127
+ // return err
128
+ // }
129
+ // fmt.Fprintln(v, "Hello world!")
130
+ // }
131
+
132
+ for coreid := 0; coreid < 8; coreid++ {
133
+ s := int64(coreid + 1)
134
+ rand.Seed(s)
135
+
136
+ inc := int(time.Now().Unix() - start_time)
137
+ for i := 0; i < inc; i++ {
138
+ rand.Float64()
139
+ }
140
+
141
+ for i := 0; i < 100; i++ {
142
+ // drawPercent(g, i+5, 1+coreid*5, 4, float64(i)/2.0, termbox.ColorDefault, termbox.ColorDefault)
143
+ drawPercent(g, i+6, 1+coreid*5, 4, rand.Float64()*100, termbox.ColorDefault, termbox.ColorDefault)
144
+
145
+ ch := '-'
146
+ if (i+inc)%10 == 0 {
147
+ ch = '+'
148
+ }
149
+ termbox.SetCell(i+6, 1+coreid*5+4, ch, termbox.ColorDefault, termbox.ColorDefault)
150
+ }
151
+ drawRunes(g, 0, 1+coreid*5, []rune(fmt.Sprintf("core%d", coreid)))
152
+
153
+ drawRunes(g, 100+6+1, 1+coreid*5, []rune(fmt.Sprintf("%%usr: % 2.1f", rand.Float64()*30)))
154
+ drawRunes(g, 100+6+1, 1+coreid*5+1, []rune(fmt.Sprintf("%%sys: % 2.1f", rand.Float64()*30)))
155
+ drawRunes(g, 100+6+1, 1+coreid*5+2, []rune(fmt.Sprintf("%%iow: % 2.1f", rand.Float64()*30)))
156
+ drawRunes(g, 100+6+1, 1+coreid*5+3, []rune(fmt.Sprintf("%%oth: % 2.1f", rand.Float64()*30)))
157
+ }
158
+
159
+ return nil
160
+ }
161
+
162
+ func quit(g *gocui.Gui, v *gocui.View) error {
163
+ return gocui.ErrQuit
164
+ }
data/core/go.mod ADDED
@@ -0,0 +1,10 @@
1
+ module github.com/hayamiz/perfmonger/core
2
+
3
+ go 1.15
4
+
5
+ require (
6
+ github.com/hayamiz/go-projson v0.0.0-20210510072849-3503bd24ae61
7
+ github.com/jroimartin/gocui v0.4.0
8
+ github.com/nsf/termbox-go v1.1.1
9
+ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
10
+ )
data/core/go.sum ADDED
@@ -0,0 +1,17 @@
1
+ github.com/hayamiz/go-projson v0.0.0-20210510072849-3503bd24ae61 h1:elFR/pEri9bFREP6YvJQDcFjncPBDhG+SwWJjYSvY8s=
2
+ github.com/hayamiz/go-projson v0.0.0-20210510072849-3503bd24ae61/go.mod h1:Zkuug8uJZoQ8V34UfDAFVmKLVHPhe+TJUAazUzh6s1k=
3
+ github.com/jroimartin/gocui v0.4.0 h1:52jnalstgmc25FmtGcWqa0tcbMEWS6RpFLsOIO+I+E8=
4
+ github.com/jroimartin/gocui v0.4.0/go.mod h1:7i7bbj99OgFHzo7kB2zPb8pXLqMBSQegY7azfqXMkyY=
5
+ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
6
+ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
7
+ github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY=
8
+ github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
9
+ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
10
+ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
11
+ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
12
+ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
13
+ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
14
+ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
15
+ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
16
+ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
17
+ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1,3 +1,7 @@
1
1
 
2
2
  all:
3
3
  make -C ../
4
+
5
+ check:
6
+ go test
7
+
@@ -429,3 +429,98 @@ func ReadNetStat(record *StatRecord) error {
429
429
 
430
430
  return nil
431
431
  }
432
+
433
+ func ReadMemStat(record *StatRecord) error {
434
+ if record == nil {
435
+ return errors.New("Valid *StatRecord is required.")
436
+ }
437
+
438
+ mem_stat := NewMemStat()
439
+
440
+ f, err := os.Open("/proc/meminfo")
441
+ if err != nil {
442
+ return err
443
+ }
444
+ defer f.Close()
445
+ scanner := bufio.NewScanner(f)
446
+
447
+ for scanner.Scan() {
448
+ var key string
449
+ var val int64
450
+ line := scanner.Text()
451
+
452
+ n, err := fmt.Sscanf(line, "%s %d", &key, &val)
453
+
454
+ if err == io.EOF {
455
+ break
456
+ } else if err != nil {
457
+ return err
458
+ }
459
+ if n != 2 {
460
+ continue
461
+ }
462
+
463
+ switch key {
464
+ case "HugePages_Surp:":
465
+ mem_stat.HugePages_Surp = val
466
+ case "HugePages_Rsvd:":
467
+ mem_stat.HugePages_Rsvd = val
468
+ case "HugePages_Free:":
469
+ mem_stat.HugePages_Free = val
470
+ case "HugePages_Total:":
471
+ mem_stat.HugePages_Total = val
472
+ case "AnonHugePages:":
473
+ mem_stat.AnonHugePages = val
474
+ case "Committed_AS:":
475
+ mem_stat.Committed_AS = val
476
+ case "CommitLimit:":
477
+ mem_stat.CommitLimit = val
478
+ case "Bounce:":
479
+ mem_stat.Bounce = val
480
+ case "NFS_Unstable:":
481
+ mem_stat.NFS_Unstable = val
482
+ case "Shmem:":
483
+ mem_stat.Shmem = val
484
+ case "Slab:":
485
+ mem_stat.Slab = val
486
+ case "SReclaimable:":
487
+ mem_stat.SReclaimable = val
488
+ case "SUnreclaim:":
489
+ mem_stat.SUnreclaim = val
490
+ case "KernelStack:":
491
+ mem_stat.KernelStack = val
492
+ case "PageTables:":
493
+ mem_stat.PageTables = val
494
+ case "Mapped:":
495
+ mem_stat.Mapped = val
496
+ case "AnonPages:":
497
+ mem_stat.AnonPages = val
498
+ case "Writeback:":
499
+ mem_stat.Writeback = val
500
+ case "Dirty:":
501
+ mem_stat.Dirty = val
502
+ case "SwapFree:":
503
+ mem_stat.SwapFree = val
504
+ case "SwapTotal:":
505
+ mem_stat.SwapTotal = val
506
+ case "Inactive:":
507
+ mem_stat.Inactive = val
508
+ case "Active:":
509
+ mem_stat.Active = val
510
+ case "SwapCached:":
511
+ mem_stat.SwapCached = val
512
+ case "Cached:":
513
+ mem_stat.Cached = val
514
+ case "Buffers:":
515
+ mem_stat.Buffers = val
516
+ case "MemFree:":
517
+ mem_stat.MemFree = val
518
+ case "MemTotal:":
519
+ mem_stat.MemTotal = val
520
+ }
521
+ }
522
+
523
+ record.Mem = mem_stat
524
+
525
+ return nil
526
+ }
@@ -1,6 +1,7 @@
1
1
  package subsystem
2
2
 
3
3
  import (
4
+ "log"
4
5
  "os"
5
6
  "testing"
6
7
  )
@@ -71,3 +72,42 @@ func TestReadNetStat(t *testing.T) {
71
72
  t.Error("Device 'lo' not found.")
72
73
  }
73
74
  }
75
+
76
+ func TestReadMemStat(t *testing.T) {
77
+ var err error
78
+ var stat_record *StatRecord = nil
79
+
80
+ err = ReadMemStat(stat_record)
81
+ if err == nil {
82
+ t.Errorf("Error should not be returned with non-nil *StatRecord.")
83
+ }
84
+
85
+ _, err = os.Stat("/proc/meminfo")
86
+ if err != nil {
87
+ t.Skip("/proc/meminfo is not present.")
88
+ }
89
+
90
+ stat_record = NewStatRecord()
91
+ err = ReadMemStat(stat_record)
92
+ if err != nil {
93
+ log.Print(err)
94
+ t.Error("Error should not be returned with valid *StatRecord.")
95
+ return
96
+ }
97
+ if stat_record.Mem == nil {
98
+ t.Error("stat_record.Mem should not be nil")
99
+ return
100
+ }
101
+
102
+ if stat_record.Mem.MemTotal == 0 {
103
+ t.Error("Cannot read MemTotal correctly")
104
+ return
105
+ }
106
+
107
+ mem := stat_record.Mem
108
+
109
+ if (mem.MemFree + mem.Cached + mem.Buffers) > mem.MemTotal {
110
+ t.Error("Inconsistent meminfo values")
111
+ return
112
+ }
113
+ }
@@ -102,6 +102,38 @@ type NetStat struct {
102
102
  Entries []*NetStatEntry
103
103
  }
104
104
 
105
+ // all values are recorded in KB
106
+ type MemStat struct {
107
+ MemTotal int64
108
+ MemFree int64
109
+ Buffers int64
110
+ Cached int64
111
+ SwapCached int64
112
+ Active int64
113
+ Inactive int64
114
+ SwapTotal int64
115
+ SwapFree int64
116
+ Dirty int64
117
+ Writeback int64
118
+ AnonPages int64
119
+ Mapped int64
120
+ Shmem int64
121
+ Slab int64
122
+ SReclaimable int64
123
+ SUnreclaim int64
124
+ KernelStack int64
125
+ PageTables int64
126
+ NFS_Unstable int64
127
+ Bounce int64
128
+ CommitLimit int64
129
+ Committed_AS int64
130
+ AnonHugePages int64
131
+ HugePages_Total int64
132
+ HugePages_Free int64
133
+ HugePages_Rsvd int64
134
+ HugePages_Surp int64
135
+ }
136
+
105
137
  type StatRecord struct {
106
138
  Time time.Time
107
139
  Cpu *CpuStat
@@ -110,6 +142,7 @@ type StatRecord struct {
110
142
  Disk *DiskStat
111
143
  Softirq *SoftIrqStat
112
144
  Net *NetStat
145
+ Mem *MemStat
113
146
  }
114
147
 
115
148
  func (core_stat *CpuCoreStat) Clear() {
@@ -219,6 +252,42 @@ func NewNetStat() *NetStat {
219
252
  return new(NetStat)
220
253
  }
221
254
 
255
+ func NewMemStat() *MemStat {
256
+ return new(MemStat)
257
+ }
258
+
259
+ func (entry *MemStat) Clear() {
260
+ entry.MemTotal = 0
261
+ entry.MemFree = 0
262
+ entry.Buffers = 0
263
+ entry.Cached = 0
264
+ entry.SwapCached = 0
265
+ entry.Active = 0
266
+ entry.Inactive = 0
267
+ entry.SwapTotal = 0
268
+ entry.SwapFree = 0
269
+ entry.Dirty = 0
270
+ entry.Writeback = 0
271
+ entry.AnonPages = 0
272
+ entry.Mapped = 0
273
+ entry.Shmem = 0
274
+ entry.Slab = 0
275
+ entry.SReclaimable = 0
276
+ entry.NFS_Unstable = 0
277
+ entry.SUnreclaim = 0
278
+ entry.KernelStack = 0
279
+ entry.PageTables = 0
280
+ entry.NFS_Unstable = 0
281
+ entry.Bounce = 0
282
+ entry.CommitLimit = 0
283
+ entry.Committed_AS = 0
284
+ entry.AnonHugePages = 0
285
+ entry.HugePages_Total = 0
286
+ entry.HugePages_Free = 0
287
+ entry.HugePages_Rsvd = 0
288
+ entry.HugePages_Surp = 0
289
+ }
290
+
222
291
  func NewStatRecord() *StatRecord {
223
292
  return &StatRecord{
224
293
  time.Now(),
@@ -228,6 +297,7 @@ func NewStatRecord() *StatRecord {
228
297
  nil,
229
298
  nil,
230
299
  nil,
300
+ nil,
231
301
  }
232
302
  }
233
303