Last active
October 15, 2020 06:37
-
-
Save shioyama/07d0d92fd3ab58385010b12af4ac734c to your computer and use it in GitHub Desktop.
Remove pry, don't need it
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# frozen_string_literal: true | |
# | |
# This script demonstrates a performance regression introduced in https://github.com/rails/rails/pull/34405 | |
# That PR patched ActiveSupport::SafeBuffer methods gsub, gsub!, sub and sub! to set backreferences, but | |
# in doing so incurred a significant penalty. | |
# | |
# This script creates a random string with texts at random locations which are swapped with gsub. The string | |
# is random but seeded the same each run, so the same length produces the same string. | |
# | |
# Run without the -a option to test performance with Ruby's String class. | |
# Run with -a and an activesupport version to test performance with any version of ActiveSupport | |
# | |
# e.g. | |
# | |
# ruby gsub_benchmark.rb -i 10000 | |
# ruby gsub_benchmark.rb -i 10000 -a 6.0.3.2 | |
# ruby gsub_benchmark.rb -i 10000 -a 5.2 | |
require 'optparse' | |
NUM_ITERATIONS = 10_000 | |
LENGTH=100_000 | |
NUM_MATCHES = 100 | |
options = { | |
iterations: NUM_ITERATIONS, | |
length: LENGTH, | |
matches: NUM_MATCHES, | |
active_support_version: nil | |
} | |
parser = OptionParser.new do |opts| | |
opts.banner = "USAGE: measure_swaptime [options]" | |
opts.on("-i", "--iterations [NUM]", Integer, "Number of iterations (Default: #{NUM_ITERATIONS})") do |v| | |
options[:iterations] = v | |
end | |
opts.on("-l", "--length [LENGTH]", Integer, "Length of string (Default: #{LENGTH})") do |v| | |
options[:length] = v | |
end | |
opts.on("-m", "--matches [NUM]", Integer, "Number of matches in string (Default: #{NUM_MATCHES})") do |v| | |
options[:matches] = v | |
end | |
opts.on("-a", "--active-support [VERSION]", String, "Set ActiveSupport version (Default: ActiveSupport is *not* required)") do |v| | |
options[:active_support_version] = v | |
end | |
end | |
parser.parse! | |
require 'bundler/inline' | |
gemfile do | |
source "https://rubygems.org" | |
gem 'activesupport', options[:active_support_version], require: 'active_support' if options[:active_support_version] | |
end | |
str_class = options[:active_support_version] ? ActiveSupport::SafeBuffer : String | |
str = str_class.new | |
puts "String Class: #{str_class.name}" | |
if options[:active_support_version] | |
puts "ActiveSupport version: #{options[:active_support_version]}." | |
else | |
puts "ActiveSupport is not loaded." | |
end | |
srand(0) # set seed to ensure we always get the same string | |
while str.length < options[:length] | |
str << rand(36**1024).to_s(36) + "\n" | |
end | |
matcher = /foo/ | |
source = 'foo' | |
target = 'bar' | |
options[:matches].times do | |
str.insert(rand(str.length), source) | |
end | |
require 'benchmark' | |
GC.start | |
durations = [] | |
options[:iterations].times do |i| | |
duped = str.dup | |
# ensure GC plays no role by force-triggering it every 100 iterations | |
GC.start if i % 100 == 0 | |
result = Benchmark.measure do | |
duped = duped.gsub(matcher) do | |
target | |
end | |
raise(Exception, "No swaps performed") if !(duped =~ /#{target}/) | |
end | |
durations << result.utime | |
end | |
puts "Max: #{durations.max*1000} ms" | |
puts "Min: #{durations.min*1000} ms" | |
puts "Average: #{durations.sum / durations.size * 1000} ms" | |
puts "Median: #{durations.sort[durations.length / 2] * 1000} ms" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment