-
-
Save Envek/d0763db337d34ef78bf8d0a1aceca9aa to your computer and use it in GitHub Desktop.
Benchmark various variants of parsing durations in Rails' ActiveSupport
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
require 'benchmark/ips' | |
require 'active_support/duration' | |
EPOCH = ::Time.utc(2000) | |
PARTS_IN_SECONDS = { | |
seconds: 1, # Used in parse method for ease of handling part hashes with seconds | |
minutes: 60, | |
hours: 60 * 60, | |
days: 24 * 60 * 60, | |
weeks: 7 * 24 * 60 * 60, | |
months: 30 * 24 * 60 * 60, | |
years: 365.25 * 24 * 60 * 60, | |
}.freeze | |
def parse_initial(iso8601duration) | |
parts = ActiveSupport::Duration::ISO8601Parser.new(iso8601duration).parse! | |
time = ::Time.current | |
ActiveSupport::Duration.new(time.advance(parts) - time, parts) | |
end | |
def parse_epoch(iso8601duration) | |
parts = ActiveSupport::Duration::ISO8601Parser.new(iso8601duration).parse! | |
ActiveSupport::Duration.new(EPOCH.advance(parts) - EPOCH, parts) | |
end | |
def parse_inject_parts(iso8601duration) | |
parts = ActiveSupport::Duration::ISO8601Parser.new(iso8601duration).parse! | |
total_seconds = parts.inject(0) do |total, (part, value)| | |
total + value * PARTS_IN_SECONDS[part] | |
end | |
ActiveSupport::Duration.new(total_seconds, parts) | |
end | |
def year_initial | |
ActiveSupport::Duration.new(1 * 365.25.days.to_i, [[:years, 1]]) | |
end | |
def year_with_parts | |
ActiveSupport::Duration.new(1 * ActiveSupport::Duration::PARTS_IN_SECONDS[:years].to_i, [[:years, 1]]) | |
end | |
ISO8601_SAMPLE = 'P1Y1M1DT1H1M1.0S' | |
Benchmark.ips do |x| | |
x.report("Initial parse with TimeWithZone#advance") { parse_initial(ISO8601_SAMPLE) } | |
x.report("Parse with Time#advance from fixed EPOCH") { parse_epoch(ISO8601_SAMPLE) } | |
x.report("Parse using sum of mapping parts to seconds") { parse_inject_parts(ISO8601_SAMPLE) } | |
x.compare! | |
end | |
Benchmark.ips do |x| | |
x.report("Initial 1.year with many intermediate durations") { year_initial } | |
x.report("1.year2 with mapping duration to seconds") { year_with_parts } | |
x.compare! | |
end |
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
Warming up -------------------------------------- | |
Initial parse with TimeWithZone#advance | |
1.050k i/100ms | |
Parse with Time#advance from fixed EPOCH | |
1.683k i/100ms | |
Parse using sum of mapping parts to seconds | |
2.695k i/100ms | |
Calculating ------------------------------------- | |
Initial parse with TimeWithZone#advance | |
10.651k (± 2.8%) i/s - 53.550k in 5.031816s | |
Parse with Time#advance from fixed EPOCH | |
17.252k (± 5.2%) i/s - 87.516k in 5.088071s | |
Parse using sum of mapping parts to seconds | |
27.991k (± 2.3%) i/s - 140.140k in 5.009231s | |
Comparison: | |
Parse using sum of mapping parts to seconds: 27991.0 i/s | |
Parse with Time#advance from fixed EPOCH: 17252.5 i/s - 1.62x slower | |
Initial parse with TimeWithZone#advance: 10650.5 i/s - 2.63x slower | |
Warming up -------------------------------------- | |
Initial 1.year with many intermediate durations | |
27.250k i/100ms | |
1.year2 with mapping duration to seconds | |
44.715k i/100ms | |
Calculating ------------------------------------- | |
Initial 1.year with many intermediate durations | |
325.580k (± 4.6%) i/s - 1.635M in 5.032719s | |
1.year2 with mapping duration to seconds | |
672.955k (± 4.7%) i/s - 3.398M in 5.060281s | |
Comparison: | |
1.year2 with mapping duration to seconds: 672955.2 i/s | |
Initial 1.year with many intermediate durations: 325579.6 i/s - 2.07x slower |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment