perfmonger 0.12.0 → 0.14.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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS +25 -1
  3. data/Rakefile +18 -7
  4. data/core/Makefile +20 -21
  5. data/core/build.sh +4 -6
  6. data/core/{perfmonger-player.go → cmd/perfmonger-player/perfmonger-player.go} +34 -10
  7. data/core/cmd/perfmonger-plot-formatter/README.md +24 -0
  8. data/core/{perfmonger-plot-formatter.go → cmd/perfmonger-plot-formatter/perfmonger-plot-formatter.go} +116 -3
  9. data/core/{perfmonger-recorder.go → cmd/perfmonger-recorder/perfmonger-recorder.go} +0 -0
  10. data/core/{perfmonger-summarizer.go → cmd/perfmonger-summarizer/perfmonger-summarizer.go} +3 -1
  11. data/core/{perfmonger-viewer.go → cmd/perfmonger-viewer/perfmonger-viewer.go} +0 -0
  12. data/core/go.mod +10 -0
  13. data/core/go.sum +17 -0
  14. data/core/subsystem/perfmonger_linux.go +2 -0
  15. data/core/subsystem/stat.go +2 -0
  16. data/core/utils.go +2 -2
  17. data/lib/exec/perfmonger-player_darwin_amd64 +0 -0
  18. data/lib/exec/perfmonger-player_linux_amd64 +0 -0
  19. data/lib/exec/perfmonger-plot-formatter_darwin_amd64 +0 -0
  20. data/lib/exec/perfmonger-plot-formatter_linux_amd64 +0 -0
  21. data/lib/exec/perfmonger-recorder_darwin_amd64 +0 -0
  22. data/lib/exec/perfmonger-recorder_linux_amd64 +0 -0
  23. data/lib/exec/perfmonger-summarizer_darwin_amd64 +0 -0
  24. data/lib/exec/perfmonger-summarizer_linux_amd64 +0 -0
  25. data/lib/exec/perfmonger-viewer_darwin_amd64 +0 -0
  26. data/lib/exec/perfmonger-viewer_linux_amd64 +0 -0
  27. data/lib/perfmonger/command/play.rb +10 -0
  28. data/lib/perfmonger/command/plot.rb +144 -2
  29. data/lib/perfmonger/command/record.rb +23 -2
  30. data/lib/perfmonger/version.rb +1 -1
  31. metadata +10 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d54380ef057091f9d6829d3a792c0c4a91789b56077ff7a59b4a1bf063ec883e
4
- data.tar.gz: c01127d30de0978a88bf1481357d3e20cde8193dd16e6bde9e0f2030d6423710
3
+ metadata.gz: 42856e6da789b3ad1a522b95bc642bdf7abe1e2fb7679e4839b7da7e3157b6a9
4
+ data.tar.gz: 937b2f2557ad06fe36e230c623ab07773d17bc1dd278e80b87bb8fb881a9427c
5
5
  SHA512:
6
- metadata.gz: 8ae9ded1f5d4c5157902ccfa23a12910866834480f7b82e1464f4c2d5e767cbf2d5752118f1aa666f445d2f61a0e5cfbc7198c3ad9cf098539c0cd96a25b12f3
7
- data.tar.gz: 3c507d05cec5b3b28e49367379846009b1848ac75d23227d22a019203190b9adeaf201a25805b3746d518d221a46399580d49899f6205f236980c70b3b73a7e5
6
+ metadata.gz: 4f06a76145f4f4aafd9f4fa8e2de7ef855190729d25b98a6ab36a8bcbcb1ee41242736e96b3c15693ffeb341ee229f3852f00f36b27785b84124e587fdcfad41
7
+ data.tar.gz: 86b957bb0edbf89f0cb7904b0059d75db11366eb26ca1b1112cd4c7566aa896240dc430d4d56a177c00c4862ebbf677f73f3447bda9e798226d7fcbf60836408
data/NEWS CHANGED
@@ -1,4 +1,28 @@
1
- ## 20XX-XX-XX: PerfMonger 0.13.0
1
+ ## 2021-XX-XX: PerfMonger 0.15.0
2
+
3
+ ## 2021-12-01: PerfMonger 0.14.1
4
+ * Changes
5
+ * [plot] subcommand:
6
+ * Skip plotting memory usage if it is not recorded
7
+
8
+ ## 2021-07-27: PerfMonger 0.14.0
9
+ * New features
10
+ * [plot] subcommand:
11
+ * Added memory usage plot
12
+ * Changes
13
+ * [record] subcommand:
14
+ * Additionaly record 'Hugepagesize' in memory usage
15
+
16
+ ## 2021-07-26: PerfMonger 0.13.1
17
+ * New features
18
+ * [play] subcommand:
19
+ * Added --disk-only option to filter results of not interesting disks
20
+ * Note: v0.13.0 is yanked from rubygems.org
21
+
22
+ ## 2021-07-08: PerfMonger 0.12.1
23
+ * Bug fixes
24
+ * [record] subcommand:
25
+ * --kill waits until a recorder process surely exits
2
26
 
3
27
  ## 2021-05-10: PerfMonger 0.12.0
4
28
  * New features
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rspec/core/rake_task'
3
3
  require "bundler/gem_tasks"
4
4
 
