On 26 Jun 2008, at 22:51, Philip R. wrote:
Eleanor McHugh wrote:
When I did the profile, the array processing was the biggest hit -
when I got rid of the array, I almost halved the time! Ruby arrays
are pretty cool but I think you pay for the convenience . .
Iām surprised at the behaviour youāre seeing so I ran a quick
benchmark on what I believe to be an equivalent array handling problem
with my laptop (OS X, Ruby 1.8.6-p111, Core 2 Duo 2GHz, 2GB RAM):
require ābenchmarkā
include Benchmark
bm(6) do |y|
y.report(āappendingā) { x = []; (1ā¦20000000).each { |i| x << i } }
y.report(ānested creationā) { x = Array.new(1000)
{ Array.new(1000) { Array.new(20, 0) } } }
y.report(āunrollingā) { x.flatten.flatten.length }
end
user system total real
appending 7.350000 0.100000 7.450000 ( 7.685458)
nested creation 0.850000 0.000000 0.850000 ( 0.851341)
unrolling 15.240000 0.280000 15.520000 ( 20.927189)
which in each case is manipulating an array of 20,000,000 elements.
This would be equivalent to processing 32000 files where each
contained 625 occurrences of the āk=ā tag.
See my other note but it didnāt make much difference.
Regardless of what the profiler says, any program thatās opening 32000
files and writing to them is a prime candidate for IO optimisationā¦
Assuming I want to write 625 single-digit numbers to 32000 files the
difference with file.puts *stats compared to individual writes is
noticeable on my setup and would more than outweigh the cost of
appending these numbers to an array. A slower processor might behave
differently, as might a system with a higher-performance drive than my
laptopās 5400RPM SATA HDD.
x = Array.new(675, 1)
bm(6) do |y|
y.report(ādirectā) { 32000.times { File.open(ātest.datā, āaā) { |
file| file.puts *x } } }
y.report(āenumeratedā) { 32000.times { File.open(ātest.datā, āaā)
{ |file| x.each { |i| file.puts i } } } }
y.report(ādirect+fsyncā) { 32000.times { File.open(ātest.datā, āaā)
{ |file| file.sync = false; file.puts *x; file.fsync } } }
y.report(āenum+fsyncā) { 32000.times { File.open(ātest.datā, āaā)
{ |file| file.sync = false; x.each { |i| file.puts i }; file.fsync } } }
end
user system total real
direct 25.160000 2.100000 27.260000 ( 38.775792)
enumerated 34.200000 2.170000 36.370000 ( 55.614969)
direct+fsync 25.300000 2.250000 27.550000 ( 60.225069)
enum+fsync 34.520000 2.420000 36.940000 ( 98.627757)
Iād be interested in equivalent benchmarking figures for your
configuration and also an estimate of how close to the actual case
this 32000x625 assumption is to your actual use case as it would help
me make sense of the doubled execution time youāre seeing with my
array modification.
The cubic array was just a direct translation of the C pointer
setup I had - basically it is a rectangular grid of sub-populations
each with an array of allele lengths.
One option is to use a Hash as a Sparse Matrix by using Arrays as keys
for indexing:
stats = Hash.new(0)
lines.each |line|
ā¦
v = stats06
stats[[x,y]] = v if v != 0
ā¦
end
File.open(output_filename, āaā) do |file|
file.puts *stats.values
end
which should pay off if the number of interesting results is much less
than the cubic search space. Obviously if you need the values to keep
a specific ordering youād need additional logicā¦
Ellie
raise ArgumentError unless @reality.responds_to? :reason