loadtester 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6f6db75fea18b2ffba192f1f0bc51928efada544
4
+ data.tar.gz: e7c8d72c8a28570fe9ee4a983fe86636da92c097
5
+ SHA512:
6
+ metadata.gz: d38c9d367a867b2915efc9e6aee0f5daebd16e535d9d1f978fe089f2dd54fbc5d96afadbd99225b66872ffa890d6aea311ec39a245e048fea84b88fbc6c158b9
7
+ data.tar.gz: 8631bc889af5743861d9cc855f459756d2f319d9e2aa9b8e7d56306a0d2109888b553da43e7dd6ada15efba5ffc721f5663961ee3c580cbce3359d423b81a629
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in loadtester.gemspec
4
+ gemspec
5
+
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Stuart Harland
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Loadtester
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/loadtester`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'loadtester'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install loadtester
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it ( https://github.com/[my-github-username]/loadtester/fork )
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "loadtester"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/loadtester ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'loadtester'
4
+
5
+ LT.new.iotest
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,81 @@
1
+ # Module to run Disk I/O benchmarks for various size files
2
+ module LoadTester
3
+ # A File with random contents of given size
4
+ class FileDefinition
5
+ RANDOM_GENERATOR = Random.new
6
+ attr_accessor :run_time, :source, :size,
7
+ :file_source_name, :file_destination_name,
8
+ :data, :type, :destination
9
+
10
+ def initialize(source, destination, size, file_source_name,
11
+ file_destination_name, type)
12
+ self.source = source
13
+ self.destination = destination
14
+ self.size = size
15
+ self.file_source_name = file_source_name
16
+ self.file_destination_name = file_destination_name
17
+ self.type = type
18
+ populate unless valid?
19
+ self.load! if type == :write
20
+ end
21
+
22
+ def populate
23
+ FileUtils.mkdir_p File.dirname src
24
+ FileUtils.mkdir_p File.dirname target
25
+ generate unless File.exist? src
26
+ FileUtils.copy src, target if type == :read
27
+ end
28
+
29
+ def generate
30
+ FileUtils.mkdir_p File.dirname src
31
+ random_string = ''
32
+ size.to_i.times do
33
+ random_string += RANDOM_GENERATOR.rand(256).chr
34
+ end
35
+ IO.binwrite src, random_string
36
+ end
37
+
38
+ def src
39
+ File.join source,
40
+ size.pretty,
41
+ file_source_name.to_s
42
+ end
43
+
44
+ def target
45
+ File.join destination,
46
+ type.to_s,
47
+ size.pretty,
48
+ file_destination_name.to_s
49
+ end
50
+
51
+ def load!
52
+ self.data = File.read src
53
+ FileUtils.mkdir_p File.join(destination, size.pretty)
54
+ end
55
+
56
+ def read
57
+ self.run_time = Benchmark.measure do
58
+ IO.binread target
59
+ end
60
+ run_time.real
61
+ end
62
+
63
+ def write
64
+ self.run_time = Benchmark.measure do
65
+ File.open(target, 'wb') do |fd|
66
+ fd.write data
67
+ fd.fsync
68
+ end
69
+ end
70
+ run_time.real
71
+ end
72
+
73
+ def valid?
74
+ if type == :read
75
+ File.exist? target
76
+ else
77
+ File.exist?(src) && File.directory?(File.dirname(target))
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,23 @@
1
+ # Module to run Disk I/O benchmarks for various size files
2
+ module LoadTester
3
+ class << self
4
+ # Creates an array set of random integers
5
+ # http://stackoverflow.com/questions/119107/how-do-i-generate-a-list-of-n-unique-random-numbers-in-rub
6
+ def rand_n(n, max)
7
+ randoms = []
8
+ loop do
9
+ r = rand(max)
10
+ randoms << r
11
+ return randoms if randoms.size >= n
12
+ end
13
+ end
14
+
15
+ def generate_file_list(random, list_size, pool_size)
16
+ if random
17
+ rand_n list_size, pool_size
18
+ else
19
+ Array.new(list_size) { |index| index % pool_size }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,113 @@
1
+ require 'ostruct'
2
+ require 'optparse'
3
+ module LoadTester
4
+ # Parses the CLI Arguments passed into LoadTester
5
+ class OptionsParser
6
+ attr_accessor :sizes, :source, :destination, :verbose, :random,
7
+ :generate, :number, :pool_size, :rw_bias, :opts
8
+ def initialize
9
+ self.opts = OptionParser.new
10
+ self.sizes = Array.new(8).map.with_index do |_x, index|
11
+ Filesize.from("#{2**(10 + index)}b")
12
+ end
13
+ self.source = 'load_tester_files'
14
+ self.verbose = false
15
+ self.random = true
16
+ self.number = 900
17
+ self.pool_size = 300
18
+ self.rw_bias = 0.5
19
+ end
20
+
21
+ def option_error(option, err_string, example)
22
+ $stderr.puts 'load_test.rb: Unable to parse command line options.'
23
+ $stderr.puts " #{option} #{err_string}"
24
+ $stderr.puts " ruby load_test.rb #{option} #{example}"
25
+ exit 2
26
+ end
27
+
28
+ def parse_verbose
29
+ opts.on('-v', '--verbose', 'Run Verbosely') do |v|
30
+ self.verbose = v
31
+ end
32
+ end
33
+
34
+ def parse_source_destination
35
+ opts.on('-d', '--destination DIR', 'Destination') do |d|
36
+ self.destination = d
37
+ end
38
+ opts.on('-s', '--source DIR', 'Path to Source Files') do |s|
39
+ self.source = s
40
+ end
41
+ end
42
+
43
+ def parse_sizes
44
+ opts.on('-x', '--sizes [BYTES]', ' sizes to test') do |size|
45
+ begin
46
+ self.sizes = size.split(',').map do |value|
47
+ Filesize.from(value)
48
+ end
49
+ rescue ArgumentError
50
+ option_error '--size', 'Must be human readable csv',
51
+ '4kb,8kb,1mb'
52
+ end
53
+ end
54
+ end
55
+
56
+ def parse_number_pool
57
+ opts.on('-n', '--number [INT]', 'Number of operations') do |n|
58
+ self.number = n.to_i
59
+ end
60
+ opts.on('-p', '--poolsize [INT]', 'Size of random pool') do |p|
61
+ self.pool_size = p.to_i
62
+ end
63
+ end
64
+
65
+ def parse_random_generate_bias
66
+ opts.on('-r', '--random', 'Random IO?') do |r|
67
+ self.random = r
68
+ end
69
+ opts.on('-g', '--generate', 'Generate Source') do |g|
70
+ self.generate = g
71
+ end
72
+ opts.on('-b', '--rw-bias [FLOAT]', 'Read Write Bias') do |b|
73
+ self.rw_bias = b.to_f
74
+ end
75
+ end
76
+
77
+ def parse_info
78
+ opts.on_tail('-h', '--help', 'Show this message') do
79
+ puts opts
80
+ exit
81
+ end
82
+ opts.on_tail('--version', 'Show version') do
83
+ puts ::Version.join('.')
84
+ exit
85
+ end
86
+ end
87
+
88
+ def setup_opts
89
+ opts.banner = 'Usage: load_test.rb [options]'
90
+ opts.separator ''
91
+ opts.separator 'Specific options:'
92
+ end
93
+
94
+ def parse!(args)
95
+ opts.parse!(args)
96
+ self
97
+ end
98
+
99
+ class << self
100
+ def factory(args)
101
+ opt = OptionsParser.new
102
+ opt.setup_opts
103
+ opt.parse_verbose
104
+ opt.parse_source_destination
105
+ opt.parse_sizes
106
+ opt.parse_number_pool
107
+ opt.parse_random_generate_bias
108
+ opt.parse_info
109
+ opt.parse!(args)
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,4 @@
1
+ # LoadTester: io Benchmark tool for various sized files
2
+ module LoadTester
3
+ VERSION = '0.1.0'
4
+ end
data/lib/loadtester.rb ADDED
@@ -0,0 +1,126 @@
1
+ # Module to run Disk I/O benchmarks for various size files
2
+ module LoadTester
3
+ require 'loadtester/version'
4
+ require 'loadtester/optionsparser'
5
+ require 'loadtester/filegenerator'
6
+ require 'loadtester/helpers'
7
+ require 'loadtester/filedefinition'
8
+ require 'fileutils'
9
+ require 'filesize'
10
+ require 'benchmark'
11
+
12
+ # Base object to run Load Test iterations
13
+ class LT
14
+ attr_accessor :read_count, :count,
15
+ :read_list, :write_list, :options,
16
+ :read_time, :write_time,
17
+ :read_number, :write_number
18
+
19
+ def initialize
20
+ self.options = OptionsParser.factory(ARGV)
21
+ generate_files if @options.generate
22
+ self.read_count = 0
23
+ self.count = 0
24
+ self.read_time = 0
25
+ self.write_time = 0
26
+ calculate_biases
27
+ end
28
+
29
+ def calculate_biases
30
+ self.read_number = (options.number * options.rw_bias).round
31
+ self.write_number = (options.number * (1 - options.rw_bias)).round
32
+ end
33
+
34
+ def speed(type, number, time, size)
35
+ "#{type}: #{number} files of size #{size.pretty} "\
36
+ "in #{time} seconds at "\
37
+ "#{(number * size.to_i / 1024 / 1024 / time).round(2)} MB/s"
38
+ end
39
+
40
+ def total_speed(size)
41
+ puts speed 'Total', read_number + write_number,
42
+ read_time + write_time, size
43
+ end
44
+
45
+ def report(size)
46
+ puts "Read/Write Bias: #{options.rw_bias}"
47
+ puts total_speed size
48
+ puts speed 'Read', read_number, read_time, size
49
+ puts speed 'Wrote', write_number, write_time, size
50
+ end
51
+
52
+ def iotest
53
+ options.sizes.each do |size|
54
+ generate_operations size
55
+ io_loop
56
+ report size
57
+ end
58
+ end
59
+
60
+ # If you are trying to run a benchmark against the write speed
61
+ # of a distributed file system, you don't want the read speed
62
+ # of your local infrastructure to be included in that
63
+ #
64
+ # This preloads the file contents for a given 'size' into ram
65
+ def generate_operation_list(size, type, number)
66
+ file_list = LoadTester.generate_file_list options.random,
67
+ number, options.pool_size
68
+ files = []
69
+ file_list.each.with_index do |file_source_name, file_destination_name|
70
+ files << FileDefinition.new(options.source, options.destination,
71
+ size, file_source_name,
72
+ file_destination_name, type)
73
+ end
74
+ files
75
+ end
76
+
77
+ # Pre-generate files for IO test
78
+ # NB this can take some time for files > 128kb!
79
+ def generate_files
80
+ options.sizes.each do |size|
81
+ options.pool_size.times do |n|
82
+ FileDefinition.new options.source,
83
+ options.destination,
84
+ size, n, n, :write
85
+ end
86
+ end
87
+ exit
88
+ end
89
+
90
+ # Create two lists: one for the order of the read operations
91
+ # and one for the write operations
92
+ def generate_operations(size)
93
+ self.read_list = generate_operation_list size, :read, read_number
94
+ self.write_list = generate_operation_list size, :write, write_number
95
+ end
96
+
97
+ # loop over the various files in the queue and perform load test
98
+ def io_loop
99
+ until write_list.empty? && read_list.empty?
100
+ if should_read
101
+ do_read
102
+ else
103
+ do_write
104
+ end
105
+ end
106
+ end
107
+
108
+ def do_read
109
+ self.read_time += read_list.pop.read
110
+ self.read_count += 1
111
+ self.count += 1
112
+ end
113
+
114
+ def do_write
115
+ self.write_time += write_list.pop.write
116
+ self.count += 1
117
+ end
118
+
119
+ def should_read
120
+ return false if self.count == 0
121
+ return false if read_list.empty?
122
+ return true if write_list.empty?
123
+ return true if (self.read_count / self.count) < options.rw_bias
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'loadtester/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'loadtester'
8
+ spec.version = LoadTester::VERSION
9
+ spec.authors = ['Stuart Harland']
10
+ spec.email = ['s.harand@livelinktechnology.net']
11
+
12
+ spec.summary = %q{File Benchmark Tool}
13
+ spec.description = %q{Provides File IO Benchmarking for named file sizes with read/write biasing}
14
+ spec.homepage = 'http://github.com/livelink/loadtester'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'bin'
19
+ spec.require_paths = ['lib']
20
+ spec.executables = ['loadtester']
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.8"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_dependency "filesize"
25
+ spec.add_dependency "fileutils"
26
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loadtester
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stuart Harland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: filesize
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: fileutils
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Provides File IO Benchmarking for named file sizes with read/write biasing
70
+ email:
71
+ - s.harand@livelinktechnology.net
72
+ executables:
73
+ - loadtester
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".travis.yml"
80
+ - CODE_OF_CONDUCT.md
81
+ - Gemfile
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
85
+ - bin/console
86
+ - bin/loadtester
87
+ - bin/setup
88
+ - lib/loadtester.rb
89
+ - lib/loadtester/filedefinition.rb
90
+ - lib/loadtester/helpers.rb
91
+ - lib/loadtester/optionsparser.rb
92
+ - lib/loadtester/version.rb
93
+ - loadtester.gemspec
94
+ homepage: http://github.com/livelink/loadtester
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.4.5
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: File Benchmark Tool
118
+ test_files: []
119
+ has_rdoc: