perfmonger 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +15 -0
  2. data/.dir-locals.el +2 -0
  3. data/.gitignore +4 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +12 -0
  6. data/COPYING +674 -0
  7. data/Gemfile +5 -0
  8. data/HOWTO.md +15 -0
  9. data/NEWS +115 -0
  10. data/README.md +61 -0
  11. data/Rakefile +8 -0
  12. data/bin/perfmonger +6 -0
  13. data/data/NOTICE +8 -0
  14. data/data/Twitter_Bootstrap_LICENSE.txt +176 -0
  15. data/data/assets/css/bootstrap-responsive.css +1109 -0
  16. data/data/assets/css/bootstrap.css +6167 -0
  17. data/data/assets/css/perfmonger.css +17 -0
  18. data/data/assets/dashboard.erb +319 -0
  19. data/data/assets/img/glyphicons-halflings-white.png +0 -0
  20. data/data/assets/img/glyphicons-halflings.png +0 -0
  21. data/data/assets/js/bootstrap.js +2280 -0
  22. data/data/assets/js/bootstrap.min.js +6 -0
  23. data/data/assets/js/canvasjs.js +9042 -0
  24. data/data/assets/js/canvasjs.min.js +271 -0
  25. data/data/sysstat.ioconf +268 -0
  26. data/ext/perfmonger/extconf.rb +19 -0
  27. data/ext/perfmonger/perfmonger.h +58 -0
  28. data/ext/perfmonger/perfmonger_record.c +754 -0
  29. data/ext/perfmonger/sysstat/common.c +627 -0
  30. data/ext/perfmonger/sysstat/common.h +207 -0
  31. data/ext/perfmonger/sysstat/ioconf.c +515 -0
  32. data/ext/perfmonger/sysstat/ioconf.h +84 -0
  33. data/ext/perfmonger/sysstat/iostat.c +1100 -0
  34. data/ext/perfmonger/sysstat/iostat.h +121 -0
  35. data/ext/perfmonger/sysstat/libsysstat.h +19 -0
  36. data/ext/perfmonger/sysstat/mpstat.c +953 -0
  37. data/ext/perfmonger/sysstat/mpstat.h +79 -0
  38. data/ext/perfmonger/sysstat/rd_stats.c +2388 -0
  39. data/ext/perfmonger/sysstat/rd_stats.h +651 -0
  40. data/ext/perfmonger/sysstat/sysconfig.h +13 -0
  41. data/lib/perfmonger/cli.rb +115 -0
  42. data/lib/perfmonger/command/base_command.rb +39 -0
  43. data/lib/perfmonger/command/fingerprint.rb +453 -0
  44. data/lib/perfmonger/command/plot.rb +429 -0
  45. data/lib/perfmonger/command/record.rb +32 -0
  46. data/lib/perfmonger/command/record_option.rb +149 -0
  47. data/lib/perfmonger/command/server.rb +294 -0
  48. data/lib/perfmonger/command/stat.rb +60 -0
  49. data/lib/perfmonger/command/stat_option.rb +29 -0
  50. data/lib/perfmonger/command/summary.rb +402 -0
  51. data/lib/perfmonger/config.rb +6 -0
  52. data/lib/perfmonger/version.rb +5 -0
  53. data/lib/perfmonger.rb +12 -0
  54. data/misc/release-howto.txt +17 -0
  55. data/misc/sample-cpu.png +0 -0
  56. data/misc/sample-read-iops.png +0 -0
  57. data/perfmonger.gemspec +44 -0
  58. data/test/run-test.sh +39 -0
  59. data/test/spec/bin_spec.rb +37 -0
  60. data/test/spec/data/2devices.expected +42 -0
  61. data/test/spec/data/2devices.output +42 -0
  62. data/test/spec/spec_helper.rb +20 -0
  63. data/test/spec/summary_spec.rb +193 -0
  64. data/test/test-perfmonger.c +145 -0
  65. data/test/test.h +9 -0
  66. metadata +154 -0
