rubybench_runner 0.1.0

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 (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +7 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +44 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +43 -0
  9. data/Rakefile +12 -0
  10. data/bin/console +15 -0
  11. data/bin/setup +8 -0
  12. data/exe/rubybench_runner +101 -0
  13. data/lib/rubybench_runner.rb +17 -0
  14. data/lib/rubybench_runner/base_runner.rb +233 -0
  15. data/lib/rubybench_runner/configurations.rb +68 -0
  16. data/lib/rubybench_runner/dependencies_checker.rb +39 -0
  17. data/lib/rubybench_runner/helpers_version +1 -0
  18. data/lib/rubybench_runner/rails/.bundle/config +4 -0
  19. data/lib/rubybench_runner/rails/benchmarks/assets/javascripts/application.js +3 -0
  20. data/lib/rubybench_runner/rails/benchmarks/assets/javascripts/one.js.erb +5 -0
  21. data/lib/rubybench_runner/rails/benchmarks/assets/javascripts/two.js +1 -0
  22. data/lib/rubybench_runner/rails/benchmarks/form_partials/first.html.erb +17 -0
  23. data/lib/rubybench_runner/rails/benchmarks/form_partials/heavy/_item.html.erb +12 -0
  24. data/lib/rubybench_runner/rails/benchmarks/form_partials/heavy/_second.html.erb +7 -0
  25. data/lib/rubybench_runner/rails/benchmarks/form_partials/heavy/_third.html.erb +8 -0
  26. data/lib/rubybench_runner/rails/benchmarks/form_partials/layouts/application.html.erb +29 -0
  27. data/lib/rubybench_runner/rails/benchmarks/partials/first.html.erb +19 -0
  28. data/lib/rubybench_runner/rails/benchmarks/partials/heavy/_item.html.erb +0 -0
  29. data/lib/rubybench_runner/rails/benchmarks/partials/heavy/_second.html.erb +7 -0
  30. data/lib/rubybench_runner/rails/benchmarks/partials/heavy/_third.html.erb +3 -0
  31. data/lib/rubybench_runner/rails/benchmarks/partials/layouts/application.html.erb +29 -0
  32. data/lib/rubybench_runner/rails/benchmarks/support/benchmark_rails.rb +14 -0
  33. data/lib/rubybench_runner/rails/benchmarks/support/echo_channel.rb +13 -0
  34. data/lib/rubybench_runner/rails/benchmarks/support/request_helper.rb +9 -0
  35. data/lib/rubybench_runner/rails/benchmarks/support/url_generation_base.rb +79 -0
  36. data/lib/rubybench_runner/rails/benchmarks/views/posts/_form.html.erb +29 -0
  37. data/lib/rubybench_runner/rails/benchmarks/views/posts/edit.html.erb +6 -0
  38. data/lib/rubybench_runner/rails/benchmarks/views/posts/index.html.erb +32 -0
  39. data/lib/rubybench_runner/rails/benchmarks/views/posts/index.json.jbuilder +4 -0
  40. data/lib/rubybench_runner/rails/benchmarks/views/posts/new.html.erb +5 -0
  41. data/lib/rubybench_runner/rails/benchmarks/views/posts/show.html.erb +19 -0
  42. data/lib/rubybench_runner/rails/benchmarks/views/posts/show.json.jbuilder +1 -0
  43. data/lib/rubybench_runner/rails_runner.rb +91 -0
  44. data/lib/rubybench_runner/support/benchmark_runner.rb +62 -0
  45. data/lib/rubybench_runner/support/helpers.rb +11 -0
  46. data/lib/rubybench_runner/support/setup/.bundle/config +4 -0
  47. data/lib/rubybench_runner/support/setup/Gemfile +11 -0
  48. data/lib/rubybench_runner/support/setup/bm_create_string_columns_setup.rb +16 -0
  49. data/lib/rubybench_runner/support/setup/bm_destroy_setup.rb +12 -0
  50. data/lib/rubybench_runner/support/setup/bm_discourse_setup.rb +164 -0
  51. data/lib/rubybench_runner/support/setup/bm_finders_setup.rb +37 -0
  52. data/lib/rubybench_runner/support/setup/bm_preload_setup.rb +41 -0
  53. data/lib/rubybench_runner/support/setup/bm_save_setup.rb +12 -0
  54. data/lib/rubybench_runner/support/setup/bm_scope_all_setup.rb +32 -0
  55. data/lib/rubybench_runner/support/setup/bm_scope_where_setup.rb +30 -0
  56. data/lib/rubybench_runner/support/setup/bm_validations_invalid_setup.rb +18 -0
  57. data/lib/rubybench_runner/support/setup/bm_validations_valid_setup.rb +30 -0
  58. data/lib/rubybench_runner/support/setup/bm_with_default_scope_setup.rb +29 -0
  59. data/lib/rubybench_runner/version.rb +5 -0
  60. data/rubybench_runner.gemspec +34 -0
  61. metadata +200 -0
@@ -0,0 +1,4 @@
1
+ json.array!(@posts) do |post|
2
+ json.extract! post, :id, :title, :body, :author
3
+ json.url post_url(post, format: :json)
4
+ end
@@ -0,0 +1,5 @@
1
+ <h1>New Post</h1>
2
+
3
+ <%= render 'form' %>
4
+
5
+ <%= link_to 'Back', posts_path %>
@@ -0,0 +1,19 @@
1
+ <p id="notice"><%= notice %></p>
2
+
3
+ <p>
4
+ <strong>Title:</strong>
5
+ <%= @post.title %>
6
+ </p>
7
+
8
+ <p>
9
+ <strong>Body:</strong>
10
+ <%= @post.body %>
11
+ </p>
12
+
13
+ <p>
14
+ <strong>Author:</strong>
15
+ <%= @post.author %>
16
+ </p>
17
+
18
+ <%= link_to 'Edit', edit_post_path(@post) %> |
19
+ <%= link_to 'Back', posts_path %>
@@ -0,0 +1 @@
1
+ json.extract! @post, :id, :title, :body, :author, :created_at, :updated_at
@@ -0,0 +1,91 @@
1
+ module RubybenchRunner
2
+ class RailsRunner < BaseRunner
3
+ def command
4
+ command = "RAILS_ENV=production #{super}"
5
+ if require_db?
6
+ command = "DATABASE_URL=#{database_url} #{command}"
7
+ end
8
+ command
9
+ end
10
+
11
+ def database_url
12
+ return @db_url if @db_url
13
+ raw_config = RubybenchRunner::Configurations.new
14
+ config = OpenStruct.new(raw_config[opts.db.to_sym])
15
+ url = "#{opts.db}://#{config.user}"
16
+ url += ":#{config.password}" if config.password
17
+ url += "@"
18
+ if config.host && config.port
19
+ url += "#{config.host}:#{config.port}"
20
+ end
21
+ url += "/#{config.dbname}"
22
+ with_prep_statement = opts.wps == true
23
+ url += "?prepared_statements=#{with_prep_statement}"
24
+ @db_url = url
25
+ end
26
+
27
+ def setup_db
28
+ return if !require_db?
29
+ log("Checking database...")
30
+ config = RubybenchRunner::Configurations.new(mysql_map: true)
31
+ if opts.db == "postgres"
32
+ require 'pg'
33
+ conn_config = config["postgres"]
34
+ rubybench_db = conn_config[:dbname]
35
+ conn_config[:dbname] = "postgres"
36
+ conn = PG.connect(conn_config)
37
+ begin
38
+ res = conn.exec("SELECT 1 FROM pg_database WHERE datname = '#{rubybench_db}'")
39
+ if !res.first
40
+ conn.exec("CREATE DATABASE #{rubybench_db}")
41
+ log("Created PostgreSQL database with the name '#{rubybench_db}'")
42
+ end
43
+ ensure
44
+ conn.close
45
+ end
46
+ elsif opts.db == "mysql2"
47
+ require 'mysql2'
48
+ conn_config = config["mysql2"]
49
+ rubybench_db = conn_config[:database]
50
+ conn_config[:database] = "mysql"
51
+ client = Mysql2::Client.new(conn_config)
52
+ begin
53
+ res = client.query("SHOW DATABASES LIKE '#{rubybench_db}'")
54
+ if !res.first
55
+ client.query("CREATE DATABASE #{rubybench_db}")
56
+ log("Created MySQL database with the name '#{rubybench_db}'")
57
+ end
58
+ ensure
59
+ client.close
60
+ end
61
+ end
62
+ end
63
+
64
+ def benchmark_name
65
+ @benchmark_name ||= "Rails"
66
+ end
67
+
68
+ def gemfile_content
69
+ @gemfile_content ||= <<~GEMFILE
70
+ source 'https://rubygems.org'
71
+
72
+ gem 'rails', path: '#{@repo_path}'
73
+
74
+ gem 'mysql2', '0.5.2'
75
+ gem 'pg', '1.1.4'
76
+ gem 'benchmark-ips', '~> 2.7.2'
77
+ gem 'redis', '~> 4.1.2'
78
+ gem 'puma', '~> 3.12.1'
79
+ GEMFILE
80
+ end
81
+
82
+ def save_dir
83
+ @save_dir ||= File.join(dest_dir, "rails")
84
+ end
85
+
86
+ def require_db?
87
+ filename = @script_url.split("/")[-1]
88
+ filename.match?(/activerecord|scaffold/)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,62 @@
1
+ require 'benchmark/ips'
2
+ require 'json'
3
+
4
+ module Benchmark
5
+ module Runner
6
+ def self.run(label=nil, version:, time:, disable_gc:, warmup:, &block)
7
+ unless block_given?
8
+ raise ArgumentError.new, "You must pass block to run"
9
+ end
10
+
11
+ GC.disable if disable_gc
12
+
13
+ ips_result = compute_ips(time, warmup, label, &block)
14
+ objects_result = compute_objects(&block)
15
+
16
+ print_output(ips_result, objects_result, label, version)
17
+ end
18
+
19
+ def self.compute_ips(time, warmup, label, &block)
20
+ report = Benchmark.ips(time, warmup, true) do |x|
21
+ x.report(label) { yield }
22
+ end
23
+
24
+ report.entries.first
25
+ end
26
+
27
+ def self.compute_objects(&block)
28
+ if block_given?
29
+ key =
30
+ if RUBY_VERSION < '2.2'
31
+ :total_allocated_object
32
+ else
33
+ :total_allocated_objects
34
+ end
35
+
36
+ before = GC.stat[key]
37
+ yield
38
+ after = GC.stat[key]
39
+ after - before
40
+ end
41
+ end
42
+
43
+ def self.print_output(ips_result, objects_result, label, version)
44
+ standard_deviation =
45
+ # https://github.com/evanphx/benchmark-ips/commit/b42c3dfbe104f32ce7db075a01858d598da87a8b
46
+ if ips_result.respond_to?(:error_percentage)
47
+ ips_result.error_percentage
48
+ else
49
+ ips_result.stddev_percentage # deprecated
50
+ end
51
+ output = {
52
+ label: label,
53
+ version: version,
54
+ iterations_per_second: ips_result.ips,
55
+ iterations_per_second_standard_deviation: standard_deviation,
56
+ total_allocated_objects_per_iteration: objects_result,
57
+ }.to_json
58
+
59
+ puts output
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,11 @@
1
+ STRING_COLUMNS_COUNT = 25
2
+
3
+ def db_adapter
4
+ ENV['DATABASE_URL'].split(":")[0]
5
+ end
6
+
7
+ def db_setup(script:)
8
+ Dir.chdir("../../support/setup") do
9
+ `DATABASE_URL=#{ENV.fetch("DATABASE_URL")} BUNDLE_GEMFILE=Gemfile ruby #{script}`
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ BUNDLE_DISABLE_SHARED_GEMS: "true"
3
+ BUNDLE_PATH: "vendor/bundle"
4
+ BUNDLE_JOBS: "4"
@@ -0,0 +1,11 @@
1
+ source "https://rubygems.org"
2
+
3
+ group :postgres do
4
+ gem "pg"
5
+ end
6
+
7
+ group :mysql do
8
+ gem "mysql2"
9
+ end
10
+
11
+ gem "activerecord"
@@ -0,0 +1,16 @@
1
+ require "bundler/setup"
2
+ require "active_record"
3
+ require_relative "../helpers"
4
+
5
+ ActiveRecord::Base.establish_connection(ENV.fetch('DATABASE_URL'))
6
+ ActiveRecord::Migration.verbose = false
7
+
8
+ ActiveRecord::Schema.define do
9
+ create_table :users, force: true do |t|
10
+ STRING_COLUMNS_COUNT.times do |i|
11
+ t.string :"column#{i}"
12
+ end
13
+
14
+ t.timestamps null: false
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ require "bundler/setup"
2
+ require "active_record"
3
+
4
+ ActiveRecord::Base.establish_connection(ENV.fetch('DATABASE_URL'))
5
+ ActiveRecord::Migration.verbose = false
6
+
7
+ ActiveRecord::Schema.define do
8
+ create_table :users, force: true do |t|
9
+ t.string :name, :email
10
+ t.timestamps null: false
11
+ end
12
+ end
@@ -0,0 +1,164 @@
1
+ require "bundler/setup"
2
+ require "active_record"
3
+
4
+ ActiveRecord::Base.establish_connection(ENV.fetch('DATABASE_URL'))
5
+
6
+ ActiveRecord::Migration.verbose = false
7
+
8
+ ActiveRecord::Schema.define do
9
+ create_table :topics, force: true do |t|
10
+ t.timestamps null: false
11
+ t.string "title"
12
+ t.datetime "bumped_at"
13
+ t.string "archetype"
14
+ t.datetime "deleted_at"
15
+ t.boolean "pinned_globally"
16
+ t.datetime "pinned_at"
17
+ t.integer "user_id", null: false
18
+ t.integer "category_id"
19
+
20
+ t.index ["deleted_at", "archetype", "category_id", "id"], name: "idx_topics_front_page", using: :btree
21
+ t.index ["user_id"], name: "idx_topics_user_id_deleted_at", using: :btree
22
+ t.index ["bumped_at"], name: "index_topics_on_bumped_at", using: :btree
23
+ t.index ["id", "deleted_at"], name: "index_topics_on_id_and_deleted_at", using: :btree
24
+ t.index ["pinned_at"], name: "index_topics_on_pinned_at", using: :btree
25
+ t.index ["pinned_globally"], name: "index_topics_on_pinned_globally", using: :btree
26
+ end
27
+
28
+ create_table :topic_users, force: true do |t|
29
+ t.timestamps null: false
30
+ t.integer "user_id", null: false
31
+ t.integer "topic_id", null: false
32
+ t.integer "notification_level"
33
+ t.datetime "cleared_pinned_at"
34
+
35
+ t.index ["topic_id", "user_id"], name: "idx_topic_users_on_topic_id_and_user_id", unique: true, using: :btree
36
+ t.index ["user_id", "topic_id"], name: "idx_topic_users_on_user_id_and_topic_id", unique: true, using: :btree
37
+ end
38
+
39
+ create_table :categories, force: true do |t|
40
+ t.timestamps null: false
41
+ t.integer "topic_id"
42
+ end
43
+
44
+ create_table :category_users, force: true do |t|
45
+ t.timestamps null: false
46
+ t.integer "user_id", null: false
47
+ t.integer "category_id", null: false
48
+ t.integer "notification_level"
49
+
50
+ t.index ["user_id", "category_id", "notification_level"], name: "idx_category_users_on_user_cat_and_not", unique: true, using: :btree
51
+ t.index ["category_id", "user_id", "notification_level"], name: "idx_category_users_on_cat_user_and_not", unique: true, using: :btree
52
+ end
53
+
54
+ create_table :users, force: true do |t|
55
+ t.timestamps null: false
56
+ t.string "username"
57
+
58
+ t.index ["username"], name: "index_users_on_username", unique: true, using: :btree
59
+ end
60
+ end
61
+
62
+ class User < ActiveRecord::Base
63
+ has_many :topic_users
64
+ has_many :category_users
65
+ has_many :topics
66
+ end
67
+
68
+ class Topic < ActiveRecord::Base
69
+ has_many :topic_users
70
+ has_many :categories
71
+ belongs_to :user
72
+ belongs_to :category
73
+ scope :listable_topics, -> { where('topics.archetype <> ?', 'private_message') }
74
+ end
75
+
76
+ class TopicUser < ActiveRecord::Base
77
+ belongs_to :topic
78
+ belongs_to :user
79
+ end
80
+
81
+ class Category < ActiveRecord::Base
82
+ has_many :category_users
83
+ has_many :topics
84
+ belongs_to :topic
85
+ end
86
+
87
+ class CategoryUser < ActiveRecord::Base
88
+ belongs_to :category
89
+ belongs_to :user
90
+ end
91
+
92
+ # Helpers
93
+
94
+ def archetype(i)
95
+ if i % 4 == 0
96
+ "not_private_message"
97
+ else
98
+ "private_message"
99
+ end
100
+ end
101
+
102
+ def bumped_at(i, user_id)
103
+ Time.at(50000 + i + user_id)
104
+ end
105
+
106
+ def deleted_at(i, user_id)
107
+ if i % 3 == 0
108
+ Time.at(100000 + i + user_id)
109
+ end
110
+ end
111
+
112
+ def pinned_globally(i)
113
+ i % 2 == 0
114
+ end
115
+
116
+ def pinned_at(i, user_id)
117
+ if i % 2 == 0
118
+ Time.at(1000 + i + user_id)
119
+ end
120
+ end
121
+
122
+ def notification_level(i)
123
+ i % 2 == 0 ? 1 : 0
124
+ end
125
+
126
+ def cleared_pinned_at(topic)
127
+ if topic.pinned_at
128
+ topic.pinned_at + 5
129
+ end
130
+ end
131
+
132
+ # Stage DB
133
+
134
+ 10.times do |i|
135
+ User.create!(username: "user#{i}")
136
+ end
137
+
138
+ User.all.each do |user|
139
+ 500.times do |i|
140
+ user.topics.create!(
141
+ title: "#{user.username} topic #{i}",
142
+ pinned_globally: pinned_globally(i),
143
+ bumped_at: bumped_at(i, user.id),
144
+ archetype: archetype(i),
145
+ deleted_at: deleted_at(i, user.id),
146
+ pinned_at: pinned_at(i, user.id)
147
+ )
148
+ end
149
+ end
150
+
151
+ 200.times do |i|
152
+ Category.create!(topic: Topic.limit(1).offset(i).first)
153
+ end
154
+
155
+ Topic.last(100).each_with_index do |topic, i|
156
+ topic.category = Category.offset(i).limit(1).first
157
+ topic.save!
158
+ end
159
+
160
+ User.all.each do |user|
161
+ Topic.where.not(user: user).each_with_index do |topic, i|
162
+ TopicUser.create!(user: user, topic: topic, cleared_pinned_at: cleared_pinned_at(topic), notification_level: notification_level(i))
163
+ end
164
+ end
@@ -0,0 +1,37 @@
1
+ require "bundler/setup"
2
+ require "active_record"
3
+
4
+ ActiveRecord::Base.establish_connection(ENV.fetch('DATABASE_URL'))
5
+ ActiveRecord::Migration.verbose = false
6
+
7
+ ActiveRecord::Schema.define do
8
+ create_table :users, force: true do |t|
9
+ t.string :name
10
+ t.string :email
11
+ t.boolean :approved
12
+ t.integer :age
13
+ t.datetime :birthday
14
+ t.timestamps null: false
15
+ end
16
+ end
17
+
18
+ class User < ActiveRecord::Base; end
19
+
20
+ attributes = {
21
+ name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
22
+ email: "foobar@email.com",
23
+ approved: false,
24
+ age: 51,
25
+ birthday: DateTime.now
26
+ }
27
+
28
+ 1000.times do
29
+ User.create!(attributes)
30
+ end
31
+
32
+ User.create!(
33
+ name: 'kir',
34
+ email: 'shatrov@me.com',
35
+ approved: true,
36
+ birthday: DateTime.now
37
+ )