5
- task :default => [:spec, :test_core]
5
+ task :default => [:spec, :test_core, :analyze_core]
6
6
 
7
7
  desc "Run all specs in spec directory"
8
8
  RSpec::Core::RakeTask.new(:spec)
@@ -30,19 +30,30 @@ task :go_get do
30
30
  sh "go get -u github.com/jroimartin/gocui"
31
31
  end
32
32
 
33
- desc "Run tests of core recorder/player"
33
+ desc "Run tests of golang core library"
34
34
  task :test_core => [:cross_build_core] do
35
35
  Dir.chdir("./core/subsystem") do
36
+ # check coverage
36
37
  sh "go test -v -cover"
37
-
38
- # running static analysis
39
- sh "go vet *.go"
40
38
  end
39
+ end
41
40
 
42
- Dir.chdir("./core") do
43
- sh "go vet *.go"
41
+ desc "Run static-analysis of golang core library"
42
+ task :analyze_core => [:cross_build_core] do
43
+ # running static analysis
44
+ Dir.chdir("./core/subsystem") do
45
+ ["linux", "darwin"].each do |platform|
46
+ puts "* ./core/subsystem"
47
+ sh "go vet perfmonger_#{platform}.go $(ls *.go | grep -v perfmonger_)"
48
+ end
44
49
  end
45
50
 
51
+ Dir["./core", "./core/cmd/*"].each do |dir|
52
+ Dir.chdir(dir) do
53
+ puts "* #{dir}"
54
+ sh "go vet *.go"
55
+ end
56
+ end
46
57
  end
47
58
 
48
59
  desc "Removed generated files"
data/core/Makefile CHANGED
@@ -2,51 +2,50 @@
2
2
  # generated by build.sh
3
3
 
4
4
  GO_DEPS := subsystem/perfmonger_darwin.go subsystem/perfmonger.go subsystem/perfmonger_linux.go subsystem/perfmonger_linux_test.go subsystem/stat.go subsystem/stat_test.go subsystem/usage.go subsystem/usage_test.go utils.go
5
- GO_SRC := utils.go
6
5
 
7
6
  .PHONY: all build clean
8
7
 
9
8
  all: build
10
9
 
11
10
 
12
- ../lib/exec/perfmonger-recorder_linux_amd64: perfmonger-recorder.go $(GO_DEPS)
13
- go build -o $@ perfmonger-recorder.go $(GO_SRC)
11
+ ../lib/exec/perfmonger-recorder_linux_amd64: cmd/perfmonger-recorder/perfmonger-recorder.go $(GO_DEPS)
12
+ cd cmd/perfmonger-recorder && go build -o ../../$@ perfmonger-recorder.go
14
13
 
15
14
 
16
- ../lib/exec/perfmonger-player_linux_amd64: perfmonger-player.go $(GO_DEPS)
17
- go build -o $@ perfmonger-player.go $(GO_SRC)
15
+ ../lib/exec/perfmonger-player_linux_amd64: cmd/perfmonger-player/perfmonger-player.go $(GO_DEPS)
16
+ cd cmd/perfmonger-player && go build -o ../../$@ perfmonger-player.go
18
17
 
19
18
 
20
- ../lib/exec/perfmonger-viewer_linux_amd64: perfmonger-viewer.go $(GO_DEPS)
21
- go build -o $@ perfmonger-viewer.go $(GO_SRC)
19
+ ../lib/exec/perfmonger-viewer_linux_amd64: cmd/perfmonger-viewer/perfmonger-viewer.go $(GO_DEPS)
20
+ cd cmd/perfmonger-viewer && go build -o ../../$@ perfmonger-viewer.go
22
21
 
23
22
 
24
- ../lib/exec/perfmonger-summarizer_linux_amd64: perfmonger-summarizer.go $(GO_DEPS)
25
- go build -o $@ perfmonger-summarizer.go $(GO_SRC)
23
+ ../lib/exec/perfmonger-summarizer_linux_amd64: cmd/perfmonger-summarizer/perfmonger-summarizer.go $(GO_DEPS)
24
+ cd cmd/perfmonger-summarizer && go build -o ../../$@ perfmonger-summarizer.go
26
25
 
27
26
 
28
- ../lib/exec/perfmonger-plot-formatter_linux_amd64: perfmonger-plot-formatter.go $(GO_DEPS)
29
- go build -o $@ perfmonger-plot-formatter.go $(GO_SRC)
27
+ ../lib/exec/perfmonger-plot-formatter_linux_amd64: cmd/perfmonger-plot-formatter/perfmonger-plot-formatter.go $(GO_DEPS)
28
+ cd cmd/perfmonger-plot-formatter && go build -o ../../$@ perfmonger-plot-formatter.go
30
29
 
31
30
 
32
- ../lib/exec/perfmonger-recorder_darwin_amd64: perfmonger-recorder.go $(GO_DEPS)
33
- go build -o $@ perfmonger-recorder.go $(GO_SRC)
31
+ ../lib/exec/perfmonger-recorder_darwin_amd64: cmd/perfmonger-recorder/perfmonger-recorder.go $(GO_DEPS)
32
+ cd cmd/perfmonger-recorder && go build -o ../../$@ perfmonger-recorder.go
34
33
 
35
34
 
