Skip to content

Instantly share code, notes, and snippets.

@inkel
Last active August 29, 2015 14:17
Show Gist options
  • Save inkel/51c27ade94a9f83d387c to your computer and use it in GitHub Desktop.
Save inkel/51c27ade94a9f83d387c to your computer and use it in GitHub Desktop.
Elasticsearch::API::Utils#__pathify is slow and probably overly complex. This gist shows the result of my attempts at improving it's performance.
$ PROTEST_REPORT=progress RUBYOPT=-rpry tmp/benchmark.rb
Calculating -------------------------------------
original 11.231k i/100ms
__pathify 14.706k i/100ms
__pathify2 21.360k i/100ms
-------------------------------------------------
original 124.124k (±13.1%) i/s - 617.705k
__pathify 154.361k (±18.9%) i/s - 735.300k
__pathify2 209.829k (± 9.5%) i/s - 1.047M
Comparison:
__pathify2: 209829.4 i/s
__pathify: 154360.9 i/s - 1.36x slower
original: 124123.8 i/s - 1.69x slower
..
2 tests, 221572 assertions (2 passed, 0 pending, 0 failed, 0 errored)
Ran in 6.345552 seconds
# This file contains several JSON lines with the following structure:
#
# [segments,expected]
#
# segments: an array of `*segments` parameter for __pathify
# expected: the result of running the original __pathify method
# for those segments.
#
# My current file has 110,786 lines, constructed by running my app's
# complete test suite and saving those values with the above format.
#! /usr/bin/env ruby
require "benchmark/ips"
require "elasticsearch"
require "oj"
def original(*segments)
Array(segments).flatten.
compact.
reject { |s| s.to_s =~ /^\s*$/ }.
join('/').
squeeze('/')
end
def __pathify(*segments)
segments.
reject { |s| s.to_s =~ /^\s*$/ }.
join("/").
squeeze("/")
end
def __pathify2(*segments)
segments.inject("") do |m, s|
next m if s.empty?
m << "/" << (s[0] == "/" ? s[1..-1] : s)
end[1..-1]
end
Benchmark.ips do |r|
r.report("original") { p = original("v1-datapoints-201501", "_mapping", "datapoint") }
r.report("__pathify") { p = __pathify("v1-datapoints-201501", "_mapping", "datapoint") }
r.report("__pathify2") { p = __pathify2("v1-datapoints-201501", "_mapping", "datapoint") }
r.compare!
end
require "protest"
Protest.describe "__pathify" do
LINES = open("tmp/__pathify.log").readlines.map(&:chomp!)
test "__pathify: produces same results" do
LINES.each do |line|
line.chomp!
segments, expected = Oj.load(line, mode: :compat)
actual = __pathify(*segments)
assert_equal expected, actual, "expected: #{expected}; actual: #{actual}; segments: #{segments.inspect}"
end
end
test "__pathify2: produces same results" do
LINES.each do |line|
line.chomp!
segments, expected = Oj.load(line, mode: :compat)
actual = __pathify2(*segments)
assert_equal expected, actual, "expected: #{expected}; actual: #{actual}; segments: #{segments.inspect}"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment