rhoconnect 3.0.6 → 3.1.0.beta1

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 (74) hide show
  1. data/CHANGELOG.md +9 -0
  2. data/Gemfile +3 -3
  3. data/Gemfile.lock +38 -17
  4. data/Rakefile +0 -10
  5. data/bench/benchapp/Gemfile.lock +1 -0
  6. data/bench/distr_bench/distr_bench_main +94 -27
  7. data/bench/distr_bench/run_test_query_script.sh +22 -18
  8. data/bench/lib/bench/aws_utils.rb +326 -0
  9. data/bench/lib/bench/bench_result_processor.rb +268 -75
  10. data/bench/lib/bench/cli.rb +1 -0
  11. data/bench/lib/bench/distr_runner.rb +102 -0
  12. data/bench/lib/bench/utils.rb +127 -0
  13. data/bench/lib/bench.rb +16 -15
  14. data/bench/prepare_bench +3 -11
  15. data/bench/scripts/test_query_script.rb +6 -7
  16. data/bin/rhoconnect-benchmark +257 -5
  17. data/doc/benchmarks-running.txt +140 -0
  18. data/doc/client-java.txt +236 -0
  19. data/doc/client-objc.txt +41 -1
  20. data/doc/client.txt +12 -0
  21. data/doc/command-line.txt +12 -3
  22. data/doc/cud-conflicts.txt +68 -0
  23. data/doc/deploying.txt +1 -70
  24. data/doc/hosting-rhohub.txt +3 -0
  25. data/doc/install.txt +50 -13
  26. data/doc/java-plugin.txt +217 -177
  27. data/doc/net-plugin.txt +97 -64
  28. data/doc/plugin-intro.txt +4 -2
  29. data/doc/preparing-production.txt +63 -0
  30. data/doc/rhoconnect-redis-stack.txt +252 -0
  31. data/doc/source-adapters.txt +3 -1
  32. data/doc/tutorial.txt +111 -49
  33. data/examples/simple/dump.rdb +0 -0
  34. data/installer/unix-like/rho_connect_install_constants.rb +6 -5
  35. data/installer/unix-like/rho_connect_install_installers.rb +6 -2
  36. data/installer/utils/nix_install_test.rb +2 -0
  37. data/installer/utils/package_upload/auto-repo.rb +136 -0
  38. data/installer/utils/package_upload/repos.rake +6 -3
  39. data/installer/utils/package_upload/s3_upload.rb +11 -6
  40. data/installer/windows/rhosync.nsi +5 -5
  41. data/lib/rhoconnect/client_sync.rb +2 -2
  42. data/lib/rhoconnect/document.rb +12 -0
  43. data/lib/rhoconnect/jobs/source_job.rb +2 -2
  44. data/lib/rhoconnect/predefined_adapters/bench_adapter.rb +61 -0
  45. data/lib/rhoconnect/source.rb +5 -0
  46. data/lib/rhoconnect/source_adapter.rb +10 -1
  47. data/lib/rhoconnect/source_sync.rb +161 -88
  48. data/lib/rhoconnect/store.rb +48 -0
  49. data/lib/rhoconnect/test_methods.rb +6 -6
  50. data/lib/rhoconnect/version.rb +1 -1
  51. data/lib/rhoconnect.rb +25 -2
  52. data/spec/apps/rhotestapp/sources/sample_adapter.rb +29 -0
  53. data/spec/jobs/source_job_spec.rb +5 -5
  54. data/spec/source_adapter_spec.rb +10 -0
  55. data/spec/source_sync_spec.rb +114 -33
  56. data/spec/spec_helper.rb +21 -2
  57. data/spec/store_spec.rb +29 -0
  58. data/spec/support/shared_examples.rb +1 -1
  59. data/spec/test_methods_spec.rb +4 -4
  60. data/tasks/redis.rake +2 -2
  61. metadata +59 -59
  62. data/bench/benchapp/log/passenger.3000.log +0 -1
  63. data/bench/benchapp/log/passenger.9292.log +0 -59
  64. data/bench/benchapp/tmp/pids/passenger.3000.pid.lock +0 -0
  65. data/bench/benchapp/tmp/pids/passenger.9292.pid.lock +0 -0
  66. data/bench/lib/testdata/0-data.txt +0 -0
  67. data/bench/lib/testdata/1-data.txt +0 -0
  68. data/bench/lib/testdata/10-data.txt +0 -15
  69. data/bench/lib/testdata/2-data.txt +0 -3
  70. data/bench/lib/testdata/25-data.txt +0 -39
  71. data/bench/lib/testdata/250-data.txt +0 -353
  72. data/bench/lib/testdata/3-data.txt +0 -4
  73. data/bench/lib/testdata/50-data.txt +0 -70
  74. data/bench/lib/testdata/500-data.txt +0 -711
