perfmonger 0.6.1

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.
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