rhoconnect 3.0.6 → 3.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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