From 42827362b6acb200f6b8826117568fcd1770b339 Mon Sep 17 00:00:00 2001 From: Matchu Date: Fri, 27 Jul 2012 23:07:20 -0400 Subject: [PATCH] optimize outfit image generation - 4x speed boost on my box Use the ImageMagick flatten command to generate the output all at once instead of compositing each layer individually, and download the layers in parallel. On my box, saving roopal27 five times took a total of 30 seconds before, whereas now it takes 7 seconds. I expect it to be even better on the production box, where latency is even lower. --- Gemfile | 2 ++ Gemfile.lock | 2 ++ app/models/outfit.rb | 39 +++++++++++++++++-------------- vendor/cache/parallel-0.5.17.gem | Bin 0 -> 11264 bytes 4 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 vendor/cache/parallel-0.5.17.gem diff --git a/Gemfile b/Gemfile index c4bc807f..fbc7a931 100644 --- a/Gemfile +++ b/Gemfile @@ -46,6 +46,8 @@ gem "mini_magick", "~> 3.4" gem "fog", "~> 1.1.2" gem "carrierwave", "~> 0.5.8" +gem "parallel", "~> 0.5.17" + group :development_async do # async wrappers gem 'eventmachine', :git => 'git://github.com/eventmachine/eventmachine.git' diff --git a/Gemfile.lock b/Gemfile.lock index 5f8ee08b..8aaf89fd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -149,6 +149,7 @@ GEM open4 (1.3.0) openneo-auth-signatory (0.1.0) ruby-hmac + parallel (0.5.17) polyglot (0.3.3) rack (1.2.5) rack-fiber_pool (0.9.2) @@ -256,6 +257,7 @@ DEPENDENCIES newrelic_rpm nokogiri (~> 1.5.2) openneo-auth-signatory (~> 0.1.0) + parallel (~> 0.5.17) rack-fiber_pool rails (= 3.0.5) rdiscount (~> 1.6.5) diff --git a/app/models/outfit.rb b/app/models/outfit.rb index f2930254..f26a034d 100644 --- a/app/models/outfit.rb +++ b/app/models/outfit.rb @@ -138,25 +138,28 @@ class Outfit < ActiveRecord::Base # file. def create_image!(output) unless image_layers.empty? - base_layer = image_layers.first - above_layers = image_layers[1..-1] - write_temp_swf_asset_image!(base_layer, output) - output.close - - unless above_layers.empty? - Tempfile.open(['outfit_overlay', '.png']) do |overlay| - above_layers.each do |layer| - overlay.open - write_temp_swf_asset_image! layer, overlay - overlay.close - - previous_image = MiniMagick::Image.open(output.path) - overlay_image = MiniMagick::Image.open(overlay.path) - output_image = previous_image.composite(overlay_image) - output_image.write output.path - end - end + temp_image_files = Parallel.map(image_layers, :in_threads => 8) do |swf_asset| + image_file = Tempfile.open(['outfit_layer', '.png']) + write_temp_swf_asset_image!(swf_asset, image_file) + image_file.close + image_file end + + # Here we do some awkwardness to get the exact ImageMagick command we + # want, though it's still less awkward than handling the command + # ourselves. Give all of the temporary images as input, flatten them and + # write them to the output path. + command = MiniMagick::CommandBuilder.new('convert') + temp_image_files.each { |image_file| command.push image_file.path } + command.layers 'flatten' + command.push output.path + + # Though the above command really is sufficient, we still need a dummy + # image to handle execution. + output_image = MiniMagick::Image.new(output.path) + output_image.run(command) + + temp_image_files.each(&:unlink) else output.close end diff --git a/vendor/cache/parallel-0.5.17.gem b/vendor/cache/parallel-0.5.17.gem new file mode 100644 index 0000000000000000000000000000000000000000..6b2fec49535951547ea66f459a7ef2b4034584cf GIT binary patch literal 11264 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 literal 0 HcmV?d00001