perfmonger 0.6.1 → 0.7.0
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.
- checksums.yaml +5 -13
- data/.gitignore +6 -0
- data/.tachikoma.yml +1 -0
- data/.travis.yml +18 -6
- data/Gemfile +1 -3
- data/Guardfile +26 -0
- data/NEWS +21 -0
- data/README.md +8 -9
- data/Rakefile +33 -1
- data/core/Makefile +23 -0
- data/core/build.sh +48 -0
- data/core/perfmonger-player.go +165 -0
- data/core/perfmonger-recorder.go +296 -0
- data/core/perfmonger-summarizer.go +207 -0
- data/core/subsystem/Makefile +3 -0
- data/core/subsystem/perfmonger.go +60 -0
- data/core/subsystem/perfmonger_darwin.go +22 -0
- data/core/subsystem/perfmonger_linux.go +292 -0
- data/core/subsystem/perfmonger_linux_test.go +73 -0
- data/core/subsystem/stat.go +214 -0
- data/core/subsystem/stat_test.go +281 -0
- data/core/subsystem/usage.go +410 -0
- data/core/subsystem/usage_test.go +496 -0
- data/lib/exec/operationBinding.rb.svn-base +59 -0
- data/lib/exec/perfmonger-player_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-player_linux_386 +0 -0
- data/lib/exec/perfmonger-player_linux_amd64 +0 -0
- data/lib/exec/perfmonger-recorder_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-recorder_linux_386 +0 -0
- data/lib/exec/perfmonger-recorder_linux_amd64 +0 -0
- data/lib/exec/perfmonger-summarizer_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-summarizer_linux_386 +0 -0
- data/lib/exec/perfmonger-summarizer_linux_amd64 +0 -0
- data/lib/exec/perfmonger-summary_linux_386 +0 -0
- data/lib/exec/perfmonger-summary_linux_amd64 +0 -0
- data/lib/perfmonger/cli.rb +8 -3
- data/lib/perfmonger/command/core.rb +62 -0
- data/lib/perfmonger/command/live.rb +39 -0
- data/lib/perfmonger/command/play.rb +56 -0
- data/lib/perfmonger/command/plot.rb +30 -22
- data/lib/perfmonger/command/record.rb +3 -2
- data/lib/perfmonger/command/record_option.rb +40 -59
- data/lib/perfmonger/command/server.rb +7 -2
- data/lib/perfmonger/command/stat.rb +2 -2
- data/lib/perfmonger/command/stat_option.rb +1 -1
- data/lib/perfmonger/command/summary.rb +11 -326
- data/lib/perfmonger/version.rb +1 -3
- data/lib/perfmonger.rb +3 -0
- data/misc/_perfmonger +128 -0
- data/misc/perfmonger-completion.bash +49 -0
- data/perfmonger.gemspec +6 -5
- data/spec/data/busy100.pgr +0 -0
- data/spec/fingerprint_spec.rb +35 -0
- data/spec/live_spec.rb +25 -0
- data/spec/perfmonger_spec.rb +37 -0
- data/spec/play_spec.rb +21 -0
- data/spec/plot_spec.rb +42 -0
- data/spec/record_spec.rb +15 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/stat_spec.rb +15 -0
- data/spec/summary_spec.rb +51 -0
- data/spec/support/aruba.rb +11 -0
- data/wercker.yml +59 -0
- metadata +117 -45
- data/ext/perfmonger/extconf.rb +0 -19
- data/ext/perfmonger/perfmonger.h +0 -58
- data/ext/perfmonger/perfmonger_record.c +0 -754
- data/ext/perfmonger/sysstat/common.c +0 -627
- data/ext/perfmonger/sysstat/common.h +0 -207
- data/ext/perfmonger/sysstat/ioconf.c +0 -515
- data/ext/perfmonger/sysstat/ioconf.h +0 -84
- data/ext/perfmonger/sysstat/iostat.c +0 -1100
- data/ext/perfmonger/sysstat/iostat.h +0 -121
- data/ext/perfmonger/sysstat/libsysstat.h +0 -19
- data/ext/perfmonger/sysstat/mpstat.c +0 -953
- data/ext/perfmonger/sysstat/mpstat.h +0 -79
- data/ext/perfmonger/sysstat/rd_stats.c +0 -2388
- data/ext/perfmonger/sysstat/rd_stats.h +0 -651
- data/ext/perfmonger/sysstat/sysconfig.h +0 -13
- data/test/run-test.sh +0 -39
- data/test/spec/bin_spec.rb +0 -37
- data/test/spec/data/2devices.expected +0 -42
- data/test/spec/data/2devices.output +0 -42
- data/test/spec/spec_helper.rb +0 -20
- data/test/spec/summary_spec.rb +0 -193
- data/test/test-perfmonger.c +0 -145
- 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
|
-
|
104
|
-
|
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(
|
137
|
+
File.open(json_file).each_line do |line|
|
130
138
|
record = JSON.parse(line)
|
131
139
|
time = record["time"]
|
132
|
-
|
133
|
-
return unless
|
140
|
+
diskinfo = record["disk"]
|
141
|
+
return unless diskinfo
|
134
142
|
|
135
143
|
start_time ||= time
|
136
|
-
devices ||=
|
144
|
+
devices ||= diskinfo["devices"]
|
137
145
|
|
138
146
|
datafile.puts([time - start_time,
|
139
147
|
devices.map{|device|
|
140
|
-
[
|
141
|
-
|
142
|
-
|
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(
|
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["
|
258
|
+
cpuinfo = record["cpu"]
|
251
259
|
return unless cpuinfo
|
252
|
-
nr_cpu = cpuinfo['
|
260
|
+
nr_cpu = cpuinfo['num_core']
|
253
261
|
|
254
|
-
cores = cpuinfo['
|
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
|
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 %
|
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(
|
332
|
+
File.open(json_file).each_line do |line|
|
325
333
|
record = JSON.parse(line)
|
326
334
|
time = record["time"]
|
327
|
-
cpurec = record["
|
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["
|
332
|
-
cpurec["
|
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 :
|
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
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
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
|
45
|
-
puts("ERROR:
|
36
|
+
if ! @recorder_bin
|
37
|
+
puts("ERROR: no executable binaries")
|
46
38
|
exit(false)
|
47
39
|
end
|
48
40
|
|
49
|
-
cmd = [
|
50
|
-
cmd <<
|
51
|
-
|
52
|
-
|
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 <<
|
57
|
-
cmd << @start_delay
|
47
|
+
cmd << "-start-delay"
|
48
|
+
cmd << "#{@start_delay*1000}ms"
|
58
49
|
end
|
59
50
|
if @timeout
|
60
|
-
cmd <<
|
61
|
-
cmd << @timeout
|
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
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
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
|
-
@
|
92
|
-
@
|
93
|
-
@
|
94
|
-
@logfile =
|
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', '--
|
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
|
-
@
|
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('-
|
131
|
-
@
|
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-
|
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('--
|
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
|