Skip to content

Instantly share code, notes, and snippets.

@Tyralion
Forked from jordansissel/Results.md
Created December 8, 2011 07:56
Show Gist options
  • Select an option

  • Save Tyralion/1446417 to your computer and use it in GitHub Desktop.

Select an option

Save Tyralion/1446417 to your computer and use it in GitHub Desktop.
ruby ipaddr vs custom pure-ruby
class TubeAddress
IPv4MASK = 0xFFFFFFFF # 255.255.255.255
def initialize(addr)
@address, cidr, unused = addr.split("/") + ["32"]
@address_int = self.class.ip_to_num(@address)
@cidr = cidr.to_i
@base = @address_int & cidr_mask
end # def initialize
def cidr_mask
# Convert /24 to 0xffffff00, etc
@cidr_mask ||= IPv4MASK ^ ((1 << (32 - @cidr)) - 1)
end # def cidr_mas
def include?(addr)
addr_int = self.class.ip_to_num(addr)
#printf "base: %08x\n", @base
#printf "addr: %08x\n", addr_int
#printf "mask: %08x\n", cidr_mask
#printf "full: %08x\n", (addr_int & cidr_mask)
return addr_int & cidr_mask == @base
end # def include?
def self.ip_to_num(addr)
return addr.split(".").reduce(0) { |s,c| s = (s << 8) + (c.to_i) }
end # def self.ip_to_num
def to_s
return "#{@address}/#{cidr}"
end
end # class TubeAddress
def time(iterations, &block)
start= Time.now
1.upto(iterations) do
block.call
end
duration = Time.now - start
return duration
end
require "ipaddr"
tube = TubeAddress.new("192.168.0.0/16")
ipaddr = IPAddr.new("192.168.0.0/16")
iterations = 50000
tube_time = time(iterations) { tube.include?("192.168.3.4") }
ipaddr_time = time(iterations) { ipaddr.include?("192.168.3.4") }
def result(name, duration, iterations)
engine = (RUBY_ENGINE rescue "ruby")
printf("%15.15s | %5s/%7s | %8.2f | %.2f\n", name, engine, RUBY_VERSION,
duration, iterations / duration)
end
result("tubeaddr", tube_time, iterations)
result("ipaddr", ipaddr_time, iterations)

Premise

I have some code that does acl checking; compares an client ip address against a list of addresses (or subnets) that permit or reject. This largely involves iterating across a set of IPAddr objects asking addr.include?(client_addr). Performance is terrible when I include this acl checking.

Why? IPAddr is really slow, so I implemented what I needed as "TubeAddress" and compared the speeds.

Data

 implementation |  platform     | duration | rate
         ipaddr |   rbx/  1.8.7 |    18.96 | 2637.29
         ipaddr |  ruby/  1.8.7 |     3.54 | 14120.15
         ipaddr | jruby/  1.9.2 |     2.76 | 18122.51
         ipaddr | jruby/  1.8.7 |     2.46 | 20316.94
         ipaddr |  ruby/  1.9.2 |     2.22 | 22474.13
       tubeaddr | jruby/  1.9.2 |     1.54 | 32383.42
       tubeaddr |   rbx/  1.8.7 |     1.53 | 32778.22
       tubeaddr | jruby/  1.8.7 |     1.52 | 32981.53
       tubeaddr |  ruby/  1.8.7 |     0.89 | 56136.06
       tubeaddr |  ruby/  1.9.2 |     0.42 | 117957.64

Conclusions

ipaddr is another really slow ruby core/stdlib tool. In call tests, my version beats the stdlib ipaddr by a wide margin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment