perfmonger 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -13
  2. data/.gitignore +6 -0
  3. data/.tachikoma.yml +1 -0
  4. data/.travis.yml +18 -6
  5. data/Gemfile +1 -3
  6. data/Guardfile +26 -0
  7. data/NEWS +21 -0
  8. data/README.md +8 -9
  9. data/Rakefile +33 -1
  10. data/core/Makefile +23 -0
  11. data/core/build.sh +48 -0
  12. data/core/perfmonger-player.go +165 -0
  13. data/core/perfmonger-recorder.go +296 -0
  14. data/core/perfmonger-summarizer.go +207 -0
  15. data/core/subsystem/Makefile +3 -0
  16. data/core/subsystem/perfmonger.go +60 -0
  17. data/core/subsystem/perfmonger_darwin.go +22 -0
  18. data/core/subsystem/perfmonger_linux.go +292 -0
  19. data/core/subsystem/perfmonger_linux_test.go +73 -0
  20. data/core/subsystem/stat.go +214 -0
  21. data/core/subsystem/stat_test.go +281 -0
  22. data/core/subsystem/usage.go +410 -0
  23. data/core/subsystem/usage_test.go +496 -0
  24. data/lib/exec/operationBinding.rb.svn-base +59 -0
  25. data/lib/exec/perfmonger-player_darwin_amd64 +0 -0
  26. data/lib/exec/perfmonger-player_linux_386 +0 -0
  27. data/lib/exec/perfmonger-player_linux_amd64 +0 -0
  28. data/lib/exec/perfmonger-recorder_darwin_amd64 +0 -0
  29. data/lib/exec/perfmonger-recorder_linux_386 +0 -0
  30. data/lib/exec/perfmonger-recorder_linux_amd64 +0 -0
  31. data/lib/exec/perfmonger-summarizer_darwin_amd64 +0 -0
  32. data/lib/exec/perfmonger-summarizer_linux_386 +0 -0
  33. data/lib/exec/perfmonger-summarizer_linux_amd64 +0 -0
  34. data/lib/exec/perfmonger-summary_linux_386 +0 -0
  35. data/lib/exec/perfmonger-summary_linux_amd64 +0 -0
  36. data/lib/perfmonger/cli.rb +8 -3
  37. data/lib/perfmonger/command/core.rb +62 -0
  38. data/lib/perfmonger/command/live.rb +39 -0
  39. data/lib/perfmonger/command/play.rb +56 -0
  40. data/lib/perfmonger/command/plot.rb +30 -22
  41. data/lib/perfmonger/command/record.rb +3 -2
  42. data/lib/perfmonger/command/record_option.rb +40 -59
  43. data/lib/perfmonger/command/server.rb +7 -2
  44. data/lib/perfmonger/command/stat.rb +2 -2
  45. data/lib/perfmonger/command/stat_option.rb +1 -1
  46. data/lib/perfmonger/command/summary.rb +11 -326
  47. data/lib/perfmonger/version.rb +1 -3
  48. data/lib/perfmonger.rb +3 -0
  49. data/misc/_perfmonger +128 -0
  50. data/misc/perfmonger-completion.bash +49 -0
  51. data/perfmonger.gemspec +6 -5
  52. data/spec/data/busy100.pgr +0 -0
  53. data/spec/fingerprint_spec.rb +35 -0
  54. data/spec/live_spec.rb +25 -0
  55. data/spec/perfmonger_spec.rb +37 -0
  56. data/spec/play_spec.rb +21 -0
  57. data/spec/plot_spec.rb +42 -0
  58. data/spec/record_spec.rb +15 -0
  59. data/spec/spec_helper.rb +33 -0
  60. data/spec/stat_spec.rb +15 -0
  61. data/spec/summary_spec.rb +51 -0
  62. data/spec/support/aruba.rb +11 -0
  63. data/wercker.yml +59 -0
  64. metadata +117 -45
  65. data/ext/perfmonger/extconf.rb +0 -19
  66. data/ext/perfmonger/perfmonger.h +0 -58
  67. data/ext/perfmonger/perfmonger_record.c +0 -754
  68. data/ext/perfmonger/sysstat/common.c +0 -627
  69. data/ext/perfmonger/sysstat/common.h +0 -207
  70. data/ext/perfmonger/sysstat/ioconf.c +0 -515
  71. data/ext/perfmonger/sysstat/ioconf.h +0 -84
  72. data/ext/perfmonger/sysstat/iostat.c +0 -1100
  73. data/ext/perfmonger/sysstat/iostat.h +0 -121
  74. data/ext/perfmonger/sysstat/libsysstat.h +0 -19
  75. data/ext/perfmonger/sysstat/mpstat.c +0 -953
  76. data/ext/perfmonger/sysstat/mpstat.h +0 -79
  77. data/ext/perfmonger/sysstat/rd_stats.c +0 -2388
  78. data/ext/perfmonger/sysstat/rd_stats.h +0 -651
  79. data/ext/perfmonger/sysstat/sysconfig.h +0 -13
  80. data/test/run-test.sh +0 -39
  81. data/test/spec/bin_spec.rb +0 -37
  82. data/test/spec/data/2devices.expected +0 -42
  83. data/test/spec/data/2devices.output +0 -42
  84. data/test/spec/spec_helper.rb +0 -20
  85. data/test/spec/summary_spec.rb +0 -193
  86. data/test/test-perfmonger.c +0 -145
  87. data/test/test.h +0 -9
@@ -0,0 +1,56 @@
1
+
2
+ require 'optparse'
3
+ require 'json'
4
+
5
+ module PerfMonger
6
+ module Command
7
+
8
+ class PlayCommand < BaseCommand
9
+ register_command 'play', "Play a perfmonger log file in JSON"
10
+
11
+ def initialize
12
+ @parser = OptionParser.new
13
+ @parser.banner = <<EOS
14
+ Usage: perfmonger play [options] LOG_FILE
15
+
16
+ Options:
17
+ EOS
18
+
19
+ end
20
+
21
+ def parse_args(argv)
22
+ @parser.parse!(argv)
23
+
24
+ if argv.size == 0
25
+ puts("ERROR: PerfMonger log file is required")
26
+ puts(@parser.help)
27
+ exit(false)
28
+ end
29
+
30
+ @logfile = argv.shift
31
+ if ! File.exists?(@logfile)
32
+ puts("ERROR: No such file: #{@logfile}")
33
+ puts(@parser.help)
34
+ exit(false)
35
+ end
36
+ end
37
+
38
+ def run(argv)
39
+ parse_args(argv)
40
+
41
+ @player_bin = ::PerfMonger::Command::CoreFinder.player()
42
+
43
+ if ! @player_bin
44
+ puts("[ERROR] no executable binary found.")
45
+ exit(false)
46
+ end
47
+
48
+ cmd = [@player_bin]
49
+ cmd << @logfile
50
+
51
+ Process.exec(*cmd)
52
+ end
53
+ end
54
+
55
+ end # module Command
56
+ end # module PerfMonger
@@ -93,19 +93,27 @@ EOS
93
93
  exit(false)
94
94
  end
95
95
 
96
- unless system('gnuplot -e "set terminal"|grep pdfcairo >/dev/null 2>&1')
96
+ unless system('gnuplot -e "set terminal" < /dev/null 2>&1 | grep pdfcairo >/dev/null 2>&1')
97
97
  puts("ERROR: pdfcairo is not supported by installed gnuplot")
98
98
  puts("ERROR: PerfMonger requires pdfcairo-supported gnuplot")
99
99
  puts(@parser.help)
100
100
  exit(false)
101
101
  end
102
102
 
103
- plot_ioinfo()
104
- plot_cpuinfo()
103
+ player_bin = ::PerfMonger::Command::CoreFinder.player()
104
+
105
+ tmpfile = Tempfile.new("jsondata")
106
+ IO.popen([player_bin, @data_file], "r").each_line do |line|
107
+ tmpfile.print(line)
108
+ end
109
+ tmpfile.flush()
110
+
111
+ plot_ioinfo(tmpfile.path)
112
+ plot_cpuinfo(tmpfile.path)
105
113
  end
106
114
 
107
115
  private
108
- def plot_ioinfo()
116
+ def plot_ioinfo(json_file)
109
117
  iops_pdf_filename = @output_prefix + 'iops.pdf'
110
118
  transfer_pdf_filename = @output_prefix + 'transfer.pdf'
111
119
  gp_filename = @output_prefix + 'io.gp'
