.
Bitland.Net Security Notes            Comments? email jwilkins-at-bitland*net
More information on the author at Jonathan Wilkins's home page
RSS feed available at http://www.bitland.net/index.rss               Add to Google
Archives: 2007, 2006, 2005, 2004, 2003, 2002, 2001, 2000


Loop speed comparison  |  (2008/11/25 15:20)

I was optimizing some code recently and noticed that there was a huge difference in speed with certain types of loop. I'm running 1.8.6 on OS X.
ruby --version : ruby 1.8.6 (2008-03-03 patchlevel 114) [i686-darwin]
I was indexing into a string and using a counter variable with a while loop and it was absurdly slow. So I wrote a quick test program and ran it through ruby-prof and the while x < 99999999 style loop is 6 times slower than the alternatives.
require 'rubygems'
require 'ruby-prof'

$count = 99_999_999

def time_it(code, filename)
  RubyProf.start
  code.call
  prof_data = RubyProf.stop
  printer = RubyProf::FlatPrinter.new(prof_data)
  printer.print(open(filename, 'w+'), 0)
end

times = Proc.new { $count.times { |x| a = x } } 
time_it(times, 'loops-times.txt')

#Thread ID: 131970
#Total: 240.905949
#
# %self     total     self     wait    child    calls  name
#100.00    240.91   240.91     0.00     0.00        1  Integer#times (ruby_runtime:0}
#  0.00    240.91     0.00     0.00   240.91        1  Object#time_it (perf-loops.rb:8}
#  0.00    240.91     0.00     0.00   240.91        1  Proc#call (ruby_runtime:0}

#------------------------------------------------------------------------------

range_each = Proc.new { (0..$count).each { |x| a = x } }
time_it(range_each, 'loops-range_each.txt')

#Thread ID: 131970
#Total: 247.886152
#
# %self     total     self     wait    child    calls  name
#100.00    247.89   247.89     0.00     0.00        1  Range#each (ruby_runtime:0}
#  0.00    247.89     0.00     0.00   247.89        1  Object#time_it (perf-loops.rb:8}
#  0.00    247.89     0.00     0.00   247.89        1  Proc#call (ruby_runtime:0}
#  0.00      0.00     0.00     0.00     0.00        1  #allocate (ruby_runtime:0}

#------------------------------------------------------------------------------
upto = Proc.new { 0.upto($count) { |x| a = x } }
time_it(upto, 'loops-upto.txt')

#Thread ID: 131970
#Total: 245.206868
#
# %self     total     self     wait    child    calls  name
#100.00    245.21   245.21     0.00     0.00        1  Integer#upto (ruby_runtime:0}
#  0.00    245.21     0.00     0.00   245.21        1  Object#time_it (perf-loops.rb:8}
#  0.00    245.21     0.00     0.00   245.21        1  Proc#call (ruby_runtime:0}

#------------------------------------------------------------------------------
$i = 0
while_plus_equals = Proc.new { while $i < $count do a = $i; $i += 1; end }
time_it(while_plus_equals, 'loops-while_plus_equals.txt')

#Thread ID: 131970
#Total: 1270.530267
#
# %self     total     self     wait    child    calls  name
# 66.86   1270.53   849.47     0.00   421.06        1  Proc#call (ruby_runtime:0}
# 16.68    211.95   211.95     0.00     0.00 99999999  Fixnum#+ (ruby_runtime:0}
# 16.46    209.11   209.11     0.00     0.00 100000000  Fixnum#< (ruby_runtime:0}
#  0.00   1270.53     0.00     0.00  1270.53        1  Object#time_it (perf-loops.rb:8}


+digg  |  +del.icio.us   |    [Ruby ]   |   Permanent link

Capistrano 2 can handle different usernames on different hosts  |  (2008/05/12 22:16)

Sometimes you'll want to deploy to different servers with different usernames. I googled around and didn't find a clean solution, though Matthew Deiters had a reasonable monkey patch. I'm not sure if this is a recent addition to the underlying Net::SSH library but I checked to see if the standard ssh configuration file was obeyed and it turns out that it is. All you have to do is add an entry like the following to your ~/.ssh/config file.
Host your.host.name
  HostName your.host.name
  User username


+digg  |  +del.icio.us   |    [Ruby ]   |   Permanent link

Quick Proxy, or Why I Love Ruby pt 9215  |  (2008/02/02 12:00)

# Quick basic proxy, just strips accept-encoding header and dumps
# to files in the local directory using the WebScarab naming convention
# (0-request, 0-response ...)
require 'net/http'
require 'webrick/httpproxy'

s = WEBrick::HTTPProxyServer.new(
  :Port => 9999, 
  :RequestCallback => Proc.new{|req,res| 
    $count ||= 0
    req.header.delete('accept-encoding')
    open("#{$count}-request", "wb+") { |f|
      f << "#{req.request_line}#{req.raw_header}\r\n#{req.body}"
    }
  },
  :ProxyContentHandler => Proc.new{|req,res|
    open("#{$count}-response", "wb+") { |f|
      f << res.status_line
      res.header.keys.each { |k|
        f << "#{k.capitalize}: #{res.header[k]}\r\n"
      }
      f << "\r\n#{res.body}"
    }
    $count += 1
  }
);
trap("INT"){
  s.shutdown
}
s.start


+digg  |  +del.icio.us   |    [Ruby ]   |   Permanent link

Ruby's equivalent of Python's setattr  |  (2007/09/17 17:52)

I am still really new to Ruby but I'm jumping in with both feet. As a result I figured out metaprogramming before I knew what the ! operator did. Anyway, I was trying to find out the equivalent of Python's setattr when I came across Hal Fulton's 'An Exercise in Metaprogramming with Ruby'. That and some hints from a ruby-talk thread on attr_accessor allowed me to translate this Python code I'd written for dealing with MySpace profiles from:
print "Getting Profile Nodes.."
for p in ['ProfileMusic', 'ProfileGeneral', 'ProfileBooks', 'ProfileHeroes']:
  try:
    v = self.soup.first('td',id=p).string
    setattr(self, p, v)
  except:
    setattr(self, p, None)
Into this Ruby:
(page/"td").each do |t|
  tid = t.attributes['id']
  if /Profile([.]*)/ =~ tid
    pname = tid[7..-1].downcase
    pname = pname.gsub(/[ \/]/, "_").gsub(/[^\w]/, "").squeeze('_')
    instance_variable_set("@"+pname, t.inner_html)
    eval("class << self; attr_accessor :#{pname}; end")
  end
end
The Ruby uses Hpricot instead of BeautifulSoup, but is more generalized and OOish. I'm a little uncomfortable with the security of the eval, but the technique is useful and I couldn't google a better solution. If you have something better, let me know.

+digg  |  +del.icio.us   |    [Ruby ]   |   Permanent link

RSS feed available at http://www.bitland.net/index.rss