On Sat, 02 Sep 2006 23:45:17 +0200, Eric Hodel <drbrain / segment7.net>  
wrote:

> On Sep 2, 2006, at 10:42 AM, Dominik Bathon wrote:
>> On Sat, 02 Sep 2006 05:26:04 +0200, Eric Hodel <drbrain / segment7.net>  
>> wrote:
>>> I wrote an article on using RubyInline for optimization where I take  
>>> png.rb, sprinkle in a little profiling and a little C and make it go  
>>> over 100 times faster.
>>
>> Nice article, but in this case it is possible to get almost the same  
>> speedup in pure Ruby:
>>
>> $ time ruby -Ilib profile.rb
>>
>> real    0m15.504s
>> user    0m15.119s
>> sys     0m0.309s
>>
>>
>> Avoiding flatten (and using a literal for the signature):
>>
>>   def to_blob
>>     blob = []
>>     blob << "\211PNG\r\n\032\n" # PNG signature
>>     blob << PNG.chunk('IHDR',
>>                       [ @height, @width, @bits, 6, 0, 0, 0 ].pack 
>> ("N2C5"))
>>     # 0 == filter type code "none"
>>     data = @data.map { |row| "\0" < row.map { |p| p.values.pack("C*")  
>> }.join }
>>     blob << PNG.chunk('IDAT', Zlib::Deflate.deflate(data.join, 9))
>>     blob << PNG.chunk('IEND', '')
>>     blob.join
>>   end
>
> This change gives a broken PNG.  You meant to call #<<, not #<.

Oops, of course I meant #<<. I actually had tested that my changes still  
produce correct results when I did the optimizations originally. Then I  
recreated them to get the times for each step and made that typo, oh well.

Just for reference, the time for the final version with #< changed to #<<  
on my machine:

$ time ruby -Ilib profile.rb

real    0m1.901s
user    0m1.841s
sys     0m0.032s

> I see no significant speedup when using #<<.
>
>> [values array for string changes]
>
> These are good.
>
>> Improving PNG::Canvas#initialize:
>>
>> Use
>>
>>     @data = Array.new(@width) { |x| Array.new(@height, background) }
>>
>> instead of
>>
>>     @data = Array.new(@width) { |x| Array.new(@height) { background } }
>>
>> $ time ruby -Ilib profile.rb
>>
>> real    0m1.941s
>> user    0m1.914s
>> sys     0m0.014s
>
> Not really worth optimizing, since the improvement is so small.  In the  
> optimized RubyInline version only 20% of the time is spent here with no  
> image generation.  Adding image generation makes this optimization  
> insignificant.

Yes, it's not much for the total runtime, but it makes this one line about  
14 times faster:

$ time ruby -e "40.times { Array.new(400) { Array.new(400) { 0 } } }"

real    0m2.430s
user    0m2.402s
sys     0m0.017s

$ time ruby -e "40.times { Array.new(400) { Array.new(400, 0) } }"

real    0m0.165s
user    0m0.147s
sys     0m0.016s

> Using your changes from the pure-ruby version I went from about 30  
> seconds to about 4 seconds, or 7.5 times faster.