36
- ../lib/exec/perfmonger-player_darwin_amd64: perfmonger-player.go $(GO_DEPS)
37
- go build -o $@ perfmonger-player.go $(GO_SRC)
35
+ ../lib/exec/perfmonger-player_darwin_amd64: cmd/perfmonger-player/perfmonger-player.go $(GO_DEPS)
36
+ cd cmd/perfmonger-player && go build -o ../../$@ perfmonger-player.go
38
37
 
39
38
 
40
- ../lib/exec/perfmonger-viewer_darwin_amd64: perfmonger-viewer.go $(GO_DEPS)
41
- go build -o $@ perfmonger-viewer.go $(GO_SRC)
39
+ ../lib/exec/perfmonger-viewer_darwin_amd64: cmd/perfmonger-viewer/perfmonger-viewer.go $(GO_DEPS)
40
+ cd cmd/perfmonger-viewer && go build -o ../../$@ perfmonger-viewer.go
42
41
 
43
42
 
44
- ../lib/exec/perfmonger-summarizer_darwin_amd64: perfmonger-summarizer.go $(GO_DEPS)
45
- go build -o $@ perfmonger-summarizer.go $(GO_SRC)
43
+ ../lib/exec/perfmonger-summarizer_darwin_amd64: cmd/perfmonger-summarizer/perfmonger-summarizer.go $(GO_DEPS)
44
+ cd cmd/perfmonger-summarizer && go build -o ../../$@ perfmonger-summarizer.go
46
45
 
47
46
 
48
- ../lib/exec/perfmonger-plot-formatter_darwin_amd64: perfmonger-plot-formatter.go $(GO_DEPS)
49
- go build -o $@ perfmonger-plot-formatter.go $(GO_SRC)
47
+ ../lib/exec/perfmonger-plot-formatter_darwin_amd64: cmd/perfmonger-plot-formatter/perfmonger-plot-formatter.go $(GO_DEPS)
48
+ cd cmd/perfmonger-plot-formatter && go build -o ../../$@ perfmonger-plot-formatter.go
50
49
 
51
50
 
52
51
  build: ../lib/exec/perfmonger-recorder_linux_amd64 ../lib/exec/perfmonger-player_linux_amd64 ../lib/exec/perfmonger-viewer_linux_amd64 ../lib/exec/perfmonger-summarizer_linux_amd64 ../lib/exec/perfmonger-plot-formatter_linux_amd64 ../lib/exec/perfmonger-recorder_darwin_amd64 ../lib/exec/perfmonger-player_darwin_amd64 ../lib/exec/perfmonger-viewer_darwin_amd64 ../lib/exec/perfmonger-summarizer_darwin_amd64 ../lib/exec/perfmonger-plot-formatter_darwin_amd64
data/core/build.sh CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/bin/bash
2
2
 
3
- READLINK=$(type -p greadlink readlink | head -1)
4
- cd $(dirname $($READLINK -f $0))
3
+ cd $(cd $(dirname $0); pwd)
5
4
 
6
5
  if [[ $1 = "-" ]]; then
7
6
  # do self build
@@ -33,7 +32,7 @@ fi
33
32
 
34
33
  set -e
35
34
 