@@ -0,0 +1,326 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..','..','lib')
2
+
3
+ require 'rubygems'
4
+ require 'yaml'
5
+
6
+ require 'readline'
7
+ require 'xmlsimple'
8
+
9
+ module Bench
10
+ module AWSUtils
11
+ extend self
12
+
13
+ module Constants
14
+ RC_VERSION = Rhoconnect::VERSION
15
+ REGION = 'us-west-1'
16
+ TEMPLATE_URL = 'http://s3.amazonaws.com/rhoconnect-bench/packages/cloud-formation/ec2-autostack.txt'
17
+ CLIENTS_GROUP_LOGICAL_ID = 'BenchClientsGroup'
18
+ WAIT_FOR_SSH = 120
19
+ HOME_DIR = `echo ~/`.strip.chomp("/")
20
+ end
21
+
22
+ class ClientsGroup
23
+ attr_accessor :stack_name, :client_instances, :auto_scaling_group
24
+
25
+ def initialize(stack_name)
26
+ @stack_name = stack_name
27
+ auto_scaling = Fog::AWS::AutoScaling.new(
28
+ :region => Bench::AWSUtils.aws_region,
29
+ :aws_access_key_id => Bench::AWSUtils.aws_access_key_id,
30
+ :aws_secret_access_key => Bench::AWSUtils.aws_secret_access_key
31
+ )
32
+ group_resources = Bench::AWSUtils.cloud_formation.describe_stack_resources({'StackName' => stack_name,
33
+ 'LogicalResourceId' => Bench::AWSUtils::Constants::CLIENTS_GROUP_LOGICAL_ID}).body
34
+
35
+ @auto_scaling_group = auto_scaling.groups.get(group_resources['StackResources'].first['PhysicalResourceId'])
36
+ @client_instances = []
37
+ @auto_scaling_group.instances.each do |instance|
38
+ next if instance.auto_scaling_group_name != @auto_scaling_group.id
39
+ ec2_instance = Bench::AWSUtils.fog_connection.servers.get(instance.id)
40
+ @client_instances << ec2_instance.dns_name
41
+ end
42
+ end
43
+ end
44
+
45
+ class << self
46
+ attr_accessor :fog_connection, :cloud_formation, :aws_access_key_id, :aws_secret_access_key, :aws_region
47
+ attr_accessor :aws_key_pair_name, :aws_ssh_pem_file
48
+ end
49
+
50
+ def validate_presense_of_file(fname)
51
+ return File.file?(File.expand_path(fname.to_s))
52
+ end
53
+
54
+ def init_connection(settings_file)
55
+ unless Bench::gem_installed?('net-ssh-multi')
56
+ puts "In order to run distributed benchmark you need to have 'net-ssh-multi' gem installed"
57
+ puts "Install it by using : '[sudo] gem install net-ssh-multi'"
58
+ raise "Gem 'net-ssh-multi' is missing"
59
+ end
60
+ unless Bench::gem_installed?('fog')
61
+ puts "In order to run distributed benchmark you need to have 'fog' gem installed"
62
+ puts "Install it by using : '[sudo] gem install fog'"
63
+ raise "Gem 'fog' is missing"
64
+ end
65
+
66
+ require 'net/ssh/multi'
67
+ require 'fog'
68
+
69
+ fog_conf_file = ENV['HOME'] + '/.fog'
70
+ settings_file ||= fog_conf_file
71
+
72
+ if validate_presense_of_file(settings_file)
73
+ # Read Fog ~/.fog configuration file
74
+ # :default:
75
+ # :aws_access_key_id: AKIAI...
76
+ # :aws_secret_access_key: 9l2ruLeCINbilik...
77
+ # :region: us-west-1
78
+ puts "Using AWS settings from #{settings_file} file"
79
+
80
+ settings = YAML::load(File.open(settings_file))
81
+ if not settings or settings[:default].nil?
82
+ raise "ERROR : AWS Settings file '#{settings_file}' doesn't have the mandatoty 'default' section"
83
+ end
84
+ config = settings[:default]
85
+
86
+ @aws_ssh_pem_file = config[:aws_ssh_pem_file]
87
+ unless validate_presense_of_file(aws_ssh_pem_file)
88
+ raise "ERROR : Can not locate SSH Access Pem File '#{aws_ssh_pem_file}'\nMake sure you set :aws_ssh_pem_file properly in the AWS Settings file"
89
+ end
90
+ @aws_access_key_id = config[:aws_access_key_id]
91
+ @aws_secret_access_key = config[:aws_secret_access_key]
92
+ @aws_region = config[:region] || Constants::REGION
93
+ @aws_key_pair_name = config[:aws_key_pair_name]
94
+
95
+ else
96
+ raise "ERROR : Can not locate AWS Settings file '#{settings_file}'\nYou must have this file in order to run the Distributed Benchmark Test"
97
+ end
98
+
99
+ make_fog
100
+ make_cloud_formation
101
+ end
102
+
103
+ # get_access_keys
104
+ # Retrieves the access key and secret access key from the above specified file.
105
+ def get_access_keys(fname)
106
+ return true if aws_access_key_id and aws_secret_access_key
107
+
108
+ lines = IO.readlines(fname)
109
+ @aws_access_key_id = lines.first.strip.split("=")[1]
110
+ @aws_secret_access_key = lines.last.strip.split("=")[1]
111
+ end
112
+
113
+ # make_fog
114
+ # Generates the Fog object used to create the new ec2 instance.
115
+ def make_fog
116
+ @fog_connection ||= Fog::Compute.new(
117
+ :provider => 'AWS',
118
+ :region => aws_region,
119
+ :aws_access_key_id => aws_access_key_id,
120
+ :aws_secret_access_key => aws_secret_access_key
121
+ )
122
+ end #make_fog
123
+
124
+ def make_cloud_formation
125
+ @cloud_formation ||= Fog::AWS::CloudFormation.new(
126
+ :region => aws_region,
127
+ :aws_access_key_id => aws_access_key_id,
128
+ :aws_secret_access_key => aws_secret_access_key
129
+ )
130
+ end
131
+
132
+ def get_template_data(template_url)
133
+ template_data = ''
134
+ begin
135
+ uri = URI.parse(template_url)
136
+ unless uri.scheme
137
+ File.open(uri.path) { |f| template_data << f.read }
138
+ else
139
+ response = Net::HTTP.get_response(uri)
140
+ template_data = response.body if response.code == '200'
141
+ end
142
+ rescue Exception => e
143
+ puts "ERROR: Can not obtain CloudFormation template from '#{template_url}'"
144
+ puts e.message
145
+ end
146
+ template_data
147
+ end
148
+
149
+ # Creates new CloudFormation stack based upon template
150
+ def create_cf_stack
151
+ puts ""
152
+ puts " Creating new AWS CloudFormation stack at '#{aws_region}' region"
153
+ puts " using '#{Constants::TEMPLATE_URL}' template ..."
154
+ puts " This may take several minutes, please be patient ..."
155
+ puts ""
156
+
157
+ stack_name = nil
158
+ stack_created = false
159
+
160
+ begin
161
+ template_data = get_template_data(Constants::TEMPLATE_URL)
162
+ cloud_formation.validate_template('TemplateBody' => template_data)
163
+
164
+ template_params = {}
165
+ template_params['SecurityKeyPair'] = aws_key_pair_name.to_s
166
+ options = {'TemplateBody' => template_data,
167
+ 'Parameters' => template_params}
168
+ stack_name = "BenchStack" + Time.now.strftime("%Y%m%d%H%M%S")
169
+ result = cloud_formation.create_stack(stack_name, options)
170
+
171
+ event_counter = 0
172
+ in_progress = true
173
+ stack_created = false
174
+ while in_progress
175
+ events = cloud_formation.describe_stack_events(stack_name).body['StackEvents']
176
+ events.reverse[event_counter..-1].each do |event|
177
+ puts "Timestamp: #{event['Timestamp']}"
178
+ puts "LogicalResourceId: #{event['LogicalResourceId']}"
179
+ puts "ResourceType: #{event['ResourceType']}"
180
+ puts "ResourceStatus: #{event['ResourceStatus']}"
181
+ puts "ResourceStatusReason: #{event['ResourceStatusReason']}" if event['ResourceStatusReason']
182
+ puts "--"
183
+
184
+ # track creation of the stack
185
+ if event['LogicalResourceId'] == stack_name
186
+ case event['ResourceStatus']
187
+ when 'CREATE_COMPLETE'
188
+ stack_created = true
189
+ in_progress = false
190
+ when /ROLLBACK/
191
+ stack_created = false
192
+ in_progress = false
193
+ when /DELETE/
194
+ stack_created = false
195
+ in_progress = false
196
+ when /FAILED/
197
+ stack_created = false
198
+ in_progress = false
199
+ break
200
+ end
201
+ end
202
+ end
203
+ event_counter += events.size - event_counter
204
+ sleep(2)
205
+ end
206
+ rescue Excon::Errors::BadRequest => excon_error
207
+ error_str = XmlSimple.xml_in(excon_error.response.body)['Error'][0]['Message'][0]
208
+ puts "ERROR: Cannot create AWS CloudFormation stack : #{error_str}"
209
+ stack_created = false
210
+ rescue Excon::Errors::Forbidden => excon_error
211
+ error_str = XmlSimple.xml_in(excon_error.response.body)['Error'][0]['Message'][0]
212
+ puts "ERROR: Cannot create AWS CloudFormation stack : #{error_str}"
213
+ stack_created = false
214
+ rescue Exception => e
215
+ puts "ERROR: Cannot create AWS CloudFormation stack : #{e.class.name}: #{e.message}"
216
+ stack_created = false
217
+ end
218
+
219
+ clients_group = nil
220
+ if stack_created
221
+ clients_group = get_clients_group(stack_name)
222
+ # wait until the SSH service is up and running
223
+ stack_created = establish_ssh_connection(clients_group)
224
+ end
225
+
226
+ unless stack_created
227
+ delete_cf_stack(stack_name)
228
+ clients_group = nil
229
+ stack_name = nil
230
+ end
231
+
232
+ clients_group
233
+ end
234
+
235
+ # Creates new CloudFormation stack based upon template
236
+ def delete_cf_stack(stack_name)
237
+ return unless stack_name
238
+ puts ""
239
+ puts "Destroying AWS CloudFormation stack '#{stack_name}' at '#{ aws_region}' region"
240
+ puts " NOTE: this command doesn't ensure deletion of the stack. "
241
+ puts " It is advised to check later that the stack has been really destroyed"
242
+ puts ""
243
+
244
+ begin
245
+ cloud_formation.delete_stack(stack_name)
246
+ rescue Excon::Errors::BadRequest => excon_error
247
+ error_str = XmlSimple.xml_in(excon_error.response.body)['Error'][0]['Message'][0]
248
+ puts "ERROR: Cannot delete the stack '#{stack_name}' : #{error_str}"
249
+ rescue Excon::Errors::Forbidden => excon_error
250
+ error_str = XmlSimple.xml_in(excon_error.response.body)['Error'][0]['Message'][0]
251
+ puts "ERROR: Cannot delete the stack '#{stack_name}' : #{error_str}"
252
+ rescue Exception => e
253
+ puts "ERROR: Cannot delete the stack '#{stack_name}' : #{e.class.name}: #{e.message}"
254
+ end
255
+ end
256
+
257
+ def get_clients_group(stack_name)
258
+ ClientsGroup.new(stack_name)
259
+ end
260
+
261
+ def establish_ssh_connection(clients_group)
262
+ STDOUT.sync = true
263
+ ssh_established = false
264
+ begin
265
+ start_timestamp = Time.now
266
+ sess_options = {:keys => [aws_ssh_pem_file]}
267
+ # just some simple command
268
+ command = 'pwd 1>/dev/null'
269
+
270
+ # clean-up outdated info (sometimes DNS names are re-used
271
+ # so we need to clean-up SSH known hosts file)
272
+ clients_group.client_instances.each do |hostname|
273
+ system("ssh-keygen -R #{hostname} 1>/dev/null 2>&1")
274
+ end
275
+
276
+ puts ""
277
+ puts " Stack '#{clients_group.stack_name}' is created. Waiting for SSH services to start-up..."
278
+ while not ssh_established
279
+ begin
280
+ run_stack_ssh_command(clients_group.client_instances, command)
281
+ # if we are here - SSH command has executed succesfully
282
+ puts " Done."
283
+ ssh_established = true
284
+ break
285
+ rescue Interrupt => i
286
+ raise "User Interruption"
287
+ rescue Net::SSH::AuthenticationFailed => e
288
+ raise e
289
+ rescue OpenSSL::PKey::PKeyError => e
290
+ raise e
291
+ rescue Errno::ECONNREFUSED => e
292
+ # service is not yet started - wait more
293
+ end
294
+
295
+ # try for 60 seconds maximum
296
+ if (Time.now.to_i - start_timestamp.to_i) > Constants::WAIT_FOR_SSH
297
+ puts " Failed!"
298
+ puts "ERROR: Cannot establish SSH session with the stack's EC2 instances..."
299
+ puts ""
300
+ break
301
+ end
302
+
303
+ sleep(10)
304
+ print '. '
305
+ end
306
+ rescue Exception => e
307
+ puts " Failed!"
308
+ puts "ERROR: Cannot establish SSH session with the stack's EC2 instances : #{e.class.name} : #{e.message}"
309
+ puts ""
310
+ end
311
+
312
+ ssh_established
313
+ end
314
+
315
+ def run_stack_ssh_command(ec2_clients, command)
316
+ sess_options = {:keys => [aws_ssh_pem_file]}
317
+ Net::SSH::Multi.start({:default_user => 'ec2-user'}) do |session|
318
+ # define the servers we want to use
319
+ session.use(sess_options) { ec2_clients }
320
+
321
+ # execute commands on all servers
322
+ session.exec command
323
+ end
324
+ end
325
+ end
326
+ end
@@ -1,90 +1,283 @@
1
1
  #!/usr/bin/ruby
