gitlab-derailed_benchmarks 1.6.1

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 (89) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/check_changelog.yml +10 -0
  3. data/.gitignore +8 -0
  4. data/.gitlab-ci.yml +56 -0
  5. data/.travis.yml +18 -0
  6. data/Appraisals +26 -0
  7. data/CHANGELOG.md +105 -0
  8. data/Gemfile +9 -0
  9. data/README.md +692 -0
  10. data/Rakefile +29 -0
  11. data/bin/derailed +93 -0
  12. data/derailed_benchmarks.gemspec +39 -0
  13. data/gemfiles/.bundle/config +2 -0
  14. data/gemfiles/rails_5_1.gemfile +15 -0
  15. data/gemfiles/rails_5_2.gemfile +15 -0
  16. data/gemfiles/rails_6_0.gemfile +15 -0
  17. data/gemfiles/rails_git.gemfile +19 -0
  18. data/lib/derailed_benchmarks.rb +51 -0
  19. data/lib/derailed_benchmarks/auth_helper.rb +34 -0
  20. data/lib/derailed_benchmarks/auth_helpers/devise.rb +41 -0
  21. data/lib/derailed_benchmarks/core_ext/kernel_require.rb +88 -0
  22. data/lib/derailed_benchmarks/load_tasks.rb +145 -0
  23. data/lib/derailed_benchmarks/require_tree.rb +65 -0
  24. data/lib/derailed_benchmarks/stats_from_dir.rb +128 -0
  25. data/lib/derailed_benchmarks/stats_in_file.rb +60 -0
  26. data/lib/derailed_benchmarks/tasks.rb +292 -0
  27. data/lib/derailed_benchmarks/version.rb +5 -0
  28. data/test/derailed_benchmarks/core_ext/kernel_require_test.rb +33 -0
  29. data/test/derailed_benchmarks/require_tree_test.rb +95 -0
  30. data/test/derailed_benchmarks/stats_from_dir_test.rb +125 -0
  31. data/test/derailed_test.rb +14 -0
  32. data/test/fixtures/require/child_one.rb +4 -0
  33. data/test/fixtures/require/child_two.rb +9 -0
  34. data/test/fixtures/require/parent_one.rb +8 -0
  35. data/test/fixtures/require/raise_child.rb +6 -0
  36. data/test/fixtures/require/relative_child.rb +4 -0
  37. data/test/fixtures/require/relative_child_two.rb +4 -0
  38. data/test/fixtures/stats/significant/loser.bench.txt +100 -0
  39. data/test/fixtures/stats/significant/winner.bench.txt +100 -0
  40. data/test/integration/tasks_test.rb +132 -0
  41. data/test/rails_app/Rakefile +9 -0
  42. data/test/rails_app/app/assets/config/manifest.js +0 -0
  43. data/test/rails_app/app/assets/javascripts/authenticated.js +2 -0
  44. data/test/rails_app/app/assets/stylesheets/authenticated.css +4 -0
  45. data/test/rails_app/app/controllers/application_controller.rb +17 -0
  46. data/test/rails_app/app/controllers/authenticated_controller.rb +8 -0
  47. data/test/rails_app/app/controllers/pages_controller.rb +14 -0
  48. data/test/rails_app/app/helpers/application_helper.rb +4 -0
  49. data/test/rails_app/app/helpers/authenticated_helper.rb +4 -0
  50. data/test/rails_app/app/models/user.rb +13 -0
  51. data/test/rails_app/app/views/authenticated/index.html.erb +1 -0
  52. data/test/rails_app/app/views/layouts/application.html.erb +14 -0
  53. data/test/rails_app/app/views/pages/index.html.erb +1 -0
  54. data/test/rails_app/config.ru +6 -0
  55. data/test/rails_app/config/application.rb +52 -0
  56. data/test/rails_app/config/boot.rb +12 -0
  57. data/test/rails_app/config/database.yml +22 -0
  58. data/test/rails_app/config/environment.rb +11 -0
  59. data/test/rails_app/config/environments/development.rb +27 -0
  60. data/test/rails_app/config/environments/production.rb +51 -0
  61. data/test/rails_app/config/environments/test.rb +37 -0
  62. data/test/rails_app/config/initializers/backtrace_silencers.rb +9 -0
  63. data/test/rails_app/config/initializers/devise.rb +258 -0
  64. data/test/rails_app/config/initializers/inflections.rb +12 -0
  65. data/test/rails_app/config/initializers/mime_types.rb +7 -0
  66. data/test/rails_app/config/initializers/secret_token.rb +13 -0
  67. data/test/rails_app/config/initializers/session_store.rb +10 -0
  68. data/test/rails_app/config/locales/devise.en.yml +59 -0
  69. data/test/rails_app/config/locales/en.yml +9 -0
  70. data/test/rails_app/config/locales/es.yml +10 -0
  71. data/test/rails_app/config/routes.rb +67 -0
  72. data/test/rails_app/db/migrate/20141210070547_devise_create_users.rb +45 -0
  73. data/test/rails_app/db/schema.rb +35 -0
  74. data/test/rails_app/perf.rake +10 -0
  75. data/test/rails_app/public/404.html +26 -0
  76. data/test/rails_app/public/422.html +26 -0
  77. data/test/rails_app/public/500.html +26 -0
  78. data/test/rails_app/public/favicon.ico +0 -0
  79. data/test/rails_app/public/javascripts/application.js +2 -0
  80. data/test/rails_app/public/javascripts/controls.js +965 -0
  81. data/test/rails_app/public/javascripts/dragdrop.js +974 -0
  82. data/test/rails_app/public/javascripts/effects.js +1123 -0
  83. data/test/rails_app/public/javascripts/prototype.js +6001 -0
  84. data/test/rails_app/public/javascripts/rails.js +202 -0
  85. data/test/rails_app/public/stylesheets/.gitkeep +0 -0
  86. data/test/rails_app/script/rails +8 -0
  87. data/test/support/integration_case.rb +7 -0
  88. data/test/test_helper.rb +65 -0
  89. metadata +398 -0
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ require 'rubygems'
5
+ require 'bundler'
6
+ require "bundler/gem_tasks"
7
+
8
+ begin
9
+ Bundler.setup(:default, :development, :test)
10
+ rescue Bundler::BundlerError => e
11
+ $stderr.puts e.message
12
+ $stderr.puts "Run `bundle install` to install missing gems"
13
+ exit e.status_code
14
+ end
15
+
16
+ require 'rake'
17
+
18
+ require 'rake/testtask'
19
+
20
+ Rake::TestTask.new(:test) do |t|
21
+ t.libs << 'lib'
22
+ t.libs << 'test'
23
+ t.pattern = 'test/**/*_test.rb'
24
+ t.verbose = false
25
+ end
26
+
27
+ task default: :test
28
+
29
+
data/bin/derailed ADDED
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ unless File.respond_to? :realpath
5
+ class File #:nodoc:
6
+ def self.realpath path
7
+ return realpath(File.readlink(path)) if symlink?(path)
8
+ path
9
+ end
10
+ end
11
+ end
12
+ lib = File.expand_path(File.dirname(File.realpath(__FILE__)) + '/../lib')
13
+ $: << lib
14
+
15
+
16
+ require File.join(lib, 'derailed_benchmarks.rb')
17
+
18
+ Bundler.setup
19
+
20
+ require 'thor'
21
+
22
+ class DerailedBenchmarkCLI < Thor
23
+
24
+ desc "exec", "executes given derailed benchmark"
25
+ def exec(task = nil)
26
+ setup_bundler!
27
+ require 'derailed_benchmarks'
28
+ require 'rake'
29
+ Rake::TaskManager.record_task_metadata = true
30
+ require 'derailed_benchmarks/tasks'
31
+
32
+ perf_rakefile = File.expand_path(".", "perf.rake")
33
+ load perf_rakefile if File.exist?(perf_rakefile)
34
+
35
+ if task.nil? || task == "--help"
36
+ Rake.application.tasks.map do |task, n|
37
+ next unless task.comment
38
+ puts " $ derailed exec #{task.name} # #{task.comment}"
39
+ end
40
+ else
41
+ task = "perf:#{task}" unless Rake::Task.task_defined?(task)
42
+ Rake::Task[task].invoke
43
+ end
44
+ end
45
+
46
+ desc "bundle:objects", "measures objects created by gems"
47
+ define_method(:"bundle:objects") do |env = "production"|
48
+ setup_bundler!
49
+ env = [:default] + env.split(",")
50
+ puts "Measuring objects created by gems in groups #{ env.inspect }"
51
+ require 'memory_profiler'
52
+ report = MemoryProfiler.report do
53
+ Bundler.require(*env)
54
+ end
55
+ report.pretty_print
56
+ end
57
+
58
+ map :"bundler:objects" => :"bundle:objects"
59
+
60
+ desc "bundle:mem", "measures memory used by gems at boot time"
61
+ define_method(:"bundle:mem") do |env = "production"|
62
+ env = [:default] + env.split(",")
63
+ require 'get_process_mem'
64
+ mem = GetProcessMem.new
65
+ require 'derailed_benchmarks/core_ext/kernel_require'
66
+ before = mem.mb
67
+ setup_bundler!
68
+ Bundler.require(*env)
69
+ after = mem.mb
70
+ TOP_REQUIRE.print_sorted_children
71
+ end
72
+ map :"bundler:mem" => :"bundle:mem"
73
+
74
+ private
75
+ def setup_bundler!
76
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
77
+ require 'bundler/setup'
78
+
79
+ begin
80
+ if ENV["DERAILED_SKIP_ACTIVE_RECORD"]
81
+ require "action_controller/railtie"
82
+ require "action_mailer/railtie"
83
+ require "sprockets/railtie"
84
+ require "rails/test_unit/railtie"
85
+ else
86
+ require 'rails/all'
87
+ end
88
+ rescue LoadError
89
+ end
90
+ end
91
+ end
92
+
93
+ DerailedBenchmarkCLI.start(ARGV)
@@ -0,0 +1,39 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ lib = File.expand_path('../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require 'derailed_benchmarks/version'
7
+
8
+ Gem::Specification.new do |gem|
9
+ gem.name = "gitlab-derailed_benchmarks"
10
+ gem.version = DerailedBenchmarks::VERSION
11
+ gem.authors = ["Richard Schneeman"]
12
+ gem.email = ["richard.schneeman+rubygems@gmail.com"]
13
+ gem.description = %q{ Go faster, off the Rails }
14
+ gem.summary = %q{ Benchmarks designed to performance test your ENTIRE site }
15
+ gem.homepage = "https://github.com/schneems/derailed_benchmarks"
16
+ gem.license = "MIT"
17
+
18
+ gem.files = `git ls-files`.split($/)
19
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.require_paths = ["lib"]
22
+
23
+ gem.required_ruby_version = ">= 2.1.0"
24
+
25
+ gem.add_dependency "heapy", "~> 0"
26
+ gem.add_dependency "memory_profiler", "~> 0"
27
+ gem.add_dependency "get_process_mem", "~> 0"
28
+ gem.add_dependency "benchmark-ips", "~> 2"
29
+ gem.add_dependency "rack", ">= 1"
30
+ gem.add_dependency "rake", "> 10", "< 14"
31
+ gem.add_dependency "thor", ">= 0.19", "< 2"
32
+ gem.add_dependency "ruby-statistics", ">= 2.1"
33
+
34
+ gem.add_development_dependency "capybara", "~> 2"
35
+ gem.add_development_dependency "m"
36
+ gem.add_development_dependency "rails", "> 3", "<= 7"
37
+ gem.add_development_dependency "devise", "> 3", "< 6"
38
+ gem.add_development_dependency "appraisal", "2.2.0"
39
+ end
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_RETRY: "1"
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file was generated by Appraisal
4
+
5
+ source "https://rubygems.org"
6
+
7
+ gem "rails", "~> 5.1.0"
8
+
9
+ group :development, :test do
10
+ gem "sqlite3", platform: [:ruby, :mswin, :mingw]
11
+ gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.13", platform: :jruby
12
+ gem "test-unit", "~> 3.0"
13
+ end
14
+
15
+ gemspec path: "../"
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file was generated by Appraisal
4
+
5
+ source "https://rubygems.org"
6
+
7
+ gem "rails", "~> 5.2.0"
8
+
9
+ group :development, :test do
10
+ gem "sqlite3", platform: [:ruby, :mswin, :mingw]
11
+ gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.13", platform: :jruby
12
+ gem "test-unit", "~> 3.0"
13
+ end
14
+
15
+ gemspec path: "../"
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file was generated by Appraisal
4
+
5
+ source "https://rubygems.org"
6
+
7
+ gem "rails", "6.0.0"
8
+
9
+ group :development, :test do
10
+ gem "sqlite3", platform: [:ruby, :mswin, :mingw]
11
+ gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.13", platform: :jruby
12
+ gem "test-unit", "~> 3.0"
13
+ end
14
+
15
+ gemspec path: "../"
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # $ BUNDLE_GEMFILE="$(pwd)/gemfiles/rails_git.gemfile" bundle exec m test/integration/tasks_test.rb:30
4
+
5
+ source "https://rubygems.org"
6
+
7
+ gem "rails", github: "rails/rails", ref: "3054e1d584e7eca110c69a1f8423f2e0866abbf9"
8
+
9
+ gem 'devise', github: "plataformatec/devise"
10
+
11
+ group :development, :test do
12
+ gem "sqlite3", platform: [:ruby, :mswin, :mingw]
13
+ gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.13", platform: :jruby
14
+ gem "test-unit", "~> 3.0"
15
+ end
16
+
17
+ gemspec path: "../"
18
+
19
+ ENV['USING_RAILS_GIT'] = "1"
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+ require 'bundler'
5
+
6
+ require 'get_process_mem'
7
+
8
+ module DerailedBenchmarks
9
+ def self.gem_is_bundled?(name)
10
+ specs = ::Bundler.locked_gems.specs.each_with_object({}) {|spec, hash| hash[spec.name] = spec }
11
+ specs[name]
12
+ end
13
+
14
+ class << self
15
+ attr_accessor :auth
16
+ end
17
+
18
+ def self.rails_path_on_disk
19
+ require 'rails/version'
20
+ rails_version_file = Rails.method(:version).source_location[0]
21
+ path = Pathname.new(rails_version_file).expand_path.parent.parent
22
+
23
+ while path != Pathname.new("/")
24
+ basename = path.expand_path.basename.to_s
25
+
26
+ break if basename.start_with?("rails") && basename != "railties"
27
+ path = path.parent
28
+ end
29
+ raise "Could not find rails folder on a folder in #{rails_version_file}" if path == Pathname.new("/")
30
+ path.expand_path
31
+ end
32
+
33
+ def self.add_auth(app)
34
+ if use_auth = ENV['USE_AUTH']
35
+ puts "Auth: #{use_auth}"
36
+ auth.add_app(app)
37
+ else
38
+ app
39
+ end
40
+ end
41
+ end
42
+
43
+ require 'derailed_benchmarks/require_tree'
44
+ require 'derailed_benchmarks/auth_helper'
45
+
46
+ require 'derailed_benchmarks/stats_in_file'
47
+ require 'derailed_benchmarks/stats_from_dir'
48
+
49
+ if DerailedBenchmarks.gem_is_bundled?("devise")
50
+ DerailedBenchmarks.auth = DerailedBenchmarks::AuthHelpers::Devise.new
51
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module DerailedBenchmarks
6
+ # Base helper class. Can be used to authenticate different strategies
7
+ # The root app will be wrapped by an authentication action
8
+ class AuthHelper
9
+ attr_reader :app
10
+
11
+ # Put any coded needed to set up or initialize your authentication module here
12
+ def setup
13
+ raise "Must subclass"
14
+ end
15
+
16
+ # Gets called for every request. Place all auth logic here.
17
+ # Return value is expected to be an valid Rack response array.
18
+ # If you do not manually `app.call(env)` here, the client app
19
+ # will never be called.
20
+ def call(env)
21
+ raise "Must subclass"
22
+ end
23
+
24
+ # Returns self and sets the target app
25
+ def add_app(app)
26
+ raise "App is required argument" unless app
27
+ @app = app
28
+ setup
29
+ self
30
+ end
31
+ end
32
+ end
33
+
34
+ require 'derailed_benchmarks/auth_helpers/devise'
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DerailedBenchmarks
4
+ class AuthHelpers
5
+ # Devise helper for authenticating requests
6
+ # Setup adds necessarry test methods, user provides a sample user.
7
+ # The authenticate method is called on every request when authentication is enabled
8
+ class Devise < AuthHelper
9
+ attr_writer :user
10
+
11
+ # Include devise test helpers and turn on test mode
12
+ # We need to do this on the class level
13
+ def setup
14
+ # self.class.instance_eval do
15
+ require 'devise'
16
+ require 'warden'
17
+ extend ::Warden::Test::Helpers
18
+ extend ::Devise::TestHelpers
19
+ Warden.test_mode!
20
+ # end
21
+ end
22
+
23
+ def user
24
+ if @user
25
+ @user = @user.call if @user.is_a?(Proc)
26
+ @user
27
+ else
28
+ password = SecureRandom.hex
29
+ @user = User.first_or_create!(email: "#{SecureRandom.hex}@example.com", password: password, password_confirmation: password)
30
+ end
31
+ end
32
+
33
+ # Logs the user in, then call the parent app
34
+ def call(env)
35
+ login_as(user)
36
+ app.call(env)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'get_process_mem'
4
+ require 'derailed_benchmarks/require_tree'
5
+
6
+ ENV['CUT_OFF'] ||= "0.3"
7
+
8
+ # This file contains classes and monkey patches to measure the amount of memory
9
+ # useage requiring an individual file adds.
10
+
11
+ # Monkey patch kernel to ensure that all `require` calls call the same
12
+ # method
13
+ module Kernel
14
+ REQUIRE_STACK = []
15
+
16
+ module_function
17
+
18
+ alias_method :original_require, :require
19
+ alias_method :original_require_relative, :require_relative
20
+
21
+ def require(file)
22
+ measure_memory_impact(file) do |file|
23
+ # "source_annotation_extractor" is deprecated in Rails 6
24
+ # # if we don't skip the library it leads to a crash
25
+ # next if file == "rails/source_annotation_extractor" && Rails.version >= '6.0'
26
+ original_require(file)
27
+ end
28
+ end
29
+
30
+ def require_relative(file)
31
+ if Pathname.new(file).absolute?
32
+ require file
33
+ else
34
+ require File.expand_path("../#{file}", caller_locations(1, 1)[0].absolute_path)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # The core extension we use to measure require time of all requires
41
+ # When a file is required we create a tree node with its file name.
42
+ # We then push it onto a stack, this is because requiring a file can
43
+ # require other files before it is finished.
44
+ #
45
+ # When a child file is required, a tree node is created and the child file
46
+ # is pushed onto the parents tree. We then repeat the process as child
47
+ # files may require additional files.
48
+ #
49
+ # When a require returns we remove it from the require stack so we don't
50
+ # accidentally push additional children nodes to it. We then store the
51
+ # memory cost of the require in the tree node.
52
+ def measure_memory_impact(file, &block)
53
+ mem = GetProcessMem.new
54
+ node = DerailedBenchmarks::RequireTree.new(file)
55
+
56
+ parent = REQUIRE_STACK.last
57
+ parent << node
58
+ REQUIRE_STACK.push(node)
59
+ begin
60
+ before = mem.mb
61
+ block.call file
62
+ ensure
63
+ REQUIRE_STACK.pop # node
64
+ after = mem.mb
65
+ end
66
+ node.cost = after - before
67
+ end
68
+ end
69
+
70
+ # Top level node that will store all require information for the entire app
71
+ TOP_REQUIRE = DerailedBenchmarks::RequireTree.new("TOP")
72
+ REQUIRE_STACK.push(TOP_REQUIRE)
73
+
74
+ class Object
75
+ private
76
+
77
+ def require(path)
78
+ Kernel.require(path)
79
+ end
80
+ end
81
+
82
+ # Don't forget to assign a cost to the top level
83
+ cost_before_requiring_anything = GetProcessMem.new.mb
84
+ TOP_REQUIRE.cost = cost_before_requiring_anything
85
+ def TOP_REQUIRE.print_sorted_children(*args)
86
+ self.cost = GetProcessMem.new.mb - self.cost
87
+ super
88
+ end