36
- GO_DEPS=$(ls subsystem/*.go; ls utils.go)
35
+ GO_DEPS=$(ls subsystem/*.go utils.go)
37
36
 
38
37
  makefile=`mktemp`
39
38
 
@@ -42,7 +41,6 @@ cat <<EOF > $makefile
42
41
  # generated by build.sh
43
42
 
44
43
  GO_DEPS := $(echo ${GO_DEPS})
45
- GO_SRC := utils.go
46
44
 
47
45
  .PHONY: all build clean
48
46
 
@@ -62,8 +60,8 @@ for idx in $(seq 0 $((${#TARGET[@]}-1))); do
62
60
 
63
61
  cat <<EOF >> $makefile
64
62
 
65
- ../lib/exec/perfmonger-${subcmd}_${var_GOOS}_${var_GOARCH}: perfmonger-${subcmd}.go \$(GO_DEPS)
66
- go build -o \$@ perfmonger-$subcmd.go \$(GO_SRC)
63
+ ../lib/exec/perfmonger-${subcmd}_${var_GOOS}_${var_GOARCH}: cmd/perfmonger-${subcmd}/perfmonger-${subcmd}.go \$(GO_DEPS)
64
+ cd cmd/perfmonger-${subcmd} && go build -o ../../\$@ perfmonger-$subcmd.go
67
65
 
68
66
  EOF
69
67
  done
@@ -9,15 +9,19 @@ import (
9
9
  "fmt"
10
10
  "io"
11
11
  "os"
12
+ "regexp"
12
13
 
13
14
  projson "github.com/hayamiz/go-projson"
15
+ core "github.com/hayamiz/perfmonger/core"
14
16
  ss "github.com/hayamiz/perfmonger/core/subsystem"
15
17
  )
16
18
 
17
19
  type PlayerOption struct {
18
- logfile string
19
- color bool
20
- pretty bool
20
+ logfile string
21
+ color bool
22
+ pretty bool
23
+ disk_only string
24
+ disk_only_regex *regexp.Regexp
21
25
  }
22
26
 
23
27
  var option PlayerOption
@@ -49,10 +53,11 @@ func showInterruptStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cu
49
53
  return nil
50
54
  }
51
55
 
52
- func showDiskStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
53
- dusage, err := ss.GetDiskUsage(
56
+ func showDiskStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord, disk_only_regex *regexp.Regexp) error {
57
+ dusage, err := ss.GetDiskUsage1(
54
58
  prev_rec.Time, prev_rec.Disk,
55
- cur_rec.Time, cur_rec.Disk)
59
+ cur_rec.Time, cur_rec.Disk,
60
+ option.disk_only_regex)
56
61
  if err != nil {
57
62
  return err
58
63
  }
@@ -93,7 +98,9 @@ func showMemStat(printer *projson.JsonPrinter, cur_rec *ss.StatRecord) error {
93
98
  return nil
94
99
  }
95
100
 
96
- func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
101
+ func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord,
102
+ disk_only_regex *regexp.Regexp) error {
103
+
97
104
  printer.Reset()
98
105
  if option.pretty {
99
106
  printer.SetStyle(projson.SmartStyle)
@@ -101,6 +108,7 @@ func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss
101
108
  if option.color {
102
109
  printer.SetColor(true)
103
110
  }
111
+
104
112
  printer.BeginObject()
105
113
  printer.PutKey("time")
106
114
  printer.PutFloatFmt(float64(cur_rec.Time.UnixNano())/1e9, "%.3f")
@@ -121,7 +129,7 @@ func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss
121
129
  }
122
130
  }
123
131
  if cur_rec.Disk != nil {
124
- err := showDiskStat(printer, prev_rec, cur_rec)
132
+ err := showDiskStat(printer, prev_rec, cur_rec, disk_only_regex)
125
133
  if err != nil {
126
134
  return err
127
135
  }
@@ -147,9 +155,25 @@ func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss
147
155
  func parseArgs() {
148
156
  flag.BoolVar(&option.color, "color", false, "Use colored JSON output")
149
157
  flag.BoolVar(&option.pretty, "pretty", false, "Use human readable JSON output")
158
+ flag.StringVar(&option.disk_only, "disk-only", "", "Select disk devices by regex")
150
159
 
151
160
  flag.Parse()
152
161
 
162
+ if len(flag.Args()) < 1 {
163
+ fmt.Fprintln(os.Stderr, "Insufficient argument")
164
+ os.Exit(1)
165
+ }
166
+
167
+ option.disk_only_regex = nil
168
+
169
+ if option.disk_only != "" {
170
+ var err error
171
+ option.disk_only_regex, err = regexp.Compile(option.disk_only)
172
+ if err != nil {
173
+ panic(err)
174
+ }
175
+ }
176
+
153
177
  option.logfile = flag.Arg(0)
154
178
  }
155
179
 
@@ -169,7 +193,7 @@ func main() {
169
193
  in = f
170
194
  defer f.Close()
171
195
  }
172
- input_reader := newPerfmongerLogReader(in)
196
+ input_reader := core.NewPerfmongerLogReader(in)
173
197
  dec := gob.NewDecoder(input_reader)
174
198
 
175
199
  out = bufio.NewWriter(os.Stdout)
@@ -218,7 +242,7 @@ func main() {
218
242
  panic(err)
219
243
  }
220
244
 
221
- err = showStat(printer, prev_rec, cur_rec)
245
+ err = showStat(printer, prev_rec, cur_rec, option.disk_only_regex)
222
246
  if err != nil {
223
247
  printer.Reset()
224
248
  fmt.Fprintln(os.Stderr, "skip by err")
@@ -0,0 +1,24 @@
1
+ # perfmonger-plot-formatter
2
+
3
+ `perfmonger-plot-formatter` is a command to generate data files for plotting
4
+ various metrices recorded by `perfmonger-recorder`.
5
+
6
+ ## Notes on memory usage records
7
+
8
+ ### `free(1)` compatible summarization
9
+
10
+ - total: `MemStat.MemTotal`
11
+ - used: `if (memUsed < 0) { MemStat.MemTotal - MemStat.MemFree } else { memUsed }`
12
+ - memUsed := `MemStat.MemTotal - MemStat.MemFree - mainCached - MemStat.Buffers`
13
+ - mainCached := `MemStat.Cached + MemStat.SReclaimable`
14
+ - free: `MemStat.MemFree`
15
+ - shared: `MemStat.Shmem`
16
+ - buffers: `MemStat.Buffers`
17
+ - cache: `mainCached`
18
+ - mainCached := `MemStat.Cached + MemStat.SReclaimable`
19
+ - available: `MemStat.MemAvailable`
20
+
21
+ ### Additional info
22
+
23
+ - hugeTotal: `MemStat.HugePages_Total`
24
+ - hugeUsed: `MemStat.HugePages_Total - MemStat.HugePages_Free`
@@ -13,13 +13,16 @@ import (
13
13
  "os"
14
14
  "regexp"
15
15
  "sort"
16
+ "strings"
16
17
 
18
+ "github.com/hayamiz/perfmonger/core"
17
19
  ss "github.com/hayamiz/perfmonger/core/subsystem"
18
20
  )
19
21
 
20
22
  type CmdOption struct {
21
23
  DiskFile string
22
24
  CpuFile string
25
+ MemFile string
23
26
  PerfmongerFile string
24
27
  disk_only string
25
28
  disk_only_regex *regexp.Regexp
@@ -30,8 +33,9 @@ func parseArgs() *CmdOption {
30
33
 
31
34
  opt := new(CmdOption)
32
35
 
33
- flag.StringVar(&opt.DiskFile, "diskfile", "./disk.dat", "Disk performance data file")
34
- flag.StringVar(&opt.CpuFile, "cpufile", "./cpu.dat", "CPU performance data file")
36
+ flag.StringVar(&opt.DiskFile, "diskfile", "./disk.dat", "Disk usage data file for gnuplot")
37
+ flag.StringVar(&opt.CpuFile, "cpufile", "./cpu.dat", "CPU usage data file for gnuplot")
38
+ flag.StringVar(&opt.MemFile, "memfile", "./mem.dat", "Memory usage data file for gnuplot")
35
39
  flag.StringVar(&opt.PerfmongerFile, "perfmonger", "", "Perfmonger log file")
36
40
  flag.StringVar(&opt.disk_only, "disk-only",
37
41
  "", "Select disk devices by regex")
@@ -79,6 +83,13 @@ type DiskDatTmpFile struct {
79
83
  Idx int
80
84
  }
81
85
 
86
+ type MemDatTmpFile struct {
87
+ Name string
88
+ Path string
89
+ File *os.File
90
+ Writer *bufio.Writer
91
+ }
92
+
82
93
  type CpuDatTmpFile struct {
83
94
  CoreId int
84
95
  Path string
@@ -117,6 +128,20 @@ func makeCpuDatTmpFile(coreid int) *CpuDatTmpFile {
117
128
  return ret
118
129
  }
119
130
 
131
+ func makeMemDatTmpFile() *MemDatTmpFile {
132
+ ret := new(MemDatTmpFile)
133
+
134
+ f, err := ioutil.TempFile("", "perfmonger-mem")
135
+ if err != nil {
136
+ panic(err)
137
+ }
138
+ ret.File = f
139
+ ret.Path = f.Name()
140
+ ret.Writer = bufio.NewWriter(f)
141
+
142
+ return ret
143
+ }
144
+
120
145
  func printCoreUsage(writer *bufio.Writer, elapsed_time float64, coreusage *ss.CpuCoreUsage) {
121
146
  writer.WriteString(
122
147
  fmt.Sprintf("%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n",
@@ -132,6 +157,80 @@ func printCoreUsage(writer *bufio.Writer, elapsed_time float64, coreusage *ss.Cp
132
157
  coreusage.Idle))
133
158
  }
134
159
 
160
+ func printMemUsage(writer *bufio.Writer, elapsed_time float64, mem *ss.MemStat) {
161
+ if mem == nil {
162
+ writer.WriteString("#")
163
+ writer.WriteString(
164
+ strings.Join([]string{
165
+ "elapsed_time", // 1
166
+ "mem_total", // 2
167
+ "mem_used", // 3
168
+ "mem_free", // 4
169
+ "buffers", // 5
170
+ "cached", // 6
171
+ "swap_cached", // 7
172
+ "active", // 8
173
+ "inactive", // 9
174
+ "swap_total", // 10
175
+ "swap_free", // 11
176
+ "dirty", // 12
177
+ "writeback", // 13
178
+ "anon_pages", // 14
179
+ "mapped", // 15
180
+ "shmem", // 16
181
+ "slab", // 17
182
+ "s_reclaimable", // 18
183
+ "s_unreclaim", // 19
184
+ "kernel_stack", // 20
185
+ "page_tables", // 21
186
+ "nfs_unstable", // 22
187
+ "bounce", // 23
188
+ "commit_limit", // 24
189
+ "committed_as", // 25
190
+ "anon_huge_pages", // 26
191
+ "huge_pages_total", // 27
192
+ "huge_pages_free", // 28
193
+ "huge_pages_rsvd", // 29
194
+ "huge_pages_surp", // 30
195
+ "hugepagesize"}, // 31
196
+ "\t"))
197
+ writer.WriteString("\n")
198
+ } else {
199
+ writer.WriteString(fmt.Sprintf("%f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
200
+ elapsed_time,
201
+ mem.MemTotal,
202
+ mem.MemTotal-mem.MemFree-mem.Buffers-mem.Cached-mem.SReclaimable,
203
+ mem.MemFree,
204
+ mem.Buffers,
205
+ mem.Cached,
206
+ mem.SwapCached,
207
+ mem.Active,
208
+ mem.Inactive,
209
+ mem.SwapTotal,
210
+ mem.SwapFree,
211
+ mem.Dirty,
212
+ mem.Writeback,
213
+ mem.AnonPages,
214
+ mem.Mapped,
215
+ mem.Shmem,
216
+ mem.Slab,
217
+ mem.SReclaimable,
218
+ mem.SUnreclaim,
219
+ mem.KernelStack,
220
+ mem.PageTables,
221
+ mem.NFS_Unstable,
222
+ mem.Bounce,
223
+ mem.CommitLimit,
224
+ mem.Committed_AS,
225
+ mem.AnonHugePages,
226
+ mem.HugePages_Total,
227
+ mem.HugePages_Free,
228
+ mem.HugePages_Rsvd,
229
+ mem.HugePages_Surp,
230
+ mem.Hugepagesize))
231
+ }
232
+ }
233
+
135
234
  func main() {
136
235
  opt := parseArgs()
137
236
 
@@ -141,7 +240,7 @@ func main() {
141
240
  }
142
241
  defer f.Close()
143
242
 
144
- input_reader := newPerfmongerLogReader(f)
243
+ input_reader := core.NewPerfmongerLogReader(f)
145
244
  dec := gob.NewDecoder(input_reader)
146
245
 
147
246
  var cheader ss.CommonHeader
@@ -192,6 +291,13 @@ func main() {
192
291
  cpu_writer.WriteString("# All cpu usage\n")
193
292
  cpu_writer.WriteString("# elapsed_time %usr %nice %sys %iowait %hardirq %softirq %steal %guest %idle\n")
194
293
 
294
+ f, err = os.Create(opt.MemFile)
295
+ if err != nil {
296
+ panic(err)
297
+ }
298
+ defer f.Close()
299
+ mem_writer := bufio.NewWriter(f)
300
+
195
301
  for {
196
302
  prev_rec := &records[curr^1]
197
303
  cur_rec := &records[curr]
@@ -283,6 +389,12 @@ func main() {
283
389
  }
284
390
  printCoreUsage(cpu_writer, prev_rec.Time.Sub(t0).Seconds(), cusage.All)
285
391
 
392
+ if !meta_set {
393
+ // print column labels
394
+ printMemUsage(mem_writer, prev_rec.Time.Sub(t0).Seconds(), nil)
395
+ }
396
+ printMemUsage(mem_writer, prev_rec.Time.Sub(t0).Seconds(), cur_rec.Mem)
397
+
286
398
  curr ^= 1
287
399
  meta_set = true
288
400
  }
@@ -331,6 +443,7 @@ func main() {
331
443
  os.Remove(cpu_dat.Path)
332
444
  }
333
445
  cpu_writer.Flush()
446
+ mem_writer.Flush()
334
447
 
335
448
  json_enc := json.NewEncoder(os.Stdout)
336
449
  json_enc.Encode(meta)
@@ -12,6 +12,7 @@ import (
12
12
  "sort"
13
13
 
14
14
  projson "github.com/hayamiz/go-projson"
15
+ "github.com/hayamiz/perfmonger/core"
15
16
  ss "github.com/hayamiz/perfmonger/core/subsystem"
16
17
  )
17
18
 
@@ -38,6 +39,7 @@ func parseArgs() {
38
39
  flag.Parse()
39
40
 
40
41
  if len(flag.Args()) < 1 {
42
+ fmt.Fprintln(os.Stderr, "Insufficient argument")
41
43
  os.Exit(1)
42
44
  }
43
45
 
@@ -61,7 +63,7 @@ func main() {
61
63
  }
62
64
  defer f.Close()
63
65
 
64
- input_reader := newPerfmongerLogReader(f)
66
+ input_reader := core.NewPerfmongerLogReader(f)
65
67
  dec := gob.NewDecoder(input_reader)
66
68
 
67
69
  err = dec.Decode(&cheader)
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=
@@ -469,6 +469,8 @@ func ReadMemStat(record *StatRecord) error {
469
469
  mem_stat.HugePages_Free = val
470
470
  case "HugePages_Total:":
471
471
  mem_stat.HugePages_Total = val
472
+ case "Hugepagesize:":
473
+ mem_stat.Hugepagesize = val
472
474
  case "AnonHugePages:":
473
475
  mem_stat.AnonHugePages = val
474
476
  case "Committed_AS:":
@@ -132,6 +132,7 @@ type MemStat struct {
132
132
  HugePages_Free int64
133
133
  HugePages_Rsvd int64
134
134
  HugePages_Surp int64
135
+ Hugepagesize int64
135
136
  }
136
137
 
137
138
  type StatRecord struct {
@@ -286,6 +287,7 @@ func (entry *MemStat) Clear() {
286
287
  entry.HugePages_Free = 0
287
288
  entry.HugePages_Rsvd = 0
288
289
  entry.HugePages_Surp = 0
290
+ entry.Hugepagesize = 0
289
291
  }
290
292
 
291
293
  func NewStatRecord() *StatRecord {
data/core/utils.go CHANGED
@@ -1,4 +1,4 @@
1
- package main
1
+ package core
2
2
 
3
3
  import (
4
4
  "bufio"
@@ -6,7 +6,7 @@ import (
6
6
  "io"
7
7
  )
8
8
 
9
- func newPerfmongerLogReader(source io.Reader) io.Reader {
9
+ func NewPerfmongerLogReader(source io.Reader) io.Reader {
10
10
  var ret io.Reader
11
11
  reader := bufio.NewReader(source)
12
12
 
Binary file
Binary file
@@ -26,6 +26,10 @@ EOS
26
26
  @pretty = true
27
27
  end
28
28
 
29
+ @disk_only_regex = nil
30
+ @parser.on('--disk-only REGEX', "Select disk devices that matches REGEX (Ex. 'sd[b-d]')") do |regex|
31
+ @disk_only_regex = regex
32
+ end
29
33
  end
30
34
 
31
35
  def parse_args(argv)
@@ -62,6 +66,12 @@ EOS
62
66
  if @pretty
63
67
  cmd << "-pretty"
64
68
  end
69
+
70
+ if @disk_only_regex
71
+ cmd << "-disk-only"
72
+ cmd << @disk_only_regex
73
+ end
74
+
65
75
  cmd << @logfile
66
76
 
67
77
  Process.exec(*cmd)
@@ -145,10 +145,13 @@ EOS
145
145
 
146
146
  @disk_dat = File.expand_path("disk.dat", @tmpdir)
147
147
  @cpu_dat = File.expand_path("cpu.dat", @tmpdir)
148
+ @mem_dat = File.expand_path("mem.dat", @tmpdir)
148
149
 
149
150
  meta_json = nil
150
- cmd = [formatter_bin, "-perfmonger", @data_file, "-cpufile", @cpu_dat,
151
- "-diskfile", @disk_dat]
151
+ cmd = [formatter_bin, "-perfmonger", @data_file,
152
+ "-cpufile", @cpu_dat,
153
+ "-diskfile", @disk_dat,
154
+ "-memfile", @mem_dat]
152
155
  if @disk_only_regex
153
156
  cmd << "-disk-only"
154
157
  cmd << @disk_only
@@ -164,6 +167,7 @@ EOS
164
167
 
165
168
  plot_disk(meta)
166
169
  plot_cpu(meta)
170
+ plot_mem(meta)
167
171
 
168
172
  FileUtils.rm_rf(@tmpdir)
169
173
 
@@ -508,6 +512,144 @@ EOS
508
512
  end
509
513
  end # def
510
514
 
515
+ def plot_mem(meta)
516
+ pdf_filename = @output_prefix + 'mem.pdf'
517
+ gp_filename = @output_prefix + 'mem.gp'
518
+ dat_filename = @output_prefix + 'mem.dat'
519
+
520
+ unless File.exists?(dat_filename)
521
+ $stderr.puts("WARN: memory usage info is not available.")
522
+ return
523
+ end
524
+
525
+ if @output_type != 'pdf'
526
+ img_filename = @output_prefix + 'cpu.' + @output_type
527
+ else
528
+ img_filename = nil
529
+ end
530
+
531
+ start_time = meta["start_time"]
532
+ end_time = meta["end_time"]
533
+
534
+ mem_scaling = 2.0**20 # KB -> GB
535
+
536
+ # "elapsed_time", // 1
537
+ # "mem_total", // 2
538
+ # "mem_used", // 3
539
+ # "mem_free", // 4
540
+ # "buffers", // 5
541
+ # "cached", // 6
542
+ # "swap_cached", // 7
543
+ # "active", // 8
544
+ # "inactive", // 9
545
+ # "swap_total", // 10
546
+ # "swap_free", // 11
547
+ # "dirty", // 12
548
+ # "writeback", // 13
549
+ # "anon_pages", // 14
550
+ # "mapped", // 15
551
+ # "shmem", // 16
552
+ # "slab", // 17
553
+ # "s_reclaimable", // 18
554
+ # "s_unreclaim", // 19
555
+ # "kernel_stack", // 20
556
+ # "page_tables", // 21
557
+ # "nfs_unstable", // 22
558
+ # "bounce", // 23
559
+ # "commit_limit", // 24
560
+ # "committed_as", // 25
561
+ # "anon_huge_pages", // 26
562
+ # "huge_pages_total", // 27
563
+ # "huge_pages_free", // 28
564
+ # "huge_pages_rsvd", // 29
565
+ # "huge_pages_surp"}, // 30
566
+ # "hugepagesize"}, // 31
567
+
568
+ Dir.chdir(@tmpdir) do
569
+ total = `tail -n+2 #{dat_filename}|head -n1`.split[1].to_f
570
+ if total == 0.0
571
+ raise RuntimeError.new("Failed to get MemTotal value from mem.dat file: #{dat_filename}")
572
+ end
573
+
574
+ gpfile = File.open(gp_filename, 'w')
575
+
576
+ pdf_file = File.join(@output_dir, "mem.pdf")
577
+ gpfile.puts <<EOS
578
+ set term pdfcairo enhanced color size 6in,2.5in
579
+ set title "Memory usage"
580
+ set output "#{pdf_filename}"
581
+ set key outside center bottom horizontal
582
+ set size 1.0, 1.0
583
+
584
+ set xlabel "elapsed time [sec]"
585
+ set ylabel "memory usage [GB]"
586
+
587
+ # scaling
588
+ s = #{mem_scaling}
589
+
590
+ set grid
591
+ set xrange [#{@offset_time}:#{end_time - start_time}]
592
+ set yrange [0:#{total * 1.2}/s]
593
+
594
+ # line styles
595
+ set style line 1 lt 1 lc rgb '#66C2A5' # teal
596
+ set style line 2 lt 1 lc rgb '#FC8D62' # orange
597
+ set style line 3 lt 1 lc rgb '#8DA0CB' # lilac
598
+ set style line 4 lt 1 lc rgb '#E78AC3' # magentat
599
+ set style line 5 lt 1 lc rgb '#A6D854' # lime green
600
+ set style line 6 lt 1 lc rgb '#FFD92F' # banana
601
+ set style line 7 lt 1 lc rgb '#E5C494' # tan
602
+ set style line 8 lt 1 lc rgb '#B3B3B3' # grey
603
+
604
+ # palette
605
+ set palette maxcolors 8
606
+ set palette defined ( 0 '#66C2A5',\
607
+ 1 '#FC8D62',\
608
+ 2 '#8DA0CB',\
609
+ 3 '#E78AC3',\
610
+ 4 '#A6D854',\
611
+ 5 '#FFD92F',\
612
+ 6 '#E5C494',\
613
+ 7 '#B3B3B3' )
614
+
615
+ used(total, free, cached, buffers, srecl) = \\
616
+ ( (total - free - cache(cached, srecl) - buffers < 0) ? \\
617
+ (total - free) : \\
618
+ (total - free - cache(cached, srecl) - buffers) )
619
+
620
+ cache(cached, srecl) = cached + srecl
621
+
622
+ plot "#{dat_filename}" usi 1:($4/s+$5/s+cache($6, $18)/s+$16/s+used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 8 ti "free", \\
623
+ "#{dat_filename}" usi 1:($5/s+cache($6, $18)/s+$16/s+used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 3 ti "buffers", \\
624
+ "#{dat_filename}" usi 1:(cache($6, $18)/s+$16/s+used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 5 ti "cached", \\
625
+ "#{dat_filename}" usi 1:($16/s+used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 6 ti "shared", \\
626
+ "#{dat_filename}" usi 1:(used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 2 ti "used", \\
627
+ "#{dat_filename}" usi 1:(($27-$28)*$31/s) wi lines dt (4,4) lc rgb 'black' lw 2.5 ti 'used (hugepage)'
628
+
629
+ EOS
630
+
631
+ gpfile.close
632
+ system("gnuplot #{gpfile.path}")
633
+
634
+ if @output_type != 'pdf'
635
+ system("convert -density 150 -background white #{pdf_filename} #{img_filename}")
636
+ end
637
+ end # chdir
638
+
639
+ copy_targets = []
640
+ copy_targets << pdf_filename
641
+ copy_targets << img_filename if img_filename
642
+
643
+ if @save_gpfiles
644
+ copy_targets << gp_filename
645
+ copy_targets << dat_filename
646
+ end
647
+
648
+ copy_targets.each do |target|
649
+ FileUtils.copy(File.join(@tmpdir, target), @output_dir)
650
+ end
651
+ end # def
652
+
511
653
  private
512
654
  def factors(n)
513
655
  (2..([n, n / 2].max).to_i).select do |x|
@@ -31,7 +31,8 @@ class RecordCommand < BaseCommand
31
31
  if @option.kill
32
32
  unless session_pid
33
33
  # There is nothing to be killed
34
- return true
34
+ $stderr.puts("[ERROR] No perfmonger record session is running.")
35
+ return false
35
36
  end
36
37
 
37
38
  begin
@@ -44,12 +45,32 @@ class RecordCommand < BaseCommand
44
45
  f.flock(File::LOCK_UN)
45
46
  end
46
47
  end
48
+
49
+ # wait until the process surely exits
50
+ sleeptime = 0.05
51
+ try = 0
52
+ while true
53
+ begin
54
+ Process.kill(:INT, session_pid)
55
+ rescue Errno::ESRCH
56
+ # no such process
57
+ break
58
+ end
59
+ sleep(sleeptime)
60
+ sleeptime *= 2
61
+ try += 1
62
+ if try >= 5
63
+ $stderr.puts("[ERROR] Cannot stop perfmonger record session correctly. PID=#{session_pid}")
64
+ return false
65
+ end
66
+ end
67
+
47
68
  return true
48
69
  end
49
70
 
50
71
  if @option.status
51
72
  unless session_pid
52
- puts "[ERROR] No perfmonger-recorder is running."
73
+ puts "[ERROR] No perfmonger record session is running."
53
74
  return false
54
75
  end
55
76
 
@@ -1,3 +1,3 @@
1
1
  module PerfMonger
2
- VERSION = "0.12.0"
2
+ VERSION = "0.14.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perfmonger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuto HAYAMIZU
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-10 00:00:00.000000000 Z
11
+ date: 2021-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -101,11 +101,14 @@ files:
101
101
  - Rakefile
102
102
  - core/Makefile
103
103
  - core/build.sh
104
- - core/perfmonger-player.go
105
- - core/perfmonger-plot-formatter.go
106
- - core/perfmonger-recorder.go
107
- - core/perfmonger-summarizer.go
108
- - core/perfmonger-viewer.go
104
+ - core/cmd/perfmonger-player/perfmonger-player.go
105
+ - core/cmd/perfmonger-plot-formatter/README.md
106
+ - core/cmd/perfmonger-plot-formatter/perfmonger-plot-formatter.go
107
+ - core/cmd/perfmonger-recorder/perfmonger-recorder.go
108
+ - core/cmd/perfmonger-summarizer/perfmonger-summarizer.go
109
+ - core/cmd/perfmonger-viewer/perfmonger-viewer.go
110
+ - core/go.mod
111
+ - core/go.sum
109
112
  - core/subsystem/Makefile
110
113
  - core/subsystem/perfmonger.go
111
114
  - core/subsystem/perfmonger_darwin.go