diff --git a/.gitignore b/.gitignore index 173f8b3..aabe3cb 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ # Ignore all logfiles and tempfiles. /log/*.log /tmp +/prof # Backup files *~ @@ -23,4 +24,4 @@ config/repositories.yml config/database.yml features/support/kalibro_cucumber_helpers.yml coverage -.capistrano \ No newline at end of file +.capistrano diff --git a/Gemfile b/Gemfile index 46dc677..1e962ff 100644 --- a/Gemfile +++ b/Gemfile @@ -59,6 +59,12 @@ gem 'kolekti_metricfu', github: 'mezuro/kolekti_metricfu', branch: 'stable' gem 'unparser', '< 0.2.5' gem 'kolekti_radon', github: 'mezuro/kolekti_radon', branch: 'stable' +# Some statistics +gem 'descriptive-statistics', '~> 2.1.2' + +# Bulk SQL inserts +gem 'activerecord-import' + group :test do # Easier test writing gem "shoulda-matchers", '~>2.8.0' @@ -103,8 +109,7 @@ group :cucumber do # gem 'database_cleaner' # Removed because it is getting added above. end -# Some statistics -gem 'descriptive-statistics', '~> 2.1.2' + # Use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index be4fde8..44bc948 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,6 +66,8 @@ GEM activemodel (= 4.2.4) activesupport (= 4.2.4) arel (~> 6.0) + activerecord-import (0.15.0) + activerecord (>= 3.2) activesupport (4.2.4) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) @@ -386,6 +388,7 @@ PLATFORMS ruby DEPENDENCIES + activerecord-import byebug capistrano (~> 3.4.0) capistrano-bundler @@ -424,4 +427,4 @@ DEPENDENCIES unparser (< 0.2.5) BUNDLED WITH - 1.12.4 + 1.12.5 diff --git a/performance/base.rb b/performance/base.rb index fef11b5..804de3a 100644 --- a/performance/base.rb +++ b/performance/base.rb @@ -1,10 +1,18 @@ +require 'fileutils' require 'database_cleaner' require 'kalibro_client/kalibro_cucumber_helpers' module Performance class Base - def initialize - @results = {} + def initialize(num_runs: nil, measure_mode: nil, save_reports: true) + if num_runs.nil? + num_runs = ENV.key?('PROFILE_NUM_RUNS') ? ENV['PROFILE_NUM_RUNS'].to_i : 1 + end + + @num_runs = num_runs + @measure_mode = measure_mode + @save_reports = save_reports + @results = [] end def setup @@ -21,56 +29,62 @@ def teardown def subject; raise NotImplementedError; end def run - self.run_process_time - self.run_wall_time - - self.print - end + STDERR.puts "Profiling #{self.class.name}" - protected - - def run_wall_time - self.setup + if @measure_mode + RubyProf.measure_mode = RubyProf.const_get(@measure_mode) + end - RubyProf.measure_mode = RubyProf::WALL_TIME + @results = (1..@num_runs).map do |i| + STDERR.puts "Setup: start" + self.setup + STDERR.puts "Setup: finish" - @results['Wall Time'] = [] - (1..5).each do |it| - @results['Wall Time'] << RubyProf.profile do + STDERR.puts "Run #{i}: start" + prof = RubyProf.profile do self.subject end + STDERR.puts "Run #{i}: finish" + + STDERR.puts "Teardown: start" + self.teardown + STDERR.puts "Teardown: finish" + + prof end - self.teardown + self.save_reports if @save_reports + self.print end - def run_process_time - self.setup + protected - RubyProf.measure_mode = RubyProf::PROCESS_TIME + def print + puts "#{@measure_mode.to_s}:" - @results['Process Time'] = [] - (1..5).each do |it| - @results['Process Time'] << RubyProf.profile do - self.subject - end + if RubyProf.measure_mode == RubyProf::WALL_TIME + totals = @results.map { |r| r.threads.map(&:total_time).max } + else + totals = @results.map { |r| r.threads.map(&:total_time).reduce(:+) } end - self.teardown - end - - def print - puts "\n" - puts "#{self.class.name}\n----------" + totals.each do |time| + puts " #{time}" + end - @results.each do |title, result| - total = 0.0 + puts " Average: #{totals.reduce(:+) / @results.count}" + puts + end - result.each { |r| r.threads.each { |thread| total += thread.total_time} } + def save_reports + path = "prof/#{self.class.name}" + FileUtils.mkdir_p(path) + base_prof = Time.now.strftime('%Y-%m-%d_%H-%M-%S') - puts "* #{title}: #{total/result.count}" + @results.each_with_index do |result, i| + printer = RubyProf::MultiPrinter.new(result) + printer.print(path: path, profile: "#{base_prof}_#{i}") end - puts "\n" end end end diff --git a/performance/tests/aggregation.rb b/performance/tests/aggregation.rb index 80d5479..19deba6 100644 --- a/performance/tests/aggregation.rb +++ b/performance/tests/aggregation.rb @@ -21,6 +21,7 @@ def setup FactoryGirl.create(:metric_configuration, metric: FactoryGirl.build(:lines_of_code_metric, code: 'pyloc'), id: nil, kalibro_configuration_id: kalibro_configuration.id) ] code_dir = "/tmp/test" + repository = FactoryGirl.create(:repository, scm_type: "GIT", kalibro_configuration: kalibro_configuration, code_directory: code_dir) root_module_result = FactoryGirl.create(:module_result, id: nil, processing: nil, @@ -32,37 +33,34 @@ def setup Processor::Preparer.metrics_list(@context) previous_module_results = [root_module_result] - (0..(TREE_HEIGHT - 2)).each do # The first level is the ROOT - next_module_results = [] + ModuleResult.transaction do + (0..(TREE_HEIGHT - 2)).each do # The first level is the ROOT + next_module_results = [] - previous_module_results.each do |parent| - (0..(TREE_WIDTH - 1)).each do - next_module_results << FactoryGirl.create(:module_result, - id: nil, - processing: processing, - parent: parent, - tree_metric_results: [], - hotspot_metric_results: []) - FactoryGirl.create(:kalibro_module_with_package_granularity, - module_result: next_module_results.last, - long_name: [*('a'..'z'),*('0'..'9')].shuffle[0,8].join # random unique name - ) + previous_module_results.each do |parent| + (0..(TREE_WIDTH - 1)).each do + next_module_results << ModuleResult.create!(processing: processing, + parent_id: parent.id) + FactoryGirl.create(:kalibro_module_with_package_granularity, + module_result: next_module_results.last, + long_name: [*('a'..'z'),*('0'..'9')].shuffle[0,8].join # random unique name + ) + end end - end - previous_module_results = next_module_results + previous_module_results = next_module_results + end end + tree_metric_results = [] previous_module_results.each do |module_result| metric_configurations.each do |metric_configuration| - FactoryGirl.create(:tree_metric_result, - module_result: module_result, - metric_configuration: metric_configuration, - metric: metric_configuration.metric, - value: rand) + tree_metric_results << [module_result.id, metric_configuration.id, rand] end end + TreeMetricResult.import([:module_result_id, :metric_configuration_id, :value], tree_metric_results) + puts "Done creating #{ModuleResult.count} ModuleResults and #{MetricResult.count} MetricResults that will get aggregated following" end