ppbench-locked 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/bin/ppbench.rb ADDED
@@ -0,0 +1,1012 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ppbench'
4
+ require 'commander/import'
5
+ require 'terminal-table'
6
+ require 'json'
7
+
8
+ # Description constants used by the help command.
9
+ #
10
+ MACHINES_DESCRIPTION = 'Consider only specific machines (e.g. m3.large,m3.xlarge); comma separated list.'
11
+ EXPERIMENTS_DESCRIPTION = 'Consider only specific experiments (e.g. bare,docker,weave); comma separated list.'
12
+ RECWINDOW_DESCRIPTION = 'Standard Receive Window. Defaults to 87380 byte (Window is not plotted if set to 0).'
13
+ YAXIS_MAX_DESCRIPTION = 'Maximum Y value on the Y axis (defaults to biggest value found).'
14
+ YAXIS_STEPS_DESCRIPTION = 'How many ticks shall be plotted on yaxis (defaults to 10).'
15
+ XAXIS_MAX_DESCRIPTION = 'Maximum X value on the X axis (defaults to biggest message size found).'
16
+ XAXIS_STEPS_DESCRIPTION = 'How many ticks shall be plotted on xaxis (defaults to 10).'
17
+ PRECISION_DESCRIPTION = 'Amount of points used per series for plotting medians, comparisons and confidence intervals.'
18
+ CONFIDENCE_DESCRIPTION = 'Percent value for confidence bands. Defaults to 90%.'
19
+ WITHBANDS_DESCRIPTION = 'Plots confidence bands (confidence bands are _not_ plotted by default).'
20
+ NOPOINTS_DESCRIPTION = 'Show no points (points are plotted by default).'
21
+ NAMING_DESCRIPTION = 'Use user defined names via an JSON file.'
22
+ ALPHA_DESCRIPTION = "Transparency (alpha) for points of scatter plots (defaults to 0.05, must be between 0.0 and 1.0)"
23
+ PDF_DESCRIPTION = 'Adds additional commands to an R script, so that it can be used to generate a PDF file.'
24
+ PDF_WIDTH_DESCRIPTION = 'Width of plot in inch (defaults to 7 inch, only useful with PDF output).'
25
+ PDF_HEIGHT_DESCRIPTION = 'Height of plot in inch (defaults to 7 inch, only useful with PDF output).'
26
+
27
+ # Plotting constants used for plotting.
28
+ #
29
+ RECWINDOW_DEFAULT = 87380
30
+ CONFIDENCE_DEFAULT = 90
31
+ AXIS_STEP_DEFAULT = 10
32
+ COMPARISON_MAX_DEFAULT = 2.0
33
+ MIN_PRECISION_DEFAULT = 20
34
+ PRECISION_DEFAULT = 1000
35
+ ALPHA_DEFAULT = 0.05
36
+
37
+ # Constants used for PDF generation.
38
+ #
39
+ PDF_HEIGHT_WIDTH_DEFAULT = 7
40
+
41
+ # Constants used to define benchmarking
42
+ #
43
+ COVERAGE_DEFAULT = 0.05
44
+
45
+
46
+ program :name, 'ppbench'
47
+ program :version, "#{Ppbench::VERSION}"
48
+ program :description, 'Ping pong benchmark'
49
+ program :help, 'Author', 'Nane Kratzke <nane.kratzke@fh-luebeck.de>'
50
+
51
+ global_option '--precision POINTS', Integer, PRECISION_DESCRIPTION
52
+ global_option '--naming FILE', String, NAMING_DESCRIPTION
53
+ global_option '--alpha FLOAT', Float, ALPHA_DESCRIPTION
54
+
55
+ default_command :help
56
+
57
+ # Validates and processes global options like
58
+ # - precision (used for comparison lines, median lines and confidence band plotting)
59
+ # - naming (used for user defined naming of machine and experiment tags)
60
+ #
61
+
62
+ def validate_global_options(args, options)
63
+ options.default :precision => PRECISION_DEFAULT
64
+ options.default :naming => ''
65
+ options.default :alpha => ALPHA_DEFAULT
66
+
67
+ if options.precision < MIN_PRECISION_DEFAULT
68
+ $stderr.puts("Error in --precision flag: Precision must be >= 20 points.\n")
69
+ exit!
70
+ end
71
+
72
+ if options.precision < 0
73
+ $stderr.puts("Error in --precision flag: Precision must be >= 1 point.\n")
74
+ exit!
75
+ end
76
+
77
+ Ppbench::precision = options.precision
78
+
79
+ if !options.naming.empty? && !File.exist?(options.naming)
80
+ $stderr.puts("Error in --naming flag: File '#{options.naming}' does not exist.")
81
+ exit!
82
+ end
83
+
84
+ Ppbench::naming = {} if options.naming.empty?
85
+
86
+ unless options.naming.empty?
87
+ begin
88
+ file = File.read(options.naming)
89
+ Ppbench::naming = JSON.parse(file)
90
+ rescue Exception => ex
91
+ $stderr.puts("Error in naming file '#{options.naming}'. Does not seem to be a valid JSON file.")
92
+ exit!
93
+ end
94
+ end
95
+
96
+ if options.alpha < 0.0 || options.alpha > 1.0
97
+ $stderr.puts("Error in --alpha flag: Alpha must be between 0.0 and 1.0, but alpha was '#{options.alpha}'.")
98
+ exit!
99
+ end
100
+
101
+ Ppbench::alpha = options.alpha
102
+ end
103
+
104
+ # Validates command line flags of the run command.
105
+ #
106
+ def validate_run_options(args, options)
107
+
108
+ if (options.machine.empty?)
109
+ $stderr.puts("You have to tag your benchmark data with the --machine flag.\n")
110
+ exit!
111
+ end
112
+
113
+ if (options.experiment.empty?)
114
+ $stderr.puts("You have to tag your benchmark data with the --experiment flag.\n")
115
+ exit!
116
+ end
117
+
118
+ if options.coverage < 0 || options.coverage > 1.0
119
+ $stderr.puts("Error in --coverage flag: Coverage must be in [0..1.0]\n")
120
+ exit!
121
+ end
122
+
123
+ if options.repetitions < 1
124
+ $stderr.puts("Error in --repetitions flag: Repetitions must be >= 1\n")
125
+ exit!
126
+ end
127
+
128
+ if options.concurrency < 1
129
+ $stderr.puts("Error in --concurrency flag: Concurrency must be >= 1\n")
130
+ exit!
131
+ end
132
+
133
+ if options.timeout < 1
134
+ $stderr.puts("Error in --timeout flag: Timeout must be >= 1 seconds\n")
135
+ exit!
136
+ end
137
+
138
+ if args.empty?
139
+ $stderr.puts("You have to specify a log file.\n")
140
+ exit!
141
+ end
142
+
143
+ if args.length > 1
144
+ $stderr.puts("You should only specify one log file. You specified #{args.length} logfiles.\n")
145
+ exit!
146
+ end
147
+
148
+ if File.exist?(args[0])
149
+ $stderr.puts("Logfile #{args[0]} already exists. You do not want to overwrite collected benchmark data.\n")
150
+ exit!
151
+ end
152
+
153
+ end
154
+
155
+ # Validates command line flags of the xyz-comparison-plot commands.
156
+ #
157
+ def validate_comparison_options(args, options)
158
+
159
+ if args.empty?
160
+ $stderr.puts("You have to provide benchmark files (*.csv) to analyze.")
161
+ exit!
162
+ end
163
+
164
+ if options.recwindow < 0
165
+ $stderr.puts("Error in --recwindow flag: TCP standard receive window must be >= 0 bytes.\n")
166
+ exit!
167
+ end
168
+
169
+ if options.yaxis_max < 0
170
+ $stderr.puts("Error in --yaxis_max flag: Maximum value on yaxis must be >= 0.\n")
171
+ end
172
+
173
+ if options.xaxis_max < 0
174
+ $stderr.puts("Error in --xaxis_max flag: Maximum value on xaxis must be >= 0.\n")
175
+ exit!
176
+ end
177
+
178
+ if options.xaxis_steps <= 0
179
+ $stderr.puts("Error in --xaxis_steps flag: You must provide a positive step > 0.\n")
180
+ exit!
181
+ end
182
+
183
+ end
184
+
185
+ # Validates command line flags of the xyz-plot commands.
186
+ #
187
+ def validate_plot_options(args, options)
188
+
189
+ if args.empty?
190
+ $stderr.puts("You have to provide benchmark files (*.csv) to analyze.")
191
+ exit!
192
+ end
193
+
194
+ if options.recwindow < 0
195
+ $stderr.puts("Error in --recwindow flag: TCP standard receive window must be >= 0 bytes\n")
196
+ exit!
197
+ end
198
+
199
+ if options.confidence < 0 || options.confidence > 100
200
+ $stderr.puts("Error in --confidence flag: Confidence interval must be between 0 and 100 %.\n")
201
+ exit!
202
+ end
203
+
204
+ if options.yaxis_max < 0
205
+ $stderr.puts("Error in --yaxis_max flag: Maximum value on yaxis must be >= 0.\n")
206
+ end
207
+
208
+ if options.yaxis_steps <= 0
209
+ $stderr.puts("Error in --yaxis_steps flag: You must provide a positive step > 0.\n")
210
+ exit!
211
+ end
212
+
213
+ if options.xaxis_max < 0
214
+ $stderr.puts("Error in --xaxis_max flag: Maximum value on xaxis must be >= 0.\n")
215
+ exit!
216
+ end
217
+
218
+ if options.xaxis_steps <= 0
219
+ $stderr.puts("Error in --xaxis_steps flag: You must provide a positive step > 0.\n")
220
+ exit!
221
+ end
222
+
223
+ if options.nopoints && !options.withbands
224
+ $stderr.puts("Error in --nopoints flag. You must use --withbands if applying --nopoints. Otherwise nothing would be plotted.\n")
225
+ exit!
226
+ end
227
+
228
+ end
229
+
230
+ # Validates command line options dealing with PDF generation.
231
+ #
232
+ def validate_pdf_options(args, options)
233
+ if options.height < 1
234
+ $stderr.puts("Error in --height flag. You must provide a positive height >= 1 in inch.\n")
235
+ exit!
236
+ end
237
+
238
+ if options.width < 1
239
+ $stderr.puts("Error in --width flag. You must provide a positive width >= 1 in inch.\n")
240
+ exit!
241
+ end
242
+ end
243
+
244
+ # Validates command line options for the naming-template command.
245
+ #
246
+ def validate_naming_options(args, options)
247
+ if args.empty?
248
+ $stderr.puts("Error due to missing files to analyze. You must provide at least one log file (csv).\n")
249
+ exit!
250
+ end
251
+
252
+ if !options.update.empty? && !File.exist?(options.update)
253
+ $stderr.puts("Error: File #{options.update} does not exist.\n")
254
+ exit!
255
+ end
256
+ end
257
+
258
+ # Implements the run command.
259
+ #
260
+ def run(args, options)
261
+
262
+ logfile = args[0]
263
+
264
+ Ppbench::run_bench(
265
+ options.host,
266
+ logfile,
267
+ machine_tag: options.machine,
268
+ experiment_tag: options.experiment,
269
+ coverage: options.coverage,
270
+ min: options.min,
271
+ max: options.max,
272
+ concurrency: options.concurrency,
273
+ repetitions: options.repetitions,
274
+ timeout: options.timeout
275
+ )
276
+ end
277
+
278
+ # Embeds a R script (content) into some PDF generating
279
+ # R statements.
280
+ #
281
+ def pdfout(content, file: 'output.pdf', width: 7, height: 7)
282
+ """
283
+ pdf('#{file}', width=#{width}, height=#{height})
284
+ #{content}
285
+ dev.off()
286
+ """
287
+ end
288
+
289
+ # Implements the transfer-plot command.
290
+ #
291
+ def transfer_plot(args, options)
292
+
293
+ experiments = options.experiments.split(',')
294
+ machines = options.machines.split(',')
295
+
296
+ data = Ppbench::load_data(args)
297
+ filtered_data = Ppbench::filter(
298
+ data,
299
+ experiments: experiments,
300
+ machines: machines
301
+ )
302
+ aggregated_data = Ppbench::aggregate(filtered_data)
303
+
304
+ max_x = Ppbench::maximum(aggregated_data, of: :length)
305
+ max_y = Ppbench::maximum(aggregated_data, of: :transfer_rate)
306
+
307
+ rplot = Ppbench::plotter(
308
+ aggregated_data,
309
+ to_plot: :transfer_rate,
310
+ machines: machines,
311
+ experiments: experiments,
312
+ receive_window: options.recwindow,
313
+ xaxis_max: options.xaxis_max == 0 ? max_x : options.xaxis_max,
314
+ confidence: options.confidence,
315
+ no_points: options.nopoints,
316
+ with_bands: options.withbands,
317
+ yaxis_max: options.yaxis_max == 0 ? max_y : options.yaxis_max,
318
+ yaxis_steps: options.yaxis_steps,
319
+ xaxis_steps: options.xaxis_steps,
320
+ title: "Data Transfer Rates",
321
+ subtitle: "bigger is better",
322
+ xaxis_title: "Message Size",
323
+ xaxis_unit: "kB",
324
+ yaxis_title: "Transfer Rate",
325
+ yaxis_unit: "MB/sec"
326
+ )
327
+
328
+ pdf = pdfout(rplot, file: options.pdf, width: options.width, height: options.height)
329
+ print("#{pdf}") unless options.pdf.empty?
330
+ print("#{rplot}") if options.pdf.empty?
331
+ end
332
+
333
+ # Implements the transfer-comparison-plot command.
334
+ #
335
+ def transfer_comparison_plot(args, options)
336
+
337
+ experiments = options.experiments.split(',')
338
+ machines = options.machines.split(',')
339
+
340
+ data = Ppbench::load_data(args)
341
+ filtered_data = Ppbench::filter(
342
+ data,
343
+ experiments: experiments,
344
+ machines: machines
345
+ )
346
+ aggregated_data = Ppbench::aggregate(filtered_data)
347
+
348
+ max_x = Ppbench::maximum(aggregated_data, of: :length)
349
+
350
+ rplot = Ppbench::comparison_plotter(
351
+ aggregated_data,
352
+ yaxis_max: options.yaxis_max,
353
+ to_plot: :transfer_rate,
354
+ machines: machines,
355
+ experiments: experiments,
356
+ receive_window: options.recwindow,
357
+ xaxis_max: options.xaxis_max == 0 ? max_x : options.xaxis_max,
358
+ xaxis_steps: options.xaxis_steps,
359
+ title: "Data transfer in relative comparison",
360
+ subtitle: "bigger is better",
361
+ xaxis_title: "Message Size",
362
+ xaxis_unit: "kB",
363
+ xaxis_divisor: 1000,
364
+ yaxis_title: "Ratio"
365
+ )
366
+
367
+ pdf = pdfout(rplot, file: options.pdf, width: options.width, height: options.height)
368
+ print("#{pdf}") unless options.pdf.empty?
369
+ print("#{rplot}") if options.pdf.empty?
370
+
371
+ end
372
+
373
+ # Implements the request-plot command.
374
+ #
375
+ def request_plot(args, options)
376
+
377
+ experiments = options.experiments.split(',')
378
+ machines = options.machines.split(',')
379
+
380
+ data = Ppbench::load_data(args)
381
+ filtered_data = Ppbench::filter(
382
+ data,
383
+ experiments: experiments,
384
+ machines: machines
385
+ )
386
+ aggregated_data = Ppbench::aggregate(filtered_data)
387
+
388
+ max_x = Ppbench::maximum(aggregated_data, of: :length)
389
+ max_y = Ppbench::maximum(aggregated_data, of: :rps)
390
+
391
+ rplot = Ppbench::plotter(
392
+ aggregated_data,
393
+ to_plot: :rps,
394
+ machines: machines,
395
+ experiments: experiments,
396
+ receive_window: options.recwindow,
397
+ xaxis_max: options.xaxis_max == 0 ? max_x : options.xaxis_max,
398
+ confidence: options.confidence,
399
+ no_points: options.nopoints,
400
+ with_bands: options.withbands,
401
+ yaxis_max: options.yaxis_max == 0 ? max_y : options.yaxis_max,
402
+ yaxis_steps: options.yaxis_steps,
403
+ xaxis_steps: options.xaxis_steps,
404
+ title: "Requests per seconds",
405
+ subtitle: "bigger is better",
406
+ xaxis_title: "Message Size",
407
+ xaxis_unit: "kB",
408
+ yaxis_title: "Requests per seconds",
409
+ yaxis_unit: "Req/sec",
410
+ yaxis_divisor: 1
411
+ )
412
+
413
+ pdf = pdfout(rplot, file: options.pdf, width: options.width, height: options.height)
414
+ print("#{pdf}") unless options.pdf.empty?
415
+ print("#{rplot}") if options.pdf.empty?
416
+ end
417
+
418
+ # Implements the request-comparison-plot command
419
+ #
420
+ def request_comparison_plot(args, options)
421
+
422
+ experiments = options.experiments.split(',')
423
+ machines = options.machines.split(',')
424
+
425
+ data = Ppbench::load_data(args)
426
+ filtered_data = Ppbench::filter(
427
+ data,
428
+ experiments: experiments,
429
+ machines: machines
430
+ )
431
+ aggregated_data = Ppbench::aggregate(filtered_data)
432
+
433
+ max_x = Ppbench::maximum(aggregated_data, of: :length)
434
+
435
+ rplot = Ppbench::comparison_plotter(
436
+ aggregated_data,
437
+ yaxis_max: options.yaxis_max,
438
+ to_plot: :rps,
439
+ machines: machines,
440
+ experiments: experiments,
441
+ receive_window: options.recwindow,
442
+ xaxis_max: options.xaxis_max == 0 ? max_x : options.xaxis_max,
443
+ xaxis_steps: options.xaxis_steps,
444
+ title: "Requests per second in relative comparison",
445
+ subtitle: "bigger is better",
446
+ xaxis_title: "Message Size",
447
+ xaxis_unit: "kB",
448
+ xaxis_divisor: 1000,
449
+ yaxis_title: "Ratio",
450
+ )
451
+
452
+ pdf = pdfout(rplot, file: options.pdf, width: options.width, height: options.height)
453
+ print("#{pdf}") unless options.pdf.empty?
454
+ print("#{rplot}") if options.pdf.empty?
455
+ end
456
+
457
+ # Implements the latency-plot command.
458
+ #
459
+ def latency_plot(args, options)
460
+
461
+ experiments = options.experiments.split(',')
462
+ machines = options.machines.split(',')
463
+
464
+ data = Ppbench::load_data(args)
465
+ filtered_data = Ppbench::filter(
466
+ data,
467
+ experiments: experiments,
468
+ machines: machines
469
+ )
470
+ aggregated_data = Ppbench::aggregate(filtered_data)
471
+
472
+ max_y = Ppbench::maximum(aggregated_data, of: :tpr)
473
+ max_x = Ppbench::maximum(aggregated_data, of: :length)
474
+
475
+ rplot = Ppbench::plotter(
476
+ aggregated_data,
477
+ to_plot: :tpr,
478
+ machines: machines,
479
+ experiments: experiments,
480
+ receive_window: options.recwindow,
481
+ xaxis_max: options.xaxis_max == 0 ? max_x : options.xaxis_max,
482
+ confidence: options.confidence,
483
+ no_points: options.nopoints,
484
+ with_bands: options.withbands,
485
+ yaxis_max: options.yaxis_max == 0 ? max_y : options.yaxis_max,
486
+ yaxis_steps: options.yaxis_steps,
487
+ xaxis_steps: options.xaxis_steps,
488
+ title: "Round-trip latency",
489
+ subtitle: "smaller is better",
490
+ xaxis_title: "Message Size",
491
+ xaxis_unit: "kB",
492
+ yaxis_title: "Latency",
493
+ yaxis_unit: "ms",
494
+ yaxis_divisor: 1
495
+ )
496
+
497
+ pdf = pdfout(rplot, file: options.pdf, width: options.width, height: options.height)
498
+ print("#{pdf}") unless options.pdf.empty?
499
+ print("#{rplot}") if options.pdf.empty?
500
+ end
501
+
502
+ # Implements the latency-comparison-plot command
503
+ #
504
+ def latency_comparison_plot(args, options)
505
+
506
+ experiments = options.experiments.split(',')
507
+ machines = options.machines.split(',')
508
+
509
+ data = Ppbench::load_data(args)
510
+ filtered_data = Ppbench::filter(
511
+ data,
512
+ experiments: experiments,
513
+ machines: machines
514
+ )
515
+ aggregated_data = Ppbench::aggregate(filtered_data)
516
+
517
+ max_x = Ppbench::maximum(aggregated_data, of: :length)
518
+
519
+ rplot = Ppbench::comparison_plotter(
520
+ aggregated_data,
521
+ yaxis_max: options.yaxis_max,
522
+ to_plot: :tpr,
523
+ machines: machines,
524
+ experiments: experiments,
525
+ receive_window: options.recwindow,
526
+ xaxis_max: options.xaxis_max == 0 ? max_x : options.xaxis_max,
527
+ xaxis_steps: options.xaxis_steps,
528
+ title: "Round-trip latency in relative comparison",
529
+ subtitle: "smaller is better",
530
+ xaxis_title: "Message Size",
531
+ xaxis_unit: "kB",
532
+ xaxis_divisor: 1000,
533
+ yaxis_title: "Ratio",
534
+ )
535
+
536
+ pdf = pdfout(rplot, file: options.pdf, width: options.width, height: options.height)
537
+ print("#{pdf}") unless options.pdf.empty?
538
+ print("#{rplot}") if options.pdf.empty?
539
+ end
540
+
541
+ # Implements the summary command.
542
+ #
543
+ def summary(args, options)
544
+
545
+ experiments = options.experiments.split(',')
546
+ machines = options.machines.split(',')
547
+
548
+ data = Ppbench::load_data(args)
549
+ filtered_data = Ppbench::filter(
550
+ data,
551
+ experiments: experiments,
552
+ machines: machines
553
+ )
554
+ aggregated_data = Ppbench::aggregate(filtered_data)
555
+
556
+ rows = []
557
+ aggregated_data.each do |experiment, machines|
558
+ machines.each do |machine, data|
559
+ mtr = data.map { |e| e[:transfer_rate] }.median / 1000 # median transfer rate
560
+ tpr = data.map { |e| e[:tpr] }.median # median round trip latency
561
+ rps = 1000 / tpr # median request per second
562
+
563
+ rows << [experiment, machine, data.count, "%.2f" % mtr, "%.2f" % rps, "%.2f" % tpr]
564
+ end
565
+ rows << :separator
566
+ end
567
+ rows.pop
568
+
569
+ print("We have data for: \n")
570
+ table = Terminal::Table.new(:headings => ['Experiment', 'Machine', 'Samples', 'Transfer (kB/s)', "Requests/sec", "Latency (ms)"], :rows => rows)
571
+ table.align_column(2, :right)
572
+ table.align_column(3, :right)
573
+ table.align_column(4, :right)
574
+ table.align_column(5, :right)
575
+ print("#{table}\n")
576
+ end
577
+
578
+ # Implements the naming command.
579
+ #
580
+ def naming(args, options)
581
+ experiments = options.experiments.split(',')
582
+ machines = options.machines.split(',')
583
+
584
+ data = Ppbench::load_data(args)
585
+ filtered_data = Ppbench::filter(
586
+ data,
587
+ experiments: experiments,
588
+ machines: machines
589
+ )
590
+
591
+ json_to_update = {}
592
+ existing_machine_names = []
593
+ existing_experiment_names = []
594
+ unless options.update.empty?
595
+ begin
596
+ file = File.read(options.update)
597
+ json_to_update = JSON.parse(file)
598
+ rescue Exception => ex
599
+ $stderr.puts("Could not process #{options.update}. It does not seem to be a valid JSON file.")
600
+ exit!
601
+ end
602
+ end
603
+
604
+ existing_machine_names = json_to_update['machines'].keys if json_to_update['machines']
605
+ existing_experiment_names = json_to_update['experiments'].keys if json_to_update['experiments']
606
+
607
+ machine_names = filtered_data.map { |entry| entry[:machine] }.uniq.sort - existing_machine_names
608
+ experiment_names = filtered_data.map { |entry| entry[:experiment] }.uniq.sort - existing_experiment_names
609
+
610
+ machines_map = (
611
+ machine_names.map { |e| [e, "#{e} (TODO: Provide a better name)"] } +
612
+ existing_machine_names.map { |e| [e, json_to_update['machines'][e]] }
613
+ ).to_h
614
+
615
+ experiments_map = (
616
+ experiment_names.map { |e| [e, "#{e} (TODO: Provide a better name)"] } +
617
+ existing_experiment_names.map { |e| [e, json_to_update['experiments'][e]] }
618
+ ).to_h
619
+
620
+ json = { "machines": machines_map, "experiments": experiments_map }
621
+ print ("#{JSON.pretty_generate(json)}")
622
+ end
623
+
624
+ # Implements the citation command.
625
+ #
626
+ def citation(args, options)
627
+ bibtex =
628
+ """
629
+ @misc{Kra2015,
630
+ title = {A distributed HTTP-based and REST-like ping-pong system for test and benchmarking purposes.},
631
+ author = {{Nane Kratzke}},
632
+ organization = {L\\\"ubeck University of Applied Sciences},
633
+ address = {L\\\"ubeck, Germany},
634
+ year = {2015},
635
+ howpublished = {\\url{https://github.com/nkratzke/pingpong}}
636
+ }
637
+ """
638
+
639
+ return bibtex if options.bibtex
640
+
641
+ """
642
+ To cite ppbench in publications use:
643
+
644
+ Kratzke, Nane (2015). A distributed HTTP-based and REST-like ping-pong system for test and benchmarking purposes.
645
+ Lübeck University of Applied Sciences, Lübeck, Germany. URL https://github.com/nkratzke/pingpong.
646
+
647
+ A BibTeX entry for LaTeX users is: #{bibtex}
648
+
649
+ """
650
+ end
651
+
652
+ command :run do |c|
653
+ c.syntax = 'ppbench run [options] log.csv'
654
+ c.description = 'Runs a ping pong benchmark.'
655
+ c.example 'Run a benchmark and tags the results as to be collected on a m3.2xlarge instance running a docker experiment',
656
+ 'ppbench run --host http://1.2.3.4:8080 --machine m3.2xlarge --experiment docker log.csv'
657
+
658
+ c.option '--host STRING', String, 'Host'
659
+ c.option '--machine STRING', String, 'A tag to categorize the machine (defaults to empty String)'
660
+ c.option '--experiment STRING', String, 'A tag to categorize the experiment (defaults to empty String)'
661
+ c.option '--min INT', Integer, 'Minimum message size [bytes] (defaults to 1)'
662
+ c.option '--max INT', Integer, 'Maximum message size [bytes] (defaults to 500.000)'
663
+ c.option '--coverage FLOAT', Float, 'Amount of requests to send (defaults to 5% == 0.05, must be between 0.0 and 1.0)'
664
+ c.option '--repetitions INT', Integer, 'Repetitions for each data point to collect (defaults to 1, must be >= 1)'
665
+ c.option '--concurrency INT', Integer, 'Requests to be send at the same time in parallel (defaults to 1, must be >= 1)'
666
+ c.option '--timeout SECONDS', Integer, 'Timeout in seconds (defaults to 60 seconds, must be >= 1)'
667
+
668
+ c.action do |args, options|
669
+
670
+ options.default :min => 1, :max => 500000
671
+ options.default :machine => ''
672
+ options.default :experiment => ''
673
+ options.default :coverage => COVERAGE_DEFAULT
674
+ options.default :repetitions => 1
675
+ options.default :concurrency => 1
676
+ options.default :timeout => 60
677
+
678
+ validate_global_options(args, options)
679
+ validate_run_options(args, options)
680
+ run(args, options)
681
+ print("Finished\n")
682
+ end
683
+ end
684
+
685
+ command 'transfer-plot' do |c|
686
+ c.syntax = 'ppbench transfer-plot [options] *.csv'
687
+ c.summary = 'Plots data transfer rates in an absolute way.'
688
+ c.description = 'Generates a R script to plot data transfer rates in an absolute way.'
689
+
690
+ c.option '--machines LIST', String, MACHINES_DESCRIPTION
691
+ c.option '--experiments LIST', String, EXPERIMENTS_DESCRIPTION
692
+ c.option '--recwindow BYTES', Integer, RECWINDOW_DESCRIPTION
693
+
694
+ c.option '--yaxis_max FLOAT', Float, YAXIS_MAX_DESCRIPTION
695
+ c.option '--yaxis_steps TICKS', Integer, YAXIS_STEPS_DESCRIPTION
696
+ c.option '--xaxis_max BYTES', Integer, YAXIS_MAX_DESCRIPTION
697
+ c.option '--xaxis_steps TICKS', Integer, XAXIS_STEPS_DESCRIPTION
698
+
699
+ c.option '--confidence PERCENT' , Integer, CONFIDENCE_DESCRIPTION
700
+ c.option '--withbands', WITHBANDS_DESCRIPTION
701
+ c.option '--nopoints', NOPOINTS_DESCRIPTION
702
+
703
+ c.option '--pdf FILE', String, PDF_DESCRIPTION
704
+ c.option '--width INCH', Integer, PDF_WIDTH_DESCRIPTION
705
+ c.option '--height INCH', Integer, PDF_HEIGHT_DESCRIPTION
706
+
707
+ c.action do |args, options|
708
+ options.default :machines => ''
709
+ options.default :experiments => ''
710
+ options.default :recwindow => RECWINDOW_DEFAULT
711
+ options.default :confidence => CONFIDENCE_DEFAULT
712
+
713
+ options.default :yaxis_max => 0
714
+ options.default :yaxis_steps => AXIS_STEP_DEFAULT
715
+ options.default :xaxis_max => 0
716
+ options.default :xaxis_steps => AXIS_STEP_DEFAULT
717
+
718
+ options.default :pdf => ''
719
+ options.default :width => PDF_HEIGHT_WIDTH_DEFAULT
720
+ options.default :height => PDF_HEIGHT_WIDTH_DEFAULT
721
+
722
+ validate_global_options(args, options)
723
+ validate_plot_options(args, options)
724
+ validate_pdf_options(args,options)
725
+ transfer_plot(args, options)
726
+ end
727
+ end
728
+
729
+
730
+ command 'transfer-comparison-plot' do |c|
731
+ c.syntax = 'ppbench transfer-comparison-plot [options] *.csv'
732
+ c.summary = 'Compares data transfer rates in a relative way.'
733
+ c.description = 'Generates a R script to compare data transfer rates in a relative way.'
734
+
735
+ c.option '--machines LIST', String, MACHINES_DESCRIPTION
736
+ c.option '--experiments LIST', String, EXPERIMENTS_DESCRIPTION
737
+ c.option '--recwindow BYTES', Integer, RECWINDOW_DESCRIPTION
738
+
739
+ c.option '--yaxis_max BYTES', Float, YAXIS_MAX_DESCRIPTION
740
+ c.option '--yaxis_steps STEPS', Integer, YAXIS_STEPS_DESCRIPTION
741
+ c.option '--xaxis_max BYTES', Integer, XAXIS_MAX_DESCRIPTION
742
+ c.option '--xaxis_steps STEPS', Integer, XAXIS_STEPS_DESCRIPTION
743
+
744
+ c.option '--pdf FILE', String, PDF_DESCRIPTION
745
+ c.option '--width INTEGER', Integer, PDF_WIDTH_DESCRIPTION
746
+ c.option '--height INTEGER', Integer, PDF_HEIGHT_DESCRIPTION
747
+
748
+ c.action do |args, options|
749
+
750
+ options.default :machines => ''
751
+ options.default :experiments => ''
752
+ options.default :recwindow => RECWINDOW_DEFAULT
753
+
754
+ options.default :yaxis_max => COMPARISON_MAX_DEFAULT
755
+ options.default :yaxis_steps => AXIS_STEP_DEFAULT
756
+ options.default :xaxis_max => 0
757
+ options.default :xaxis_steps => AXIS_STEP_DEFAULT
758
+
759
+ options.default :pdf => ''
760
+ options.default :width => PDF_HEIGHT_WIDTH_DEFAULT
761
+ options.default :height => PDF_HEIGHT_WIDTH_DEFAULT
762
+
763
+ validate_global_options(args, options)
764
+ validate_comparison_options(args, options)
765
+ validate_pdf_options(args,options)
766
+ transfer_comparison_plot(args, options)
767
+ end
768
+ end
769
+
770
+ command 'request-plot' do |c|
771
+ c.syntax = 'ppbench request-plot [options] *.csv'
772
+ c.summary = 'Plots requests per second in an absolute way.'
773
+ c.description = 'Generates a R script to plot requests per second in an absolute way.'
774
+
775
+ c.option '--machines LIST', String, MACHINES_DESCRIPTION
776
+ c.option '--experiments LIST', String, EXPERIMENTS_DESCRIPTION
777
+ c.option '--recwindow BYTES', Integer, RECWINDOW_DESCRIPTION
778
+
779
+ c.option '--yaxis_max REQS', Float, YAXIS_MAX_DESCRIPTION
780
+ c.option '--yaxis_steps STEPS', Integer, YAXIS_STEPS_DESCRIPTION
781
+ c.option '--xaxis_max BYTES', Integer, XAXIS_MAX_DESCRIPTION
782
+ c.option '--xsteps STEPS', Integer, YAXIS_STEPS_DESCRIPTION
783
+
784
+ c.option '--confidence PERCENT' , Integer, CONFIDENCE_DESCRIPTION
785
+ c.option '--withbands', WITHBANDS_DESCRIPTION
786
+ c.option '--nopoints', NOPOINTS_DESCRIPTION
787
+
788
+ c.option '--pdf FILE', String, PDF_DESCRIPTION
789
+ c.option '--width INCH', Integer, PDF_WIDTH_DESCRIPTION
790
+ c.option '--height INCH', Integer, PDF_HEIGHT_DESCRIPTION
791
+
792
+ c.action do |args, options|
793
+ options.default :machines => ''
794
+ options.default :experiments => ''
795
+ options.default :recwindow => RECWINDOW_DEFAULT
796
+ options.default :confidence => CONFIDENCE_DEFAULT
797
+
798
+ options.default :yaxis_max => 0
799
+ options.default :yaxis_steps => AXIS_STEP_DEFAULT
800
+ options.default :xaxis_max => 0
801
+ options.default :xaxis_steps => AXIS_STEP_DEFAULT
802
+
803
+ options.default :pdf => ''
804
+ options.default :width => PDF_HEIGHT_WIDTH_DEFAULT
805
+ options.default :height => PDF_HEIGHT_WIDTH_DEFAULT
806
+
807
+ validate_global_options(args, options)
808
+ validate_plot_options(args, options)
809
+ validate_pdf_options(args, options)
810
+ request_plot(args, options)
811
+ end
812
+ end
813
+
814
+ command 'request-comparison-plot' do |c|
815
+ c.syntax = 'ppbench request-comparison-plot [options] *.csv'
816
+ c.summary = 'Compares requests per second in a relative way.'
817
+ c.description = 'Generates a R script to compare requests per second in a relative way.'
818
+
819
+ c.option '--machines STRING', String, MACHINES_DESCRIPTION
820
+ c.option '--experiments STRING', String, EXPERIMENTS_DESCRIPTION
821
+ c.option '--recwindow INTEGER', Integer, RECWINDOW_DESCRIPTION
822
+
823
+ c.option '--yaxis_max FLOAT', Float, YAXIS_MAX_DESCRIPTION
824
+
825
+ c.option '--xaxis_max BYTES', Integer, XAXIS_MAX_DESCRIPTION
826
+ c.option '--xaxis_steps INTEGER', Integer, YAXIS_STEPS_DESCRIPTION
827
+
828
+ c.option '--pdf FILE', String, 'Saves output to a PDF file'
829
+ c.option '--width INTEGER', Integer, 'Width of plot in inch (defaults to 7 inch, only useful with PDF output)'
830
+ c.option '--height INTEGER', Integer, 'Height of plot in inch (defaults to 7 inch, only useful with PDF output)'
831
+
832
+ c.action do |args, options|
833
+
834
+ options.default :machines => ''
835
+ options.default :experiments => ''
836
+ options.default :recwindow => RECWINDOW_DEFAULT
837
+
838
+ options.default :yaxis_max => COMPARISON_MAX_DEFAULT
839
+ options.default :xaxis_max => 0
840
+ options.default :xaxis_steps => AXIS_STEP_DEFAULT
841
+
842
+ options.default :pdf => ''
843
+ options.default :width => PDF_HEIGHT_WIDTH_DEFAULT
844
+ options.default :height => PDF_HEIGHT_WIDTH_DEFAULT
845
+
846
+ validate_global_options(args, options)
847
+ validate_comparison_options(args, options)
848
+ validate_pdf_options(args, options)
849
+ request_comparison_plot(args, options)
850
+ end
851
+ end
852
+
853
+ command 'latency-plot' do |c|
854
+ c.syntax = 'ppbench latency-plot [options] *.csv'
855
+ c.summary = 'Plots round-trip latencies in an absolute way.'
856
+ c.description = 'Generates a R script to plot round-trip latencies in an absolute way.'
857
+
858
+ c.example 'Generates a latency plot for data collected on machine m3.xlarge for java, dart and go implementations of the ping-pong system.',
859
+ 'ppbench latency-plot --machines m3.xlarge --experiments bare-java,bare-go,bare-dart *.csv > bare-comparison.R'
860
+
861
+ c.example 'Generates a latency plot for data collected on machine m3.xlarge for java, dart implementations of the ping-pong system.',
862
+ 'ppbench latency-comparison-plot --machines m3.xlarge --experiments bare-java,bare-go --pdf compare.pdf --width 9, --height 6 *.csv > bare-comparison.R'
863
+
864
+ c.option '--machines LIST', String, MACHINES_DESCRIPTION
865
+ c.option '--experiments LIST', String, EXPERIMENTS_DESCRIPTION
866
+ c.option '--recwindow BYTES', Integer, RECWINDOW_DESCRIPTION
867
+
868
+ c.option '--yaxis_max MS', Integer, YAXIS_MAX_DESCRIPTION
869
+ c.option '--yaxis_steps TICKS', Integer, YAXIS_STEPS_DESCRIPTION
870
+ c.option '--xaxis_max BYTES', Integer, XAXIS_MAX_DESCRIPTION
871
+ c.option '--xaxis_steps TICKS', Integer, XAXIS_STEPS_DESCRIPTION
872
+
873
+ c.option '--confidence PERCENT' , Integer, CONFIDENCE_DESCRIPTION
874
+ c.option '--withbands', WITHBANDS_DESCRIPTION
875
+ c.option '--nopoints', NOPOINTS_DESCRIPTION
876
+
877
+ c.option '--pdf FILE', String, PDF_DESCRIPTION
878
+ c.option '--width INCH', Integer, PDF_WIDTH_DESCRIPTION
879
+ c.option '--height INCH', Integer, PDF_HEIGHT_DESCRIPTION
880
+
881
+ c.action do |args, options|
882
+
883
+ options.default :machines => ''
884
+ options.default :experiments => ''
885
+ options.default :recwindow => RECWINDOW_DEFAULT
886
+
887
+ options.default :confidence => CONFIDENCE_DEFAULT
888
+
889
+ options.default :yaxis_max => 0
890
+ options.default :yaxis_steps => AXIS_STEP_DEFAULT
891
+ options.default :xaxis_max => 0
892
+ options.default :xaxis_steps => AXIS_STEP_DEFAULT
893
+
894
+ options.default :pdf => ''
895
+ options.default :width => PDF_HEIGHT_WIDTH_DEFAULT
896
+ options.default :height => PDF_HEIGHT_WIDTH_DEFAULT
897
+
898
+ validate_global_options(args, options)
899
+ validate_plot_options(args, options)
900
+ validate_pdf_options(args, options)
901
+ latency_plot(args, options)
902
+ end
903
+ end
904
+
905
+ command 'latency-comparison-plot' do |c|
906
+ c.syntax = 'ppbench latency-comparison-plot [options] *.csv'
907
+ c.summary = 'Compares round-trip latencies in a relative way.'
908
+ c.description = 'Generates a R script to compare round-trip latencies in a relative way.'
909
+
910
+ c.example 'Generates a latency comparison plot for data collected on machine m3.xlarge for java, dart and go implementations of the ping-pong system.',
911
+ 'ppbench latency-comparison-plot --machines m3.xlarge --experiments bare-java,bare-go,bare-dart *.csv > bare-comparison.R'
912
+
913
+ c.example 'Generates a latency comparison plot as PDF using Rscript',
914
+ 'ppbench latency-comparison-plot -m m3.xlarge -e bare-java,bare-go -p compare.pdf *.csv | Rscript - '
915
+
916
+ c.option '--machines LIST', String, MACHINES_DESCRIPTION
917
+ c.option '--experiments LIST', String, EXPERIMENTS_DESCRIPTION
918
+ c.option '--recwindow BYTES', Integer, RECWINDOW_DESCRIPTION
919
+
920
+ c.option '--yaxis_max MS', Float, 'Maximum Y Value (must be greater than 1.0, defaults to 2.0)'
921
+ c.option '--xaxis_max BYTES', Integer, XAXIS_MAX_DESCRIPTION
922
+ c.option '--xaxis_steps TICKS', Integer, YAXIS_STEPS_DESCRIPTION
923
+
924
+ c.option '--pdf FILE', String, PDF_DESCRIPTION
925
+ c.option '--width INCH', Integer, PDF_WIDTH_DESCRIPTION
926
+ c.option '--height INCH', Integer, PDF_HEIGHT_DESCRIPTION
927
+
928
+ c.action do |args, options|
929
+
930
+ options.default :machines => ''
931
+ options.default :experiments => ''
932
+ options.default :recwindow => RECWINDOW_DEFAULT
933
+
934
+ options.default :yaxis_max => COMPARISON_MAX_DEFAULT
935
+ options.default :xaxis_max => 0
936
+ options.default :xaxis_steps => AXIS_STEP_DEFAULT
937
+
938
+ options.default :pdf => ''
939
+ options.default :width => PDF_HEIGHT_WIDTH_DEFAULT
940
+ options.default :height => PDF_HEIGHT_WIDTH_DEFAULT
941
+
942
+ validate_global_options(args, options)
943
+ validate_comparison_options(args, options)
944
+ validate_pdf_options(args, options)
945
+ latency_comparison_plot(args, options)
946
+ end
947
+ end
948
+
949
+ command :summary do |c|
950
+ c.syntax = 'ppbench summary [options] *.csv'
951
+ c.summary = 'Summarizes benchmark data.'
952
+ c.description = 'Summarizes benchmark data. Useful to inspect data for completeness or to query machine and experiment tags.'
953
+
954
+ c.example 'Lists a summary of all benchmark data.',
955
+ 'ppbench summary *.csv'
956
+ c.example 'Lists a summary of all benchmark data tagged to be run on machines m3.2xlarge, m3.xlarge',
957
+ 'ppbench summary --machines m3.2xlarge,m3.xlarge *.csv'
958
+ c.example 'Lists a summary of all benchmark data tagged to be run as docker-java or bare-dart experiments',
959
+ 'ppbench summary --experiments bare-dart,docker-java *.csv'
960
+
961
+ c.option '--machines LIST', String, MACHINES_DESCRIPTION
962
+ c.option '--experiments LIST', String, EXPERIMENTS_DESCRIPTION
963
+
964
+ c.action do |args, options|
965
+ options.default :machines => ''
966
+ options.default :experiments => ''
967
+
968
+ summary(args, options)
969
+ end
970
+ end
971
+
972
+ command 'naming-template' do |c|
973
+
974
+ c.syntax = 'ppbench naming-template [options] *.csv'
975
+ c.summary = 'Generates a JSON file for naming.'
976
+ c.description = 'Generates a JSON file from benchmark data for naming. This file can be used with the --naming flag.'
977
+
978
+ c.example 'Generates a naming template from all benchmark data.',
979
+ 'ppbench naming-template *.csv > naming.json'
980
+ c.example 'Appends all missing names to an existing naming-template',
981
+ 'ppbench naming-template --update naming.json > naming-update.json'
982
+
983
+ c.option '--machines LIST', String, MACHINES_DESCRIPTION
984
+ c.option '--experiments LIST', String, EXPERIMENTS_DESCRIPTION
985
+ c.option '--update FILE', 'Naming file to update with additional data.'
986
+
987
+ c.action do |args, options|
988
+ options.default :machines => ''
989
+ options.default :experiments => ''
990
+ options.default :update => ''
991
+
992
+ validate_naming_options(args, options)
993
+ naming(args, options)
994
+ end
995
+
996
+ end
997
+
998
+ command :citation do |c|
999
+ c.syntax = 'ppbench citation [options]'
1000
+ c.summary = 'Citation information about ppbench.'
1001
+ c.description = 'Provides information how to cite ppbench in publications.'
1002
+
1003
+ c.example 'Get general information how to cite ppbench in publications',
1004
+ 'ppbench citation'
1005
+ c.example 'Append a bibtex entry for ppbench to your references.bib (LaTex users).',
1006
+ 'ppbench citation --bibtex >> references.bib'
1007
+ c.option '--bibtex', 'Get bibtex entry (for Latex users)'
1008
+
1009
+ c.action do |args, options|
1010
+ print "#{citation(args, options)}\n"
1011
+ end
1012
+ end