2
2
  require 'rubygems'
3
- require 'yaml'
4
- require 'gruff'
5
- $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', '..','lib'))
6
- require 'bench'
7
3
 
8
- # 1) load all result YAML files
9
- current_dir = Dir.pwd
10
- results_dir = ARGV[0]
11
- if results_dir.nil?
12
- puts "Bench Result Processor: No result directory is provided - Skipping ..."
13
- exit(1)
14
- end
15
- Dir.chdir results_dir
16
- results_dir = Dir.pwd
17
-
18
- Dir.chdir current_dir
19
- output_dir = ARGV[1]
20
- output_dir ||= 'images'
21
- begin
22
- Dir.mkdir output_dir
23
- rescue
24
- end
25
- Dir.chdir output_dir
26
- output_dir = Dir.pwd
4
+ module Bench
5
+ def self.gem_installed?(gem_name)
6
+ (Gem::Specification.respond_to?(:find_by_name) ?
7
+ Gem::Specification.find_by_name(gem_name) : Gem.source_index.find_name(gem_name).last) != nil
8
+ rescue Exception => e
9
+ false
10
+ end
27
11
 
28
- # load meta.yaml
29
- meta_hash = YAML.load_file("#{results_dir}/meta.yml") if File.exists?("#{results_dir}/meta.yml")
30
- if meta_hash.nil?
31
- puts "Bench Result Processor: No valid meta.yml file is found in the result directory - Skipping ..."
32
- exit(1)
33
- end
12
+ module PostProcessing
13
+ @plugins = ['RhoSpreadSheet','RhoGruff']
14
+
15
+
16
+ def self.execute(res_dir)
17
+ return unless res_dir
18
+
19
+ puts ""
20
+ puts "Starting Benchmark Post-Processing ..."
21
+ puts ""
22
+
23
+ @plugins.each do |plugin|
24
+ plugin_class = eval(plugin)
25
+ available = plugin_class.has?
26
+ if available
27
+ available = plugin_class.load_myself
28
+ end
29
+
30
+ # print the message
31
+ if not available
32
+ puts ""
33
+ plugin_class.what_is_needed?
34
+ puts ""
35
+ next
36
+ end
37
+
38
+ plugin_instance = plugin_class.new
39
+ plugin_instance.process res_dir
40
+ end
41
+ end
42
+
43
+ # this post-processor creates EXCEL spreadsheets
44
+ class RhoSpreadSheet
45
+ def self.has?
46
+ Bench::gem_installed?('spreadsheet')
47
+ end
48
+
49
+ def self.what_is_needed?
50
+ puts "In order to run SpreadSheet post-processor - you need to have SpreadSheet gem installed"
51
+ puts "Install it by using : '[sudo] gem install spreadsheet'"
52
+ end
53
+
54
+ def self.load_myself
55
+ require 'yaml'
56
+ require 'spreadsheet'
57
+ true
58
+ end
59
+
60
+ def process(res_dir)
61
+ current_dir = Dir.pwd
62
+ begin
63
+ puts "Starting SpreadSheet post-processor..."
64
+ # 1) Create images dir
65
+ Dir.chdir res_dir
66
+ @results_dir = Dir.pwd
67
+ output_dir = Bench.create_subdir 'spreadsheet'
68
+ Dir.chdir output_dir
69
+ @output_dir = Dir.pwd
70
+
71
+ _load_meta_hash
72
+ _init
73
+ _process_res_files
74
+ _write
75
+ Dir.chdir current_dir
76
+ rescue Exception => e
77
+ Dir.chdir current_dir
78
+ raise e
79
+ end
80
+ end
81
+
82
+ def _load_meta_hash
83
+ # load meta.yaml
84
+ @meta_hash = YAML.load_file(File.join(@results_dir,'raw_data','meta.yml')) if File.exists?(File.join(@results_dir,'raw_data','meta.yml'))
85
+ if @meta_hash.nil?
86
+ raise "SpreadSheet Result Processor: No valid meta.yml file is found in the result directory - Skipping ..."
87
+ end
34
88
 
