# today there was a bit of discussion on using RMagick vs shelling out to
# convert to make thumbnails in the excellent paperclip plugin on github
#
# http://github.com/thoughtbot/paperclip/issues/closed/#issue/90
#
# oddly no one bothered to actually test the assertion that using the api
# should be faster or require less resources.  this test does not test forking
# on a heavily loaded system but given that rmagick itself uses multiple
# threads to do processing (the image magick library actually - and these are
# native threads) i don't think it's relevant.
#
# the *important* thing to get about the below is just how easy it would be
# for paperclip to continue using the shell commands and easily make all the
# scaling parallel for a super easy speed boost.  note that this is not true
# of using the api - it can only leverage a single ruby green thread so the
# naive attempt at making it parallel fails - the only way to make it parallel
# is, in fact, to create processes anyhow.
#
# my general rules for 'making shit faster' in ruby are
#   - use processes
#   - use many of them by forking
# or
#   - use many of them by threading system calls
#
# the later (threading sys calls) works on all platforms including windoze to
# give easy parallel process management and speedup.
#

require 'benchmark'

require 'rubygems'
require 'RMagick'
gem 'threadify', '>= 1.3.0'
require 'threadify'

path = ARGV.shift or abort('no path')
n = Integer(ARGV.shift || 4)

scale_api = lambda do
  img = Magick::Image.read(path).first
  thumb = img.scale(0.25)
  thumb.write("thumb.gif")
end

cmd = "convert -scale 25%x25% #{ path.inspect } thumb.gif"

scale_shl = lambda do
  system(cmd) or abort("cmd:#{ cmd } failed with #{ $?.inspect }")
end

Benchmark.bm do |bm|
  bm.report('api'){ n.times{ scale_api.call } }
  bm.report('shl'){ n.times{ scale_shl.call } }

  bm.report('threaded api'){ Threadify(n){ scale_api.call } }
  bm.report('threaded shl'){ Threadify(n){ scale_shl.call } }
end


__END__

output from two sample runs - the first is on a small image and the second a
large one


cfp:~ > identify Pictures/arnold.jpg
Pictures/arnold.jpg JPEG 300x411 300x411+0+0 8-bit DirectClass 37.0117kb

cfp:~ > ruby a.rb Pictures/arnold.jpg 16
      user     system      total        real
api  4.850000   0.060000   4.910000 (  5.022925)
shl  0.000000   0.020000   5.230000 (  5.477109)
threaded api  4.860000   0.070000   4.930000 (  5.103877)
threaded shl  0.020000   0.040000   5.380000 (  2.981845)



cfp:~ > identify Pictures/A-is-for-axel.tif
Pictures/A-is-for-axel.tif TIFF 1623x2100 1623x2100+0+0 8-bit DirectClass 9.7514mb

cfp:~ > ruby a.rb Pictures/A-is-for-axel.tif 4
      user     system      total        real
api 36.850000   1.260000  38.110000 ( 39.744877)
shl  0.000000   0.000000  37.820000 ( 38.856584)
threaded api 36.640000   1.210000  37.850000 ( 38.913540)
threaded shl  0.070000   0.050000  53.730000 ( 30.936035)