perfmonger 0.12.0 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
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