35
- @metrics = meta_hash[:metrics]
36
- if @metrics.nil?
37
- puts "Bench Result Processor: No valid metrics are found in the result directory - Skipping ..."
38
- exit(1)
39
- end
89
+ @metrics = @meta_hash[:metrics]
90
+ if @metrics.nil?
91
+ raise "SpreadSheet Result Processor: No valid metrics are found in the result directory - Skipping ..."
92
+ end
40
93
 
41
- if meta_hash[:x_keys].nil?
42
- puts "Bench Result Processor: No valid x_keys are found in the result directory - Skipping ..."
43
- exit(1)
44
- end
45
- @x_keys = meta_hash[:x_keys].keys
46
- @x_keys = @x_keys.sort_by(&Bench.sort_natural_order)
94
+ if @meta_hash[:x_keys].nil?
95
+ raise "SpreadSheet Result Processor: No valid x_keys are found in the result directory - Skipping ..."
96
+ end
97
+ @x_keys = @meta_hash[:x_keys].keys
98
+ @x_keys = @x_keys.sort_by(&Bench.sort_natural_order)
99
+ end
100
+
101
+ def _init
102
+ # initialize graphs for each metric
103
+ # row 0 - payload labels
104
+ # col 0 - X keys
105
+ @title = @meta_hash[:label]
106
+ @book = Spreadsheet::Workbook.new(@title)
107
+ @sheets = {}
108
+ axis_format = Spreadsheet::Format.new :color => :blue,
109
+ :weight => :bold,
110
+ :size => 18
111
+ @metrics.each do |name,index|
112
+ sheet = @book.create_worksheet({:name => "#{name} (#{@title})"})
113
+ @sheets[index] = sheet
114
+ sheet.column(0).default_format = axis_format
115
+ sheet.row(0).default_format = axis_format
116
+ @meta_hash[:x_keys].each do |key,key_index|
117
+ sheet[key_index + 1, 0] = "#{key}"
118
+ end
119
+ end
120
+ end
121
+
122
+ def _process_res_files
123
+ # load all result files
124
+ res_files = Dir.entries(File.join(@results_dir,'raw_data')).collect { |entry| entry if entry =~ /bench.*result/ }
125
+ res_files.compact!
126
+ res_files = res_files.sort_by(&Bench.sort_natural_order)
127
+
128
+ res_files.each_with_index do |entry, entry_index|
129
+ begin
130
+ res_hash = YAML.load_file(File.join(@results_dir,'raw_data',entry))
131
+ next if res_hash.nil? or res_hash.empty?
47
132
 
