jkr 0.0.1 → 0.1.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 +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +81 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +674 -0
- data/{README.txt → README.rdoc} +0 -0
- data/Rakefile +4 -5
- data/bin/console +7 -0
- data/etc/example.plan +32 -0
- data/etc/zsh-comp.sh +82 -0
- data/exe/jkr +6 -0
- data/jkr.gemspec +31 -0
- data/lib/jkr.rb +13 -4
- data/lib/jkr/analysis.rb +5 -14
- data/lib/jkr/analytics.rb +75 -0
- data/lib/jkr/array.rb +47 -0
- data/lib/jkr/blktrace.rb +131 -0
- data/lib/jkr/cli.rb +110 -0
- data/lib/jkr/cpu_usage.rb +81 -0
- data/lib/jkr/cpufreq.rb +201 -0
- data/lib/jkr/dirlock.rb +9 -0
- data/lib/jkr/env.rb +17 -17
- data/lib/jkr/error.rb +5 -0
- data/lib/jkr/numeric.rb +28 -0
- data/lib/jkr/plan.rb +317 -26
- data/lib/jkr/planfinder.rb +40 -0
- data/lib/jkr/plot.rb +626 -0
- data/lib/jkr/stat.rb +2 -0
- data/lib/jkr/stat/kmeans-1d.rb +94 -0
- data/lib/jkr/su_cmd +163 -0
- data/lib/jkr/sysinfo.rb +34 -0
- data/lib/jkr/trial.rb +91 -16
- data/lib/jkr/userutils.rb +300 -22
- data/lib/jkr/utils.rb +38 -314
- data/lib/jkr/version.rb +3 -0
- data/sample-jkr.plan +52 -0
- metadata +171 -63
- data/bin/jkr +0 -224
- data/test/test_jkr.rb +0 -8
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
module Jkr
|
3
|
+
class PlanFinder
|
4
|
+
def initialize(jkr_env)
|
5
|
+
@jkr_env = jkr_env
|
6
|
+
end
|
7
|
+
|
8
|
+
def find_by_name(name, options = {})
|
9
|
+
options[:plan_search_path] ||= [@jkr_env.jkr_plan_dir]
|
10
|
+
|
11
|
+
options[:plan_search_path].each do |dir|
|
12
|
+
Dir.glob("#{dir}/*.plan").each do |path|
|
13
|
+
if File.basename(path, ".plan") == name
|
14
|
+
return path
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_by_result_id(ret_id)
|
23
|
+
ret_dir = Dir[sprintf("#{@jkr_env.jkr_result_dir}/%05d*", ret_id)].first
|
24
|
+
|
25
|
+
unless ret_dir
|
26
|
+
raise ArgumentError.new("Result not found: id=#{ret_id}")
|
27
|
+
end
|
28
|
+
|
29
|
+
plan_files = Dir["#{ret_dir}/*.plan"]
|
30
|
+
|
31
|
+
if plan_files.size < 1
|
32
|
+
raise RuntimeError.new("No plan file found: #{File.basename(ret_dir)}")
|
33
|
+
elsif plan_files.size > 1
|
34
|
+
raise RuntimeError.new("Multiple plan files found: #{File.basename(ret_dir)}")
|
35
|
+
end
|
36
|
+
|
37
|
+
plan_files.first
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/jkr/plot.rb
ADDED
@@ -0,0 +1,626 @@
|
|
1
|
+
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
def rel_path(basefile, path)
|
5
|
+
base = Pathname.new(File.dirname(basefile))
|
6
|
+
path = Pathname.new(path)
|
7
|
+
path.relative_path_from(base).to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def gnuplot_label_escape(str)
|
11
|
+
ret = str.gsub(/_/, "\\\\\\_").gsub(/\{/, "\\{").gsub(/\}/, "\\}")
|
12
|
+
ret
|
13
|
+
end
|
14
|
+
|
15
|
+
def plot_distribution(config)
|
16
|
+
dataset = config[:dataset]
|
17
|
+
xrange_max = config[:xrange_max]
|
18
|
+
xrange_min = config[:xrange_min] || 0
|
19
|
+
title = config[:title]
|
20
|
+
xlabel = config[:xlabel]
|
21
|
+
eps_file = config[:output]
|
22
|
+
datafile = if config[:datafile]
|
23
|
+
File.open(config[:datafile], "w")
|
24
|
+
else
|
25
|
+
Tempfile.new("dist")
|
26
|
+
end
|
27
|
+
if config[:gpfile]
|
28
|
+
gpfile = File.open(config[:gpfile], "w")
|
29
|
+
else
|
30
|
+
gpfile = Tempfile.new("plot_dist")
|
31
|
+
end
|
32
|
+
datafile_path = rel_path(gpfile.path, datafile)
|
33
|
+
|
34
|
+
stepnum = 500
|
35
|
+
|
36
|
+
plot_stmt = []
|
37
|
+
data_idx = 0
|
38
|
+
xrange_max_local = 0
|
39
|
+
histset = []
|
40
|
+
dataset.each do |tx_type,data|
|
41
|
+
next if data.empty?
|
42
|
+
hist = Array.new
|
43
|
+
avg = data.inject(&:+) / data.size.to_f
|
44
|
+
sterr = data.sterr
|
45
|
+
stdev = data.stdev
|
46
|
+
n90th_idx = (data.size * 0.9).to_i
|
47
|
+
n90percent = data.sort[n90th_idx]
|
48
|
+
xrange_max_local = [xrange_max_local, xrange_max || n90percent * 4].max
|
49
|
+
step = xrange_max_local / stepnum
|
50
|
+
maxidx = 0
|
51
|
+
data.each_with_index do |num, data_idx|
|
52
|
+
idx = (num / step).to_i
|
53
|
+
maxidx = [idx, maxidx].max
|
54
|
+
hist[idx] = (hist[idx] || 0) + 1
|
55
|
+
end
|
56
|
+
|
57
|
+
0.upto(maxidx) do |idx|
|
58
|
+
unless hist[idx]
|
59
|
+
hist[idx] = 0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
histset.push({:tx_type => tx_type, :step => step, :hist => hist, :max => hist.max})
|
64
|
+
|
65
|
+
histmax = hist.max.to_f
|
66
|
+
datafile.puts "##{tx_type}"
|
67
|
+
0.upto(stepnum - 1) do |i|
|
68
|
+
x = (i + 0.5) * step
|
69
|
+
y = hist[i] || 0
|
70
|
+
if config[:normalize]
|
71
|
+
y = y / histmax
|
72
|
+
end
|
73
|
+
datafile.puts "#{x}\t#{y}"
|
74
|
+
end
|
75
|
+
datafile.puts
|
76
|
+
datafile.puts
|
77
|
+
|
78
|
+
# index data_idx+1
|
79
|
+
datafile.puts "#{avg}\t0"
|
80
|
+
datafile.puts "#{avg}\t#{hist.max * 1.2}"
|
81
|
+
datafile.puts
|
82
|
+
datafile.puts
|
83
|
+
|
84
|
+
# index data_idx+2
|
85
|
+
datafile.puts "#{n90percent}\t0"
|
86
|
+
datafile.puts "#{n90percent}\t#{hist.max * 1.2}"
|
87
|
+
datafile.puts
|
88
|
+
datafile.puts
|
89
|
+
|
90
|
+
# index data_idx+3
|
91
|
+
datafile.puts "#{avg-sterr * 3}\t0"
|
92
|
+
datafile.puts "#{avg-sterr * 3}\t#{hist.max * 1.2}"
|
93
|
+
datafile.puts
|
94
|
+
datafile.puts
|
95
|
+
# index data_idx+4
|
96
|
+
datafile.puts "#{avg+sterr * 3}\t0"
|
97
|
+
datafile.puts "#{avg+sterr * 3}\t#{hist.max * 1.2}"
|
98
|
+
datafile.puts
|
99
|
+
|
100
|
+
plot_stmt.push(sprintf("'%s' index %d:%d using 1:2 with linespoints title '%s'",
|
101
|
+
datafile_path, data_idx, data_idx, tx_type))
|
102
|
+
if config[:show_avgline]
|
103
|
+
plot_stmt.push(sprintf("'%s' index %d:%d using 1:2 with lines lc 1 lt 2 lw 3 title '%s(avg)'",
|
104
|
+
datafile_path, data_idx+1, data_idx+1, tx_type))
|
105
|
+
end
|
106
|
+
if config[:show_90pline]
|
107
|
+
plot_stmt.push(sprintf("'%s' index %d:%d using 1:2 with lines lc 2 lt 2 lw 3 title '%s(90%%-th)'",
|
108
|
+
datafile_path, data_idx+2, data_idx+2, tx_type))
|
109
|
+
end
|
110
|
+
if config[:show_confinterval]
|
111
|
+
plot_stmt.push(sprintf("'%s' index %d:%d using 1:2 with lines lc 3 lt 3 lw 3 title '%s(std err)'",
|
112
|
+
datafile_path, data_idx+3, data_idx+3, tx_type))
|
113
|
+
plot_stmt.push(sprintf("'%s' index %d:%d using 1:2 with lines lc 3 lt 3 lw 3 title '%s(std err)'",
|
114
|
+
datafile_path, data_idx+4, data_idx+4, tx_type))
|
115
|
+
end
|
116
|
+
data_idx += 5
|
117
|
+
end
|
118
|
+
|
119
|
+
datafile.fsync
|
120
|
+
plot_stmt = plot_stmt.flatten.join(", \\\n ")
|
121
|
+
plot_stmt = "plot #{plot_stmt}"
|
122
|
+
|
123
|
+
script = <<EOS
|
124
|
+
set term postscript enhanced color
|
125
|
+
set output "#{rel_path(gpfile.path, eps_file)}"
|
126
|
+
set size 0.9,0.6
|
127
|
+
set title "#{gnuplot_label_escape(title)}"
|
128
|
+
set ylabel "Frequency"
|
129
|
+
set xlabel "#{gnuplot_label_escape(xlabel)}"
|
130
|
+
set xrange [#{xrange_min}:#{xrange_max_local}]
|
131
|
+
#{config[:other_options]}
|
132
|
+
#{plot_stmt}
|
133
|
+
EOS
|
134
|
+
gpfile.puts script
|
135
|
+
gpfile.fsync
|
136
|
+
Dir.chdir(File.dirname(gpfile.path)) do
|
137
|
+
system_("gnuplot #{gpfile.path}")
|
138
|
+
end
|
139
|
+
gpfile.close
|
140
|
+
end
|
141
|
+
|
142
|
+
def plot_timeseries(config)
|
143
|
+
[:plot_data, :output, :title, :xlabel, :ylabel].each do |key|
|
144
|
+
unless config[key]
|
145
|
+
raise ArgumentError.new("key '#{key.to_s}' is required for time-series graph")
|
146
|
+
return
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
xrange = if config[:xrange]
|
151
|
+
"set xrange #{config[:xrange]}"
|
152
|
+
else
|
153
|
+
""
|
154
|
+
end
|
155
|
+
yrange = if config[:yrange]
|
156
|
+
"set yrange #{config[:yrange]}"
|
157
|
+
else
|
158
|
+
""
|
159
|
+
end
|
160
|
+
|
161
|
+
if config[:gpfile]
|
162
|
+
gpfile = File.open(config[:gpfile], "w")
|
163
|
+
else
|
164
|
+
gpfile = Tempfile.new("plot_timeseries")
|
165
|
+
end
|
166
|
+
|
167
|
+
plot_stmt = "plot " + config[:plot_data].map {|plot_datum|
|
168
|
+
[:datafile, :using, :with, :title].each do |key|
|
169
|
+
unless plot_datum[key]
|
170
|
+
raise ArgumentError.new("key '#{key.to_s}' is required for a plot_datum of time-series graph")
|
171
|
+
return
|
172
|
+
end
|
173
|
+
end
|
174
|
+
index = ""
|
175
|
+
if plot_datum[:index]
|
176
|
+
index = " index #{plot_datum[:index]} "
|
177
|
+
end
|
178
|
+
"'#{rel_path(gpfile.path, plot_datum[:datafile])}' #{index} using #{plot_datum[:using]} with #{plot_datum[:with]}"+
|
179
|
+
" title '#{gnuplot_label_escape(plot_datum[:title])}' " + plot_datum[:other_options].to_s
|
180
|
+
}.join(", \\\n ")
|
181
|
+
|
182
|
+
script = <<EOS
|
183
|
+
set term postscript enhanced color
|
184
|
+
set output "#{rel_path(gpfile.path, config[:output])}"
|
185
|
+
set size 0.9,0.6
|
186
|
+
set title "#{gnuplot_label_escape(config[:title])}"
|
187
|
+
set ylabel "#{config[:ylabel]}"
|
188
|
+
set xlabel "#{config[:xlabel]}"
|
189
|
+
set rmargin 3
|
190
|
+
set lmargin 10
|
191
|
+
#{xrange}
|
192
|
+
#{yrange}
|
193
|
+
set grid
|
194
|
+
#{config[:other_options]}
|
195
|
+
#{plot_stmt}
|
196
|
+
EOS
|
197
|
+
gpfile.puts script
|
198
|
+
gpfile.fsync
|
199
|
+
Dir.chdir(File.dirname(gpfile.path)) do
|
200
|
+
system_("gnuplot #{gpfile.path}")
|
201
|
+
end
|
202
|
+
gpfile.close
|
203
|
+
end
|
204
|
+
|
205
|
+
def plot_bar(config)
|
206
|
+
[:output, :title, :series_labels, :item_labels, :data].each do |key|
|
207
|
+
unless config[key]
|
208
|
+
raise StandardError.new("key '#{key.to_s}' is required for bar graph")
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
config[:size] ||= "0.9,0.6"
|
213
|
+
|
214
|
+
data = config[:data]
|
215
|
+
|
216
|
+
if ! data.all?{|series| series.all?{|datum| datum[:value].is_a? Numeric}}
|
217
|
+
raise StandardError.new("All datum must have :value key")
|
218
|
+
end
|
219
|
+
|
220
|
+
if config[:datafile]
|
221
|
+
datafile = File.open(config[:datafile], "w")
|
222
|
+
else
|
223
|
+
datafile = Tempfile.new("plot_bar")
|
224
|
+
end
|
225
|
+
if config[:gpfile]
|
226
|
+
gpfile = File.open(config[:gpfile], "w")
|
227
|
+
else
|
228
|
+
gpfile = Tempfile.new("plot_bar")
|
229
|
+
end
|
230
|
+
datafile_path = rel_path(gpfile.path, datafile.path)
|
231
|
+
|
232
|
+
config[:item_label_angle] ||= -30
|
233
|
+
|
234
|
+
plot_data = []
|
235
|
+
plot_stdev_data = []
|
236
|
+
|
237
|
+
if data.all?{|series| series.all?{|datum| datum[:stdev].is_a? Numeric}}
|
238
|
+
draw_stdev = true
|
239
|
+
else
|
240
|
+
draw_stdev = false
|
241
|
+
end
|
242
|
+
|
243
|
+
item_barwidth = 0.8 # 2.0 / 3.0
|
244
|
+
num_serieses = data.size
|
245
|
+
data_idx = 0
|
246
|
+
config[:data].each_with_index do |series, series_idx|
|
247
|
+
series.each_with_index do |datum, item_idx|
|
248
|
+
xpos = item_idx - item_barwidth / 2.0 + item_barwidth / num_serieses.to_f / 2.0 + item_barwidth / num_serieses.to_f * series_idx
|
249
|
+
barwidth = item_barwidth / num_serieses.to_f
|
250
|
+
datafile.puts([xpos, datum[:value], barwidth, (datum[:stdev] || "")].join("\t"))
|
251
|
+
end
|
252
|
+
|
253
|
+
plot_data.push({
|
254
|
+
:title => config[:series_labels][series_idx],
|
255
|
+
:using => "1:2:3",
|
256
|
+
:index => "#{data_idx}:#{data_idx}",
|
257
|
+
:with => "with boxes fs solid 0.7",
|
258
|
+
})
|
259
|
+
|
260
|
+
if series.every?{|datum| datum[:stdev]}
|
261
|
+
plot_data.push({
|
262
|
+
:title => nil,
|
263
|
+
:using => "1:2:4",
|
264
|
+
:index => "#{data_idx}:#{data_idx}",
|
265
|
+
:with => "with yerrorbars lc 1 lt 1 pt 0",
|
266
|
+
})
|
267
|
+
end
|
268
|
+
|
269
|
+
datafile.puts("\n\n")
|
270
|
+
data_idx += 1
|
271
|
+
end
|
272
|
+
datafile.fsync
|
273
|
+
|
274
|
+
ylabel = if config[:ylabel]
|
275
|
+
"set ylabel '#{config[:ylabel]}'"
|
276
|
+
else
|
277
|
+
""
|
278
|
+
end
|
279
|
+
|
280
|
+
yrange = if config[:yrange]
|
281
|
+
"set yrange #{config[:yrange]}"
|
282
|
+
else
|
283
|
+
""
|
284
|
+
end
|
285
|
+
|
286
|
+
plot_stmt = "plot " + plot_data.map do |plot_datum|
|
287
|
+
[:using].each do |key|
|
288
|
+
unless plot_datum[key]
|
289
|
+
raise StandardError.new("key '#{key.to_s}' is required for a plot_datum of bar graph")
|
290
|
+
return
|
291
|
+
end
|
292
|
+
end
|
293
|
+
index = ""
|
294
|
+
if plot_datum[:index]
|
295
|
+
index = " index #{plot_datum[:index]} "
|
296
|
+
end
|
297
|
+
if plot_datum[:title]
|
298
|
+
title = "title '#{gnuplot_label_escape(plot_datum[:title])}'"
|
299
|
+
else
|
300
|
+
title = "notitle"
|
301
|
+
end
|
302
|
+
"'#{rel_path(gpfile.path, datafile.path)}' #{index} using #{plot_datum[:using]}"+
|
303
|
+
" #{title} #{plot_datum[:with]} "
|
304
|
+
end.join(", \\\n ")
|
305
|
+
|
306
|
+
xpos = -1
|
307
|
+
xtics = config[:item_labels].map do |label|
|
308
|
+
xpos += 1
|
309
|
+
"\"#{label}\" #{xpos}"
|
310
|
+
end.join(",")
|
311
|
+
xtics = "(#{xtics})"
|
312
|
+
xrange = "[-0.5:#{config[:item_labels].size - 0.5}]"
|
313
|
+
|
314
|
+
script = <<EOS
|
315
|
+
set term postscript enhanced color
|
316
|
+
set output "#{rel_path(gpfile.path, config[:output])}"
|
317
|
+
set size #{config[:size]}
|
318
|
+
set title "#{gnuplot_label_escape(config[:title])}"
|
319
|
+
#{ylabel}
|
320
|
+
#{yrange}
|
321
|
+
set xrange #{xrange}
|
322
|
+
set xtic rotate by #{config[:item_label_angle]} scale 0
|
323
|
+
set xtics #{xtics}
|
324
|
+
#{config[:other_options]}
|
325
|
+
#{plot_stmt}
|
326
|
+
EOS
|
327
|
+
gpfile.puts script
|
328
|
+
gpfile.fsync
|
329
|
+
Dir.chdir(File.dirname(gpfile.path)) do
|
330
|
+
system_("gnuplot #{gpfile.path}")
|
331
|
+
end
|
332
|
+
gpfile.close
|
333
|
+
end
|
334
|
+
|
335
|
+
def plot_scatter(config)
|
336
|
+
[:plot_data, :output, :xlabel, :ylabel].each do |key|
|
337
|
+
unless config.keys.include?(key)
|
338
|
+
raise ArgumentError.new("key '#{key.to_s}' is required for scatter graph")
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
xrange = if config[:xrange]
|
343
|
+
"set xrange #{config[:xrange]}"
|
344
|
+
else
|
345
|
+
""
|
346
|
+
end
|
347
|
+
yrange = if config[:yrange]
|
348
|
+
"set yrange #{config[:yrange]}"
|
349
|
+
else
|
350
|
+
""
|
351
|
+
end
|
352
|
+
if config[:gpfile]
|
353
|
+
gpfile = File.open(config[:gpfile], "w")
|
354
|
+
else
|
355
|
+
gpfile = Tempfile.new("gnuplot")
|
356
|
+
end
|
357
|
+
|
358
|
+
plot_stmt = "plot " + config[:plot_data].map {|plot_datum|
|
359
|
+
unless plot_datum[:expression] ||
|
360
|
+
[:datafile, :using].every?{|key| plot_datum[key]}
|
361
|
+
raise ArgumentError.new("key ('datafile', 'using', 'with') or 'expression' is required for a plot_datum")
|
362
|
+
end
|
363
|
+
|
364
|
+
plot_target = nil
|
365
|
+
if plot_datum[:expression]
|
366
|
+
plot_target = plot_datum[:expression]
|
367
|
+
else
|
368
|
+
index = ""
|
369
|
+
if plot_datum[:index]
|
370
|
+
index = " index #{plot_datum[:index]} "
|
371
|
+
end
|
372
|
+
|
373
|
+
plot_target = "'#{rel_path(gpfile.path, plot_datum[:datafile])}' #{index} using #{plot_datum[:using]}"
|
374
|
+
end
|
375
|
+
|
376
|
+
unless plot_datum[:title]
|
377
|
+
title = "notitle"
|
378
|
+
else
|
379
|
+
title = "title '#{gnuplot_label_escape(plot_datum[:title])}'"
|
380
|
+
end
|
381
|
+
|
382
|
+
if plot_datum[:with]
|
383
|
+
with = "with #{plot_datum[:with]}"
|
384
|
+
else
|
385
|
+
with = ""
|
386
|
+
end
|
387
|
+
"#{plot_target} #{with} #{title} " + plot_datum[:other_options].to_s
|
388
|
+
}.join(", \\\n ")
|
389
|
+
|
390
|
+
title_stmt = "unset title"
|
391
|
+
if config[:title]
|
392
|
+
title_stmt = "set title \"#{gnuplot_label_escape(config[:title])}\""
|
393
|
+
end
|
394
|
+
|
395
|
+
case config[:output]
|
396
|
+
when /\.svg\Z/
|
397
|
+
terminal = 'svg'
|
398
|
+
else
|
399
|
+
terminal = 'postscript enhanced color'
|
400
|
+
end
|
401
|
+
|
402
|
+
script = <<EOS
|
403
|
+
set term #{terminal}
|
404
|
+
set output "#{rel_path(gpfile.path, config[:output])}"
|
405
|
+
#{if config[:size]; then "set size " + config[:size]; else; ""; end}
|
406
|
+
#{title_stmt}
|
407
|
+
set ylabel "#{gnuplot_label_escape(config[:ylabel])}"
|
408
|
+
set xlabel "#{gnuplot_label_escape(config[:xlabel])}"
|
409
|
+
set rmargin 10
|
410
|
+
set lmargin 10
|
411
|
+
#{xrange}
|
412
|
+
#{yrange}
|
413
|
+
set grid
|
414
|
+
#{config[:other_options]}
|
415
|
+
#{plot_stmt}
|
416
|
+
EOS
|
417
|
+
gpfile.puts script
|
418
|
+
gpfile.fsync
|
419
|
+
Dir.chdir(File.dirname(gpfile.path)) do
|
420
|
+
system_("gnuplot #{gpfile.path}")
|
421
|
+
end
|
422
|
+
gpfile.close
|
423
|
+
end
|
424
|
+
|
425
|
+
def plot_mpstat_data(mpstat_data, option)
|
426
|
+
option[:dir] ||= "mpstat"
|
427
|
+
option[:start_time] ||= mpstat_data.first[:time]
|
428
|
+
option[:end_time] ||= mpstat_data[-1][:time]
|
429
|
+
|
430
|
+
if ! Dir.exists?(option[:dir])
|
431
|
+
FileUtils.mkdir_p(option[:dir])
|
432
|
+
end
|
433
|
+
|
434
|
+
datafile = File.open(File.join(option[:dir],
|
435
|
+
"mpstat.tsv"),
|
436
|
+
"w")
|
437
|
+
|
438
|
+
start_time = option[:start_time]
|
439
|
+
end_time = option[:end_time]
|
440
|
+
|
441
|
+
data_idx = 0
|
442
|
+
nr_cpu = mpstat_data.first[:data].size - 1
|
443
|
+
(nr_cpu + 1).times do |cpu_idx|
|
444
|
+
scale = 1.0
|
445
|
+
if cpu_idx < nr_cpu
|
446
|
+
label = cpu_idx.to_s
|
447
|
+
else
|
448
|
+
label = "ALL"
|
449
|
+
scale = nr_cpu.to_f
|
450
|
+
end
|
451
|
+
|
452
|
+
datafile.puts("# cpu#{label}")
|
453
|
+
mpstat_data.each do |rec|
|
454
|
+
t = rec[:time] - start_time
|
455
|
+
|
456
|
+
if cpu_idx < nr_cpu
|
457
|
+
data = rec[:data].find{|x| x[:cpu] == cpu_idx}
|
458
|
+
else
|
459
|
+
data = rec[:data].find{|x| x[:cpu] == "all"}
|
460
|
+
end
|
461
|
+
datafile.puts([t,
|
462
|
+
data[:usr] * scale,
|
463
|
+
data[:nice] * scale,
|
464
|
+
data[:sys] * scale,
|
465
|
+
data[:iowait] * scale,
|
466
|
+
data[:irq] * scale,
|
467
|
+
data[:soft] * scale,
|
468
|
+
data[:steal] * scale,
|
469
|
+
data[:idle] * scale].map(&:to_s).join("\t"))
|
470
|
+
end
|
471
|
+
datafile.puts("\n\n")
|
472
|
+
datafile.fsync
|
473
|
+
|
474
|
+
plot_scatter(:output => File.join(option[:dir],
|
475
|
+
"cpu#{label}.eps"),
|
476
|
+
:gpfile => File.join(option[:dir],
|
477
|
+
"gp_cpu#{label}.gp"),
|
478
|
+
:title => nil,
|
479
|
+
:xlabel => "elapsed time [sec]",
|
480
|
+
:ylabel => "CPU usage [%]",
|
481
|
+
:xrange => "[0:#{end_time - start_time}]",
|
482
|
+
:yrange => "[0:#{105 * scale}]",
|
483
|
+
:plot_data => [{
|
484
|
+
:title => "%usr",
|
485
|
+
:using => "1:2",
|
486
|
+
:index => "#{data_idx}:#{data_idx}",
|
487
|
+
:with => "filledcurve x1",
|
488
|
+
:datafile => datafile.path
|
489
|
+
},
|
490
|
+
{
|
491
|
+
:title => "%nice",
|
492
|
+
:using => "1:($2+$3)",
|
493
|
+
:index => "#{data_idx}:#{data_idx}",
|
494
|
+
:with => "filledcurve x1",
|
495
|
+
:datafile => datafile.path
|
496
|
+
},
|
497
|
+
{
|
498
|
+
:title => "%sys",
|
499
|
+
:using => "1:($2+$3+$4)",
|
500
|
+
:index => "#{data_idx}:#{data_idx}",
|
501
|
+
:with => "filledcurve x1",
|
502
|
+
:datafile => datafile.path
|
503
|
+
},
|
504
|
+
{
|
505
|
+
:title => "%iowait",
|
506
|
+
:using => "1:($2+$3+$4+$5)",
|
507
|
+
:index => "#{data_idx}:#{data_idx}",
|
508
|
+
:with => "filledcurve x1",
|
509
|
+
:datafile => datafile.path
|
510
|
+
},
|
511
|
+
{
|
512
|
+
:title => "%irq",
|
513
|
+
:using => "1:($2+$3+$4+$5+$6)",
|
514
|
+
:index => "#{data_idx}:#{data_idx}",
|
515
|
+
:with => "filledcurve x1",
|
516
|
+
:datafile => datafile.path
|
517
|
+
},
|
518
|
+
{
|
519
|
+
:title => "%soft",
|
520
|
+
:using => "1:($2+$3+$4+$5+$6+$7)",
|
521
|
+
:index => "#{data_idx}:#{data_idx}",
|
522
|
+
:with => "filledcurve x1",
|
523
|
+
:datafile => datafile.path
|
524
|
+
},
|
525
|
+
{
|
526
|
+
:title => "%steal",
|
527
|
+
:using => "1:($2+$3+$4+$5+$6+$7+$8)",
|
528
|
+
:index => "#{data_idx}:#{data_idx}",
|
529
|
+
:with => "filledcurve x1",
|
530
|
+
:datafile => datafile.path
|
531
|
+
}].reverse,
|
532
|
+
:size => "0.9,0.9",
|
533
|
+
:other_options => <<EOS
|
534
|
+
set rmargin 3
|
535
|
+
set lmargin 5
|
536
|
+
set key below
|
537
|
+
EOS
|
538
|
+
)
|
539
|
+
|
540
|
+
data_idx += 1
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
def plot_io_pgr_data(pgr_data, option)
|
545
|
+
option[:dir] ||= "io_pgr"
|
546
|
+
option[:start_time] ||= pgr_data.first["time"]
|
547
|
+
option[:end_time] ||= pgr_data[-1]["time"]
|
548
|
+
|
549
|
+
if ! Dir.exists?(option[:dir])
|
550
|
+
FileUtils.mkdir_p(option[:dir])
|
551
|
+
end
|
552
|
+
|
553
|
+
start_time = option[:start_time]
|
554
|
+
end_time = option[:end_time]
|
555
|
+
|
556
|
+
datafile = File.open(File.join(option[:dir],
|
557
|
+
"io_pgr.tsv"),
|
558
|
+
"w")
|
559
|
+
devices = pgr_data.first["ioinfo"]["devices"]
|
560
|
+
|
561
|
+
idx = 0
|
562
|
+
devices.each do |device|
|
563
|
+
do_read = false
|
564
|
+
do_write = false
|
565
|
+
unless pgr_data.all?{|rec| rec["ioinfo"][device]['r/s'] < 0.1}
|
566
|
+
do_read = true
|
567
|
+
end
|
568
|
+
unless pgr_data.all?{|rec| rec["ioinfo"][device]['w/s'] < 0.1}
|
569
|
+
do_read = true
|
570
|
+
end
|
571
|
+
|
572
|
+
if do_read == false && do_write == false
|
573
|
+
$stderr.puts("#{device} performs no I/O")
|
574
|
+
next
|
575
|
+
end
|
576
|
+
|
577
|
+
datafile.puts("# #{device}")
|
578
|
+
pgr_data.each do |rec|
|
579
|
+
datafile.puts([rec["time"] - start_time,
|
580
|
+
rec["ioinfo"][device]['r/s'],
|
581
|
+
rec["ioinfo"][device]['w/s'],
|
582
|
+
].map(&:to_s).join("\t"))
|
583
|
+
end
|
584
|
+
datafile.puts("\n\n")
|
585
|
+
datafile.fsync
|
586
|
+
|
587
|
+
plot_data = []
|
588
|
+
if do_read
|
589
|
+
plot_data.push({
|
590
|
+
:title => "read",
|
591
|
+
:datafile => datafile.path,
|
592
|
+
:using => "1:2",
|
593
|
+
:index => "#{idx}:#{idx}",
|
594
|
+
:with => "lines"
|
595
|
+
})
|
596
|
+
end
|
597
|
+
if do_write
|
598
|
+
plot_data.push({
|
599
|
+
:title => "write",
|
600
|
+
:datafile => datafile.path,
|
601
|
+
:using => "1:3",
|
602
|
+
:index => "#{idx}:#{idx}",
|
603
|
+
:with => "lines"
|
604
|
+
})
|
605
|
+
end
|
606
|
+
|
607
|
+
idx += 1
|
608
|
+
|
609
|
+
plot_scatter(:output => File.join(option[:dir],
|
610
|
+
device + ".eps"),
|
611
|
+
:gpfile => File.join(option[:dir],
|
612
|
+
"gp_" + device + ".gp"),
|
613
|
+
:xlabel => "elapsed time [sec]",
|
614
|
+
:ylabel => "IOPS",
|
615
|
+
:xrange => "[0:#{end_time - start_time}]",
|
616
|
+
:yrange => "[0:]",
|
617
|
+
:title => "IO performance",
|
618
|
+
:plot_data => plot_data,
|
619
|
+
:other_options => <<EOS
|
620
|
+
set rmargin 3
|
621
|
+
set lmargin 10
|
622
|
+
set key below
|
623
|
+
EOS
|
624
|
+
)
|
625
|
+
end
|
626
|
+
end
|