gitlab-derailed_benchmarks 1.6.1

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