perfmonger 0.11.1 → 0.13.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 (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