@@ -126,20 +134,20 @@ EOS
126
134
  start_time = nil
127
135
  devices = nil
128
136
 
129
- File.open(@data_file).each_line do |line|
137
+ File.open(json_file).each_line do |line|
130
138
  record = JSON.parse(line)
131
139
  time = record["time"]
132
- ioinfo = record["ioinfo"]
133
- return unless ioinfo
140
+ diskinfo = record["disk"]
141
+ return unless diskinfo
134
142
 
135
143
  start_time ||= time
136
- devices ||= ioinfo["devices"]
144
+ devices ||= diskinfo["devices"]
137
145
 
138
146
  datafile.puts([time - start_time,
139
147
  devices.map{|device|
140
- [ioinfo[device]["riops"], ioinfo[device]["wiops"],
141
- ioinfo[device]["rsecps"] * 512 / 1024 / 1024, # in MB/s
142
- ioinfo[device]["wsecps"] * 512 / 1024 / 1024, # in MB/s
148
+ [diskinfo[device]["riops"], diskinfo[device]["wiops"],
149
+ diskinfo[device]["rkbyteps"] * 512 / 1024 / 1024, # in MB/s
150
+ diskinfo[device]["wkbyteps"] * 512 / 1024 / 1024, # in MB/s
143
151
  ]
144
152
  }].flatten.map(&:to_s).join("\t"))
145
153
  end
@@ -214,7 +222,7 @@ EOS
214
222
  end # mktempdir
215
223
  end # def
216
224
 
217
- def plot_cpuinfo()
225
+ def plot_cpuinfo(json_file)
218
226
  pdf_filename = @output_prefix + 'cpu.pdf'
219
227
  gp_filename = @output_prefix + 'cpu.gp'
220
228
  dat_filename = @output_prefix + 'cpu.dat'
@@ -243,21 +251,21 @@ EOS
243
251
  devices = nil
244
252
  nr_cpu = nil
245
253
 
246
- File.open(@data_file).each_line do |line|
254
+ File.open(json_file).each_line do |line|
247
255
  record = JSON.parse(line)
248
256
 
249
257
  time = record["time"]
250
- cpuinfo = record["cpuinfo"]
258
+ cpuinfo = record["cpu"]
251
259
  return unless cpuinfo
252
- nr_cpu = cpuinfo['nr_cpu']
260
+ nr_cpu = cpuinfo['num_core']
253
261
 
254
- cores = cpuinfo['cpus']
262
+ cores = cpuinfo['cores']
255
263
 
256
264
  start_time ||= time
257
265
  end_time = [end_time, time].max
258
266
 
259
267
  datafile.puts([time - start_time,
260
- %w|usr nice sys iowait irq soft steal guest idle|.map do |key|
268
+ %w|usr nice sys iowait hardirq softirq steal guest idle|.map do |key|
261
269
  cores.map{|core| core[key]}.inject(&:+)
262
270
  end].flatten.map(&:to_s).join("\t"))
263
271
  end
@@ -266,7 +274,7 @@ EOS
266
274
  col_idx = 2
267
275
  columns = []
268
276
  plot_stmt_list = []
269
- %w|%usr %nice %sys %iowait %irq %soft %steal %guest|.each do |key|
277
+ %w|%usr %nice %sys %iowait %hardirq %softirq %steal %guest|.each do |key|
270
278
  columns << col_idx
271
279
  plot_stmt = "\"#{datafile.path}\" usi 1:(#{columns.map{|i| "$#{i}"}.join("+")}) with filledcurve x1 lw 0 lc #{col_idx - 1} title \"#{key}\""
272
280
  plot_stmt_list << plot_stmt
@@ -321,15 +329,15 @@ EOS
321
329
  legend_height = 0.04
322
330
  nr_cpu.times do |cpu_idx|
323
331
  all_datafile.puts("# cpu #{cpu_idx}")
324
- File.open(@data_file).each_line do |line|
332
+ File.open(json_file).each_line do |line|
325
333
  record = JSON.parse(line)
326
334
  time = record["time"]
327
- cpurec = record["cpuinfo"]["cpus"][cpu_idx]
335
+ cpurec = record["cpu"]["cores"][cpu_idx]
328
336
  all_datafile.puts([time - start_time,
329
337
  cpurec["usr"] + cpurec["nice"],
330
338
  cpurec["sys"],
331
- cpurec["irq"],
332
- cpurec["soft"],
339
+ cpurec["hardirq"],
340
+ cpurec["softirq"],
333
341
  cpurec["steal"] + cpurec["guest"],
334
342
  cpurec["iowait"]].map(&:to_s).join("\t"))
335
343
  end
@@ -1,8 +1,7 @@
1
-
2
1
  require 'optparse'
3
- require 'json'
4
2
  require 'tempfile'
5
3
  require 'tmpdir'
4
+ require 'json'
6
5
 
7
6
  module PerfMonger
8
7
  module Command
@@ -24,6 +23,8 @@ private
24
23
  def exec_record_cmd()
25
24
  cmd = @option.make_command
26
25
 
26
+ $stdout.puts("[recording to #{@option.logfile}]")
27
+
27
28
  Process.exec(*cmd)
28
29
  end
29
30
  end
@@ -7,11 +7,11 @@ class RecordOption
7
7
  attr_reader :interval
8
8
  attr_reader :verbose
9
9
  attr_reader :report_cpu
10
- attr_reader :report_io
11
- attr_reader :report_ctx_switch
10
+ attr_reader :no_disk
12
11
  attr_reader :logfile
13
12
 
14
13
  attr_reader :parser
14
+ attr_accessor :record_bin
15
15
 
16
16
  def self.parse(argv)
17
17
  option = self.new
@@ -23,88 +23,73 @@ class RecordOption
23
23
  def parse(argv)
24
24
  argv = @parser.parse(argv)
25
25
 
26
- if ! @report_io && ! @report_ctx_switch && ! @report_cpu
27
- @report_cpu = true
28
- @report_io = true
29
- @all_devices = true
30
- end
26
+ @no_cpu = false
27
+ @no_disk = false
28
+ @all_devices = true
31
29
 
32
30
  argv
33
31
  end
34
32
 
35
33
  def make_command
36
- # try to search perfmonger-record in build environment
37
- # then search installed directory
38
- record_bin = [File.expand_path("../../perfmonger_record", __FILE__),
39
- File.expand_path("lib/perfmonger/perfmonger_record", PerfMonger::ROOTDIR),
40
- File.expand_path("ext/perfmonger/perfmonger_record", PerfMonger::ROOTDIR)].find do |bin|
41
- File.executable?(bin)
42
- end
34
+ @recorder_bin = ::PerfMonger::Command::CoreFinder.recorder()
43
35
 
44
- if record_bin == nil || ! File.executable?(record_bin)
45
- puts("ERROR: perfmonger-record(1) not found!")
36
+ if ! @recorder_bin
37
+ puts("ERROR: no executable binaries")
46
38
  exit(false)
47
39
  end
48
40
 
49
- cmd = [record_bin]
50
- cmd << '-i'
51
- cmd << @interval.to_s
52
- if @interval_backoff
53
- cmd << '-b'
41
+ cmd = [@recorder_bin]
42
+ cmd << sprintf("-interval=%.1fms", @interval * 1000)
43
+ if ! @interval_backoff
44
+ cmd << "-no-interval-backoff"
54
45
  end
55
46
  if @start_delay > 0
56
- cmd << '-s'
57
- cmd << @start_delay.to_s
47
+ cmd << "-start-delay"
48
+ cmd << "#{@start_delay*1000}ms"
58
49
  end
59
50
  if @timeout
60
- cmd << '-t'
61
- cmd << @timeout.to_s
51
+ cmd << "-timeout"
52
+ cmd << "#{@timeout*1000}ms"
53
+ end
54
+ if @no_cpu
55
+ cmd << "-no-cpu"
56
+ end
57
+ if @no_disk
58
+ cmd << "-no-disk"
62
59
  end
63
- cmd << '-C' if @report_cpu
64
- cmd << '-S' if @report_ctx_switch
65
- cmd << '-l' if @logfile != STDOUT
66
- cmd << @logfile if @logfile != STDOUT
67
- if @report_io
68
- if @all_devices
69
- cmd << '-D'
70
- else
71
- @devices.each do |device|
72
- cmd << '-d'
73
- cmd << device
74
- end
75
- end
60
+ if @devices.size > 0
61
+ cmd << "-disks"
62
+ cmd << @devices.join(",")
76
63
  end
77
- cmd << '-v' if @verbose
64
+
65
+ # TODO: implement device filter
66
+
67
+ cmd << "-output"
68
+ cmd << @logfile
69
+
70
+ raise NotImplementedError if @verbose
78
71
 
79
72
  cmd
80
73
  end
81
74
 
82
75
  private
83
76
  def initialize
84
- @devices = []
85
- @all_devices = false
86
77
  @interval = 1.0 # in second
87
78
  @interval_backoff = true
88
79
  @start_delay = 0.0 # in second
89
80
  @timeout = nil # in second, or nil (= no timeout)
90
81
  @verbose = false
91
- @report_cpu = false
92
- @report_io = false
93
- @report_ctx_switch = false
94
- @logfile = STDOUT
82
+ @no_cpu = false
83
+ @no_disk = false
84
+ @devices = []
85
+ @logfile = "perfmonger.pgr"
95
86
 
96
87
  @parser = OptionParser.new
97
88
 
98
- @parser.on('-d', '--device DEVICE',
89
+ @parser.on('-d', '--disk DEVICE',
99
90
  'Device name to be monitored (e.g. sda, sdb, md0, dm-1).') do |device|
100
91
  @devices.push(device)
101
- @report_io = true
102
- end
103
-
104
- @parser.on('-D', '--all-devices',
105
- 'Monitor all block devices.') do
106
- @all_devices = true
107
- @report_io = true
92
+ @no_disk = false
108
93
  end
109
94
 
110
95
  @parser.on('-i', '--interval SEC',
@@ -127,12 +112,8 @@ class RecordOption
127
112
  @timeout = Float(timeout)
128
113
  end
129
114
 
130
- @parser.on('-C', '--cpu', 'Report CPU usage.') do
131
- @report_cpu = true
132
- end
133
-
134
- @parser.on('-S', '--context-switch', 'Report context switches per sec.') do
135
- @report_ctx_switch = true
115
+ @parser.on('--no-cpu', 'Suppress recording CPU usage.') do
116
+ @no_cpu = true
136
117
  end
137
118
 
138
119
  @parser.on('-l', '--logfile FILE') do |file|
@@ -70,12 +70,12 @@ EOS
70
70
  @hostname = hostname
71
71
  end
72
72
 
73
- @parser.on('--http-hostname NAME',
73
+ @parser.on('--http-host NAME',
74
74
  "Host name for HTTP server URL. If not specified, value of '--hostname' option is used.") do |hostname|
75
75
  @http_hostname = hostname
76
76
  end
77
77
 
78
- @parser.on('--http-port PORT', 'HTTP server port to listen.') do |port|
78
+ @parser.on('--port PORT', 'HTTP server port to listen.') do |port|
79
79
  if ! port =~ /\A\d+\Z/
80
80
  puts("ERROR: invalid port number value: #{port}")
81
81
  puts(@parser.help)
@@ -84,6 +84,11 @@ EOS
84
84
  @http_port = port.to_i
85
85
  end
86
86
 
87
+ @parser.on('-h', '--help', 'Show this help.') do
88
+ puts @parser.help
89
+ exit(false)
90
+ end
91
+
87
92
  # @parser.on('--tcp-port PORT', 'TCP data server port to listen.') do |port|
88
93
  # if ! port =~ /\A\d+\Z/
89
94
  # puts("ERROR: invalid port number value: #{port}")
@@ -43,15 +43,15 @@ class StatCommand < BaseCommand
43
43
  system(*@argv)
44
44
  end
45
45
  end
46
+
46
47
  Process.wait(command_pid)
48
+
47
49
  ensure
48
50
  @end_time = Time.now
49
51
  Process.kill(:INT, record_pid)
50
52
  Process.wait(record_pid)
51
53
  end
52
54
 
53
- puts("")
54
- printf("Execution time: %.4f\n", @end_time - @start_time)
55
55
  summary_command = SummaryCommand.new.run([@option.logfile], @argv.join(" "))
56
56
  end
57
57
  end
@@ -16,7 +16,7 @@ Run a command and gather performance information during its execution.
16
16
  Options:
17
17
  EOS
18
18
 
19
- @logfile = './perfmonger.log'
19
+ @logfile = './perfmonger.pgr'
20
20
  @json = false
21
21
 
22
22
  @parser.on('--json', "Output summary in JSON") do