@@ -0,0 +1,402 @@
1
+
2
+ require 'optparse'
3
+ require 'json'
4
+
5
+ module PerfMonger
6
+ module Command
7
+
8
+ class SummaryCommand < BaseCommand
9
+ register_command 'summary', "Show a summary of a perfmonger log file"
10
+
11
+ def initialize
12
+ @parser = OptionParser.new
13
+ @parser.banner = <<EOS
14
+ Usage: perfmonger summary [options] LOG_FILE
15
+
16
+ Options:
17
+ EOS
18
+
19
+ @json = false
20
+ @pager = nil
21
+
22
+ @parser.on('--json', "Output summary in JSON") do
23
+ @json = true
24
+ end
25
+
26
+ @parser.on('-p', '--pager [PAGER]', "Use pager to see summary output.") do |pager|
27
+ if pager.nil?
28
+ if ENV['PAGER'].nil?
29
+ puts("ERROR: No pager is available.")
30
+ puts("ERROR: Please set PAGER or give pager name to --pager option.")
31
+ puts(@parser.help)
32
+ exit(false)
33
+ else
34
+ @pager = ENV['PAGER']
35
+ end
36
+ else
37
+ @pager = pager
38
+ end
39
+ end
40
+ end
41
+
42
+ def parse_args(argv)
43
+ @parser.parse!(argv)
44
+
45
+ if argv.size == 0
46
+ puts("ERROR: PerfMonger log file is required")
47
+ puts(@parser.help)
48
+ exit(false)
49
+ end
50
+
51
+ @logfile = argv.shift
52
+ if ! File.exists?(@logfile)
53
+ puts("ERROR: No such file: #{@logfile}")
54
+ puts(@parser.help)
55
+ exit(false)
56
+ end
57
+ end
58
+
59
+ def run(argv, summary_title = nil)
60
+ parse_args(argv)
61
+
62
+ summary_title ||= @logfile
63
+
64
+ show_summary(@logfile, summary_title)
65
+ end
66
+
67
+
68
+ def read_logfile(logfile)
69
+ File.read(logfile).lines.map do |line|
70
+ begin
71
+ JSON.parse(line)
72
+ rescue JSON::ParserError => err
73
+ nil
74
+ end
75
+ end.compact
76
+ end
77
+
78
+ def make_accumulation(records)
79
+ unless records.all?{|record| record.has_key?("ioinfo")}
80
+ return nil
81
+ end
82
+ unless records.size > 1
83
+ return nil
84
+ end
85
+
86
+ accum = Hash.new
87
+
88
+ devices = records.first["ioinfo"]["devices"]
89
+ accum["ioinfo"] = Hash.new
90
+
91
+ devices.each do |device|
92
+ read_requests = 0
93
+ read_bytes = 0
94
+ write_requests = 0
95
+ write_bytes = 0
96
+
97
+ (1..(records.size - 1)).each do |idx|
98
+ last_record = records[idx - 1]
99
+ record = records[idx]
100
+ dt = record["time"] - last_record["time"]
101
+
102
+ read_requests += record["ioinfo"][device]["riops"] * dt
103
+ write_requests += record["ioinfo"][device]["wiops"] * dt
104
+ read_bytes += record["ioinfo"][device]["rsecps"] * 512 * dt
105
+ write_bytes += record["ioinfo"][device]["wsecps"] * 512 * dt
106
+ end
107
+
108
+ accum["ioinfo"][device] = Hash.new
109
+ accum["ioinfo"][device]["read_requests"] = read_requests
110
+ accum["ioinfo"][device]["read_bytes"] = read_bytes
111
+ accum["ioinfo"][device]["write_requests"] = write_requests
112
+ accum["ioinfo"][device]["write_bytes"] = write_bytes
113
+ end
114
+
115
+ accum
116
+ end
117
+
118
+ def make_summary(records)
119
+ if records.empty?
120
+ return nil
121
+ elsif records.size == 1
122
+ return records.first
123
+ end
124
+
125
+ # setup getters and setters all attributes for avg. calculation
126
+ # getter.call(record) returns value
127
+ # setter.call(record, value) set value
128
+ # getters and setters include attribute info as a closure
129
+ getters = []
130
+ setters = []
131
+
132
+ if records.first.include?("ioinfo")
133
+ records.first["ioinfo"]["devices"].each do |device|
134
+ records.first["ioinfo"][device].keys.each do |attr|
135
+ getters << lambda do |record|
136
+ record["ioinfo"][device][attr]
137
+ end
138
+ setters << lambda do |record, value|
139
+ record["ioinfo"][device][attr] = value
140
+ end
141
+ end
142
+ end
143
+
144
+ records.first["ioinfo"]["total"].keys.each do |attr|
145
+ getters << lambda do |record|
146
+ record["ioinfo"]["total"][attr]
147
+ end
148
+ setters << lambda do |record, value|
149
+ record["ioinfo"]["total"][attr] = value
150
+ end
151
+ end
152
+ end
153
+
154
+ if records.first.include?("cpuinfo")
155
+ records.first["cpuinfo"]["all"].keys.each do |attr|
156
+ getters << lambda do |record|
157
+ record["cpuinfo"]["all"][attr]
158
+ end
159
+ setters << lambda do |record, value|
160
+ record["cpuinfo"]["all"][attr] = value
161
+ end
162
+ end
163
+
164
+ records.first["cpuinfo"]["nr_cpu"].times do |cpu_idx|
165
+ records.first["cpuinfo"]["cpus"][cpu_idx].keys.each do |attr|
166
+ getters << lambda do |record|
167
+ record["cpuinfo"]["cpus"][cpu_idx][attr]
168
+ end
169
+ setters << lambda do |record, value|
170
+ record["cpuinfo"]["cpus"][cpu_idx][attr] = value
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ avg_record = Marshal.load(Marshal.dump(records.first)); # deep copy
177
+
178
+ setters.each do |setter|
179
+ setter.call(avg_record, 0.0)
180
+ end
181
+
182
+ (1..(records.size - 1)).each do |idx|
183
+ record = records[idx]
184
+
185
+ last_t = records[idx - 1]["time"]
186
+ t = record["time"]
187
+
188
+ getters.size.times do |_etters_idx|
189
+ getter = getters[_etters_idx]
190
+ setter = setters[_etters_idx]
191
+
192
+ setter.call(avg_record,
193
+ getter.call(avg_record) + getter.call(record) * (t - last_t))
194
+ end
195
+ end
196
+
197
+ getters.size.times do |_etters_idx|
198
+ getter = getters[_etters_idx]
199
+ setter = setters[_etters_idx]
200
+
201
+ setter.call(avg_record,
202
+ getter.call(avg_record) / (records[-1]["time"] - records[0]["time"]))
203
+ end
204
+
205
+
206
+ # r_await/w_await need special handling
207
+ if records.first.include?("ioinfo")
208
+ records.first["ioinfo"]["devices"].each do |device|
209
+ accum_r_io_time = 0.0
210
+ accum_w_io_time = 0.0
211
+ r_io_count = 0
212
+ w_io_count = 0
213
+
214
+ (records.size - 1).times do |idx|
215
+ rec0 = records[idx]
216
+ rec1 = records[idx + 1]
217
+ dev_ioinfo = rec1["ioinfo"][device]
218
+ dt = rec1["time"] - rec0["time"]
219
+
220
+ accum_r_io_time += dev_ioinfo["r_await"] * dev_ioinfo["riops"] * dt
221
+ accum_w_io_time += dev_ioinfo["w_await"] * dev_ioinfo["wiops"] * dt
222
+ r_io_count += dev_ioinfo["riops"] * dt
223
+ w_io_count += dev_ioinfo["wiops"] * dt
224
+ end
225
+
226
+ if r_io_count > 0
227
+ avg_record["ioinfo"][device]["r_await"] = accum_r_io_time / r_io_count
228
+ else
229
+ avg_record["ioinfo"][device]["r_await"] = 0.0
230
+ end
231
+
232
+ if w_io_count > 0
233
+ avg_record["ioinfo"][device]["w_await"] = accum_w_io_time / w_io_count
234
+ else
235
+ avg_record["ioinfo"][device]["w_await"] = 0.0
236
+ end
237
+ end
238
+ end
239
+
240
+ avg_record
241
+ end
242
+
243
+ def show_summary(logfile, summary_title)
244
+ records = read_logfile(logfile)
245
+ summary = make_summary(records)
246
+ accum = make_accumulation(records)
247
+
248
+ duration = records.last["time"] - records.first["time"]
249
+
250
+ if @json
251
+ output = Hash.new
252
+
253
+ output["duration"] = duration
254
+ if summary
255
+ if summary["cpuinfo"]
256
+ output["cpuinfo"] = summary["cpuinfo"]
257
+ end
258
+
259
+ if summary['ioinfo']
260
+ output["ioinfo"] = summary["ioinfo"]
261
+ end
262
+ end
263
+
264
+ puts output.to_json
265
+ else
266
+ if $stdout.tty? && @pager
267
+ output_file = IO.popen(@pager, "w")
268
+ else
269
+ output_file = $stdout
270
+ end
271
+
272
+ output_file.puts("")
273
+ output_file.puts("== Performance summary of '#{summary_title}' ==")
274
+ output_file.puts("")
275
+ duration_str = sprintf("%.2f", duration)
276
+ output_file.puts("record duration: #{duration_str} sec")
277
+
278
+ if summary.nil?
279
+ output_file.puts("")
280
+ output_file.puts("No performance info was collected.")
281
+ output_file.puts("This is because command execution time was too short, or something went wrong.")
282
+ end
283
+
284
+ if summary && summary["cpuinfo"]
285
+ nr_cpu = records.first["cpuinfo"]["nr_cpu"]
286
+
287
+ usr, sys, iowait, irq, soft, idle =
288
+ [summary['cpuinfo']['all']['usr'] + summary['cpuinfo']['all']['nice'],
289
+ summary['cpuinfo']['all']['sys'],
290
+ summary['cpuinfo']['all']['iowait'],
291
+ summary['cpuinfo']['all']['irq'],
292
+ summary['cpuinfo']['all']['soft'],
293
+ summary['cpuinfo']['all']['idle']].map do |val|
294
+ val * nr_cpu
295
+ end
296
+
297
+ other = [100.0 - (usr + sys + iowait + irq + soft + idle), 0.0].max * nr_cpu
298
+
299
+ usr_str, sys_str, iowait_str, irq_str, soft_str, other_str, idle_str =
300
+ [usr, sys, iowait, irq, soft, other, idle].map do |value|
301
+ sprintf("%.2f", value)
302
+ end
303
+
304
+ total_non_idle_str = sprintf("%.2f", usr + sys + irq + soft + other)
305
+ total_idle_str = sprintf("%.2f", iowait + idle)
306
+
307
+ output_file.puts("")
308
+ output_file.puts <<EOS
309
+ * Average CPU usage (MAX: #{100 * nr_cpu} %)
310
+ * Non idle portion: #{total_non_idle_str}
311
+ %usr: #{usr_str}
312
+ %sys: #{sys_str}
313
+ %irq: #{irq_str}
314
+ %soft: #{soft_str}
315
+ %other: #{other_str}
316
+ * Idle portion: #{total_idle_str}
317
+ %iowait: #{iowait_str}
318
+ %idle: #{idle_str}
319
+ EOS
320
+ end
321
+
322
+ if summary && summary['ioinfo']
323
+ total_r_iops, total_w_iops, total_r_sec, total_w_sec = [0.0] * 4
324
+
325
+ summary['ioinfo']['devices'].each do |device|
326
+ r_iops, w_iops, r_sec, w_sec, r_await, w_await =
327
+ [summary['ioinfo'][device]['riops'],
328
+ summary['ioinfo'][device]['wiops'],
329
+ summary['ioinfo'][device]['rsecps'] * 512 / 1024.0 / 1024.0,
330
+ summary['ioinfo'][device]['wsecps'] * 512 / 1024.0 / 1024.0,
331
+ summary['ioinfo'][device]['r_await'],
332
+ summary['ioinfo'][device]['w_await']]
333
+
334
+ total_r_iops += r_iops
335
+ total_w_iops += w_iops
336
+ total_r_sec += r_sec
337
+ total_w_sec += w_sec
338
+
339
+ r_iops_str, w_iops_str, r_sec_str, w_sec_str = [r_iops, w_iops, r_sec, w_sec].map do |value|
340
+ sprintf("%.2f", value)
341
+ end
342
+
343
+ r_await_str, w_await_str = [r_await, w_await].map do |await|
344
+ if await < 1.0
345
+ sprintf("%.1f usec", await * 1000)
346
+ else
347
+ sprintf("%.2f msec", await)
348
+ end
349
+ end
350
+
351
+ total_r_bytes_str, total_w_bytes_str = ["read_bytes", "write_bytes"].map do |key|
352
+ bytes = accum["ioinfo"][device][key]
353
+ if bytes > 2**30
354
+ sprintf("%.2f GB", bytes / 2**30)
355
+ elsif bytes > 2**20
356
+ sprintf("%.2f MB", bytes / 2**20)
357
+ elsif bytes > 2**10
358
+ sprintf("%.2f KB", bytes / 2**10)
359
+ else
360
+ sprintf("%.2f bytes", bytes)
361
+ end
362
+ end
363
+
364
+
365
+ output_file.puts("")
366
+ output_file.puts("* Average DEVICE usage: #{device}")
367
+ output_file.puts(" read IOPS: #{r_iops_str}")
368
+ output_file.puts(" write IOPS: #{w_iops_str}")
369
+ output_file.puts(" read throughput: #{r_sec_str} MB/s")
370
+ output_file.puts(" write throughput: #{w_sec_str} MB/s")
371
+ output_file.puts(" read latency: #{r_await_str}")
372
+ output_file.puts(" write latency: #{w_await_str}")
373
+ output_file.puts(" read amount: #{total_r_bytes_str}")
374
+ output_file.puts(" write amount: #{total_w_bytes_str}")
375
+ end
376
+
377
+ if summary['ioinfo']['devices'].size > 1
378
+ total_r_iops_str, total_w_iops_str, total_r_sec_str, total_w_sec_str =
379
+ [total_r_iops, total_w_iops, total_r_sec, total_w_sec].map do |value|
380
+ sprintf("%.2f", value)
381
+ end
382
+
383
+ output_file.puts("")
384
+ output_file.puts("* TOTAL DEVICE usage: #{summary['ioinfo']['devices'].join(', ')}")
385
+ output_file.puts(" read IOPS: #{total_r_iops_str}")
386
+ output_file.puts(" write IOPS: #{total_w_iops_str}")
387
+ output_file.puts(" read throughput: #{total_r_sec_str} MB/s")
388
+ output_file.puts(" write throughput: #{total_w_sec_str} MB/s")
389
+ end
390
+
391
+ output_file.puts("")
392
+ end
393
+
394
+ if output_file != $stdout
395
+ output_file.close
396
+ end
397
+ end
398
+ end
399
+ end
400
+
401
+ end # module Command
402
+ end # module PerfMonger
@@ -0,0 +1,6 @@
1
+ # This file is automatically generated by Autoconf: 2014-06-23 19:42:25
2
+
3
+ module PerfMonger
4
+ ROOTDIR = File.expand_path("../../..", __FILE__)
5
+ DATAROOTDIR = File.expand_path("../../../data", __FILE__)
6
+ end
@@ -0,0 +1,5 @@
1
+ # This file is automatically generated by Autoconf: 2014-06-23 19:42:25
2
+
3
+ module PerfMonger
4
+ VERSION = "0.6.1"
5
+ end
data/lib/perfmonger.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'perfmonger/version.rb'
2
+ require 'perfmonger/config.rb'
3
+ require 'perfmonger/cli.rb'
4
+ require 'perfmonger/command/base_command.rb'
5
+ require 'perfmonger/command/record.rb'
6
+ require 'perfmonger/command/record_option.rb'
7
+ require 'perfmonger/command/stat.rb'
8
+ require 'perfmonger/command/stat_option.rb'
9
+ require 'perfmonger/command/summary.rb'
10
+ require 'perfmonger/command/plot.rb'
11
+ require 'perfmonger/command/server.rb'
12
+ require 'perfmonger/command/fingerprint.rb'
@@ -0,0 +1,17 @@
1
+ リリース手順
2
+
3
+ 1. make check
4
+ 2. rake spec
5
+ 3. リリースノート書く
6
+ 3. rpm生成
7
+ * chrootでrpm生成
8
+ * gpgで署名
9
+ 4. tarball生成
10
+ 5. タグ付け
11
+ 6. ファイル公開
12
+ * yumにアップロード
13
+ * tarballアップロード
14
+ 7. freecode リリース登録
15
+ 8. Webサイト更新
16
+ 9. 告知エントリ書く
17
+
Binary file
Binary file
@@ -0,0 +1,44 @@
1
+ # -*- mode: ruby -*-
2
+
3
+ $:.push File.expand_path("../lib", __FILE__)
4
+ require 'perfmonger'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'perfmonger'
8
+ s.version = PerfMonger::VERSION
9
+ s.date = '2015-01-19'
10
+ s.summary = "yet anothor performance measurement/monitoring tool"
11
+ s.description = "yet anothor performance measurement/monitoring tool"
12
+ s.authors = ["Yuto HAYAMIZU"]
13
+ s.email = 'y.hayamizu@gmail.com'
14
+ s.homepage = 'http://github.com/hayamiz/perfmonger/'
15
+ s.license = 'GPL-2'
16
+
17
+ s.required_ruby_version = '>= 1.9.0'
18
+
19
+ s.add_development_dependency "rake"
20
+ s.add_development_dependency "rspec"
21
+ s.add_development_dependency "rake-compiler"
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
26
+
27
+ s.extensions << 'ext/perfmonger/extconf.rb'
28
+
29
+ s.post_install_message = <<EOS
30
+
31
+ ============================================================
32
+
33
+ Thank you for installing perfmonger.
34
+ Try to start performance monitoring with:
35
+
36
+ perfmonger record
37
+
38
+ Enjoy.
39
+
40
+ ============================================================
41
+
42
+ EOS
43
+
44
+ end
data/test/run-test.sh ADDED
@@ -0,0 +1,39 @@
1
+ #!/bin/sh
2
+
3
+ export BASE_DIR="`dirname $0`"
4
+ export TEST_DIR="$(readlink -f $(dirname $0))"
5
+ top_dir="$BASE_DIR/.."
6
+
7
+ if test -z "$NO_MAKE"; then
8
+ make -C $top_dir > /dev/null || exit 1
9
+ fi
10
+
11
+ if test -z "$CUTTER"; then
12
+ CUTTER="`make -s -C $BASE_DIR echo-cutter`"
13
+ fi
14
+
15
+ if ! test -z "$DEBUG"; then
16
+ WRAPPER="gdb --args"
17
+ elif ! test -z "$MEMCHECK"; then
18
+ VGLOG=`mktemp`
19
+ WRAPPER="valgrind --leak-check=summary --track-origins=yes --log-file=${VGLOG}"
20
+ fi
21
+
22
+ # MOCK_SO=$(readlink -f $(find -name mock.so | head -n1))
23
+ # if ! test -z "$MOCK_SO"; then
24
+ # export LD_PRELOAD="$MOCK_SO"
25
+ # fi
26
+
27
+ $WRAPPER $CUTTER --keep-opening-modules -s $BASE_DIR "$@" $BASE_DIR
28
+ RET=$?
29
+
30
+ # show log file of valgrind
31
+ if ! test -z "$MEMCHECK"; then
32
+ if ! test -z "$PAGER"; then
33
+ $PAGER $VGLOG
34
+ else
35
+ cat $VGLOG
36
+ fi
37
+ fi
38
+
39
+ exit $RET
@@ -0,0 +1,37 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe "PerfmongerCommand" do
5
+ before(:each) do
6
+ @perfmonger_command = File.expand_path('../../src/perfmonger', __FILE__)
7
+ end
8
+
9
+ it "should be an executable" do
10
+ File.executable?(@perfmonger_command).should be_true
11
+ end
12
+
13
+ it 'should print version number if --version specified' do
14
+ `#{@perfmonger_command} --version`.should include(PerfMonger::VERSION)
15
+ end
16
+
17
+ describe 'stat subcommand' do
18
+ it 'should print "Execution time: XXX.XXX"' do
19
+ if File.exists?("/proc/diskstats")
20
+ `#{@perfmonger_command} stat -- sleep 1`.should match(/^Execution time: (\d+)\.(\d+)$/)
21
+ else
22
+ # do nothing
23
+ true.should be_true
24
+ end
25
+ end
26
+ end
27
+
28
+ describe 'summary subcommand' do
29
+ it 'should print expected output with 2devices.log' do
30
+ File.open(data_file('2devices.output'), "w") do |f|
31
+ f.print(`#{@perfmonger_command} summary #{data_file('2devices.log')}`)
32
+ end
33
+
34
+ system("diff -u #{data_file('2devices.expected')} #{data_file('2devices.output')}").should be_true
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,42 @@
1
+
2
+ == Performance summary of 'spec/data/2devices.log' ==
3
+
4
+ record duration: 1.00 sec
5
+
6
+ * Average CPU usage (MAX: 200 %)
7
+ * Non idle portion: 200.00
8
+ %usr: 0.00
9
+ %sys: 200.00
10
+ %irq: 0.00
11
+ %soft: 0.00
12
+ %other: 0.00
13
+ * Idle portion: 0.00
14
+ %iowait: 0.00
15
+ %idle: 0.00
16
+
17
+ * Average DEVICE usage: sda
18
+ read IOPS: 1.00
19
+ write IOPS: 0.00
20
+ read throughput: 0.00 MB/s
21
+ write throughput: 0.00 MB/s
22
+ read latency: 53.00 msec
23
+ write latency: 0.0 usec
24
+ read amount: 512.00 bytes
25
+ write amount: 0.00 bytes
26
+
27
+ * Average DEVICE usage: sdb
28
+ read IOPS: 0.00
29
+ write IOPS: 0.00
30
+ read throughput: 0.00 MB/s
31
+ write throughput: 0.00 MB/s
32
+ read latency: 0.0 usec
33
+ write latency: 0.0 usec
34
+ read amount: 0.00 bytes
35
+ write amount: 0.00 bytes
36
+
37
+ * TOTAL DEVICE usage: sda, sdb
38
+ read IOPS: 1.00
39
+ write IOPS: 0.00
40
+ read throughput: 0.00 MB/s
41
+ write throughput: 0.00 MB/s
42
+
@@ -0,0 +1,42 @@
1
+
2
+ == Performance summary of 'spec/data/2devices.log' ==
3
+
4
+ record duration: 1.00 sec
5
+
6
+ * Average CPU usage (MAX: 200 %)
7
+ * Non idle portion: 200.00
8
+ %usr: 0.00
9
+ %sys: 200.00
10
+ %irq: 0.00
11
+ %soft: 0.00
12
+ %other: 0.00
13
+ * Idle portion: 0.00
14
+ %iowait: 0.00
15
+ %idle: 0.00
16
+
17
+ * Average DEVICE usage: sda
18
+ read IOPS: 1.00
19
+ write IOPS: 0.00
20
+ read throughput: 0.00 MB/s
21
+ write throughput: 0.00 MB/s
22
+ read latency: 53.00 msec
23
+ write latency: 0.0 usec
24
+ read amount: 512.00 bytes
25
+ write amount: 0.00 bytes
26
+
27
+ * Average DEVICE usage: sdb
28
+ read IOPS: 0.00
29
+ write IOPS: 0.00
30
+ read throughput: 0.00 MB/s
31
+ write throughput: 0.00 MB/s
32
+ read latency: 0.0 usec
33
+ write latency: 0.0 usec
34
+ read amount: 0.00 bytes
35
+ write amount: 0.00 bytes
36
+
37
+ * TOTAL DEVICE usage: sda, sdb
38
+ read IOPS: 1.00
39
+ write IOPS: 0.00
40
+ read throughput: 0.00 MB/s
41
+ write throughput: 0.00 MB/s
42
+
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ $LOAD_PATH << File.expand_path('../../src/ruby', __FILE__)
4
+
5
+ TEST_DATA_DIR = File.expand_path('../data', __FILE__)
6
+
7
+ require 'perfmonger'
8
+ require 'tempfile'
9
+ require 'pathname'
10
+
11
+ def data_file(rel_path)
12
+ from = Pathname.new(Dir.pwd)
13
+ path = Pathname.new(File.expand_path(rel_path, TEST_DATA_DIR))
14
+
15
+ path.relative_path_from(from).to_s
16
+ end
17
+
18
+ RSpec.configure do |config|
19
+ # RSpec config here
20
+ end