48
- # initialize graphs for each metric
49
- graphs = {}
50
- title = meta_hash[:label]
51
- @metrics.each do |name,index|
52
- g = Gruff::Line.new
53
- g.title = "#{title} (#{name})"
54
- g.labels = meta_hash[:x_keys].invert
55
- graphs[index] = g
56
- end
133
+ marker = entry.split('.').last.to_s
134
+
135
+ @sheets.each do |index,sheet|
136
+ sheet[0, entry_index + 1] = "#{marker}"
137
+ end
57
138
 
58
- # load all result files
59
- Dir.foreach(results_dir) do |entry|
60
- begin
61
- next unless entry =~ /bench.*result/
62
-
63
- res_hash = YAML.load_file(File.join(results_dir, entry))
64
- next if res_hash.nil? or res_hash.empty?
65
-
66
- marker = entry.split('.').last.to_s
67
-
68
- g_data = Array.new(@metrics.size) { Array.new }
69
- @x_keys.each do |x_key|
70
- results = res_hash[x_key]
71
- results ||= Array.new(@metrics.size, 0.0)
72
- results.each_with_index do |res, index|
73
- g_data[index] << ("%0.4f" % res).to_f
139
+ g_data = Array.new(@metrics.size) { Array.new }
140
+ @x_keys.each do |x_key|
141
+ row_idx = @meta_hash[:x_keys][x_key] + 1
142
+ results = res_hash[x_key]
143
+ results ||= Array.new(@metrics.size, 0.0)
144
+ results.each_with_index do |res, index|
145
+ col_idx = entry_index + 1
146
+ @sheets[index][row_idx,col_idx] = ("%0.4f" % res).to_f
147
+ end
148
+ end
149
+ rescue Exception => e
150
+ raise "SpreadSheet processing resulted in Error : #{e.message} " + e.backtrace.join("\n")
151
+ end
152
+ end
153
+ end
154
+
155
+ def _write
156
+ image_fname = File.join(@output_dir,"bench_results.xls")
157
+ puts "Spreadsheet processor: writing #{image_fname}"
158
+ @book.write image_fname
74
159
  end
75
160
  end
76
161
 
77
- graphs.each do |index, graph|
78
- graph.data("#{marker}", g_data[index])
162
+ # this post-processor creates PNG graph files
163
+ class RhoGruff
164
+ def self.has?
165
+ Bench::gem_installed?('gruff')
166
+ end
167
+
168
+ def self.what_is_needed?
169
+ puts "In order to run Gruff post-processor - you need to have Gruff gem installed"
170
+ puts "Install it by using : '[sudo] gem install gruff'"
171
+ puts "You may also need to install additional components - please check Gruff documentation for details"
172
+ end
173
+
174
+ def self.load_myself
175
+ res = true
176
+ begin
177
+ require 'yaml'
178
+ require 'gruff'
179
+ rescue Exception => e
180
+ puts " Can not run Gruff post-processor : #{e.message}"
181
+ res = false
182
+ end
183
+ res
184
+ end
185
+
186
+ def process(res_dir)
187
+ current_dir = Dir.pwd
188
+ begin
189
+ puts "Starting Gruff post-processor..."
190
+ # 1) Create images dir
191
+ Dir.chdir res_dir
192
+ @results_dir = Dir.pwd
193
+ output_dir = Bench.create_subdir 'images'
194
+ Dir.chdir output_dir
195
+ @output_dir = Dir.pwd
196
+
197
+ _load_meta_hash
198
+ _init_graphs
199
+ _process_res_files
200
+ _write_graphs
201
+ Dir.chdir current_dir
202
+ rescue Exception => e
203
+ Dir.chdir current_dir
204
+ raise e
205
+ end
206
+ end
207
+
208
+ def _load_meta_hash
209
+ # load meta.yaml
210
+ @meta_hash = YAML.load_file(File.join(@results_dir,'raw_data','meta.yml')) if File.exists?(File.join(@results_dir,'raw_data','meta.yml'))
211
+ if @meta_hash.nil?
212
+ raise "Gruff Result Processor: No valid meta.yml file is found in the result directory - Skipping ..."
213
+ end
214
+
215
+ @metrics = @meta_hash[:metrics]
216
+ if @metrics.nil?
217
+ raise "Gruff Result Processor: No valid metrics are found in the result directory - Skipping ..."
218
+ end
219
+
220
+ if @meta_hash[:x_keys].nil?
221
+ raise "Gruff Result Processor: No valid x_keys are found in the result directory - Skipping ..."
222
+ end
223
+ @x_keys = @meta_hash[:x_keys].keys
224
+ @x_keys = @x_keys.sort_by(&Bench.sort_natural_order)
225
+ end
226
+
227
+ def _init_graphs
228
+ # initialize graphs for each metric
229
+ @graphs = {}
230
+ @title = @meta_hash[:label]
231
+ @metrics.each do |name,index|
232
+ g = Gruff::Line.new
233
+ g.title = "#{@title} (#{name})"
234
+ g.labels = @meta_hash[:x_keys].invert
235
+ @graphs[index] = g
236
+ end
237
+ end
238
+
239
+ def _process_res_files
240
+ # load all result files
241
+ res_files = Dir.entries(File.join(@results_dir,'raw_data')).collect { |entry| entry if entry =~ /bench.*result/ }
242
+ res_files.compact!
243
+ res_files = res_files.sort_by(&Bench.sort_natural_order)
244
+
245
+ # we can only create 7 unique lines
246
+ # per graph
247
+ for entry in res_files.last(7) do
248
+ begin
249
+ res_hash = YAML.load_file(File.join(@results_dir,'raw_data',entry))
250
+ next if res_hash.nil? or res_hash.empty?
251
+
252
+ marker = entry.split('.').last.to_s
253
+
254
+ g_data = Array.new(@metrics.size) { Array.new }
255
+ @x_keys.each do |x_key|
256
+ results = res_hash[x_key]
257
+ results ||= Array.new(@metrics.size, 0.0)
258
+ results.each_with_index do |res, index|
259
+ g_data[index] << ("%0.4f" % res).to_f
260
+ end
261
+ end
262
+
263
+ @graphs.each do |index, graph|
264
+ graph.data("#{marker}", g_data[index])
265
+ end
266
+ rescue Exception => e
267
+ raise "Gruff processing resulted in Error : " + e.backtrace.join("\n")
268
+ end
269
+ end
270
+ end
271
+
272
+ def _write_graphs
273
+ # write out resulting graphs
274
+ @metrics.each do |name, index|
275
+ image_fname = File.join(@output_dir,"#{name}.png")
276
+ puts "Gruff processor: writing #{image_fname}"
277
+ @graphs[index].write image_fname
278
+ end
279
+ end
79
280
  end
80
- rescue Exception => e
81
- puts " Benchmark processing resulted in Error : " + e.backtrace.join("\n")
82
- throw e
83
281
  end
84
282
  end
85
283
 
86
- # write out resulting graphs
87
- @metrics.each do |name, index|
88
- puts "writing #{output_dir}/#{name}.png"
89
- graphs[index].write "#{output_dir}/#{name}.png"
90
- end
@@ -20,6 +20,7 @@ module Bench
20
20
  Statistics.new(Bench.concurrency,Bench.iterations,
21
21
  Bench.total_time,Bench.start_time,Bench.end_time,Bench.sessions).process.print_stats.save_results
22
22
  bench_log "Bench completed..."
23
+ Bench.reset_app
23
24
  end
24
25
  end
25
26