Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Struct is slow

Reply
Thread Tools

Struct is slow

 
 
Wayne Magor
Guest
Posts: n/a
 
      10-16-2007
I have a script in which I was using a 2-element array where a struct
would be used in another language, so I decided to give the Ruby class
Struct a try.

My script went from taking 2 seconds to taking 27 seconds from this
simple change! The use of this 2-element array is only one small part
of the script so it was very surprising to me that it could even cause
the script to take twice as long no matter how inefficient it might be.
To take more than 10 times longer for the entire script to execute was a
shocker.

I will probably shy away from the use of the Struct class after this
brief experience and use arrays with constants for the indexes. I'm
wondering if this is an erroneous conclusion and perhaps I am missing
something.

What are the advantages/disadvantages of using the Struct class in Ruby?
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
Robert Dober
Guest
Posts: n/a
 
      10-16-2007
On 10/16/07, Wayne Magor <(E-Mail Removed)> wrote:
> I have a script in which I was using a 2-element array where a struct
> would be used in another language, so I decided to give the Ruby class
> Struct a try.
>
> My script went from taking 2 seconds to taking 27 seconds from this
> simple change! The use of this 2-element array is only one small part
> of the script so it was very surprising to me that it could even cause
> the script to take twice as long no matter how inefficient it might be.
> To take more than 10 times longer for the entire script to execute was a
> shocker.

Hmm some code to look at would be nice, this seems difficult to believe indeed.

Robert


--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/

 
Reply With Quote
 
 
 
 
Alex Fenton
Guest
Posts: n/a
 
      10-16-2007
Wayne Magor wrote:
> I have a script in which I was using a 2-element array where a struct
> would be used in another language, so I decided to give the Ruby class
> Struct a try.
>
> My script went from taking 2 seconds to taking 27 seconds from this
> simple change!


This doesn't sound likely, even if your script did nothing else but use
the Struct class. I'd look elsewhere for the source of slowness (try
running your script with -rprofile).

A quick benchmark suggests that Struct is somewhat slower to instantiate
(+100%), marginally slower to set values in (+33%), and the same speed
to fetch values from as an Array:

BENCHMARK:

require 'benchmark'

GC.disable
Foo = Struct.new(:foo, :bar)

repetitions = 500_000

puts 'struct-init', Benchmark::measure {
repetitions.times { f = Foo.new('x', 666) }
}

puts 'array-init', Benchmark::measure {
repetitions.times { f = ['x', 666] }
}

puts 'struct-get', Benchmark::measure {
f = Foo.new('x', 666)
repetitions.times { g = f.foo }
}

puts 'array-get', Benchmark::measure {
f = ['x', 666]
repetitions.times { g = f[0] }
}

puts 'struct-set', Benchmark::measure {
f = Foo.new('x', 666)
repetitions.times { f.foo = 'y' }
}

puts 'array-set', Benchmark::measure {
f = ['x', 666]
repetitions.times { f[0] = 'y' }
}


__END__

RESULTS (ruby 1.8.4 (2005-12-24) [i386-mswin32])

struct-init
1.359000 0.031000 1.390000 ( 1.390000)
array-init
0.563000 0.016000 0.579000 ( 0.579000)
struct-get
0.281000 0.000000 0.281000 ( 0.281000)
array-get
0.297000 0.000000 0.297000 ( 0.297000)
struct-set
0.422000 0.000000 0.422000 ( 0.422000)
array-set
0.281000 0.000000 0.281000 ( 0.281000)


alex
 
Reply With Quote
 
Wayne Magor
Guest
Posts: n/a
 
      10-16-2007
I understand your skepticism, it seems impossible, and I totally agree
it DOES seem impossible, yet that is what I am seeing.

I thought maybe I had done something wrong, so I recreated my experiment
(I had already deleted the file). I was running it from Eclipse, so I
opened a DOS window and ran it directly and got the same result.

The script is too large to post, but what it does is read C header files
and generates an array of these "structs" which have two strings: the
type and the name of a typedef. It then goes through the list making
them to be somewhat "primary" types for another script to process. Here
are some examples of the output:

float UBT_Feet_Type
uint_8 UBT_Turn_Directions_Type
struct NCBYTERD_PositionConvRecType
uint_32 NCTPLYGN_PolygonIterationsType
struct[4] NCTPLYGN_QuadralateralPolygonVerticesType
struct NCTPLYGN_QuadralateralClassType
struct[8] NCTPLYGN_QuadralateralPolygonSetType
uint_8 NCPRMYTP_DataStatusType
double NCPRMYTP_DegreesType
enum NCPRMYTP_PeriodsTypeEnum

One thing I just noticed is that the script with the Struct class
doesn't work correctly. It doesn't make the types "primary" and it
doesn't generate as many lines. Obviously, there's something I don't
understand about how to use Struct.

Here is the difference between the 2 scripts. The array

FILE COMPARISON
Produced: 10/16/2007 1:27:12 PM

Mode: Just Differences

Left file: C:\workspace\CreateSfct\h_file_types_diff.txt Right file:
C:\workspace\CreateSfct\h_file_types (before struct mod).rb
L19 $typedef_rec = Struct.new("Typedef", :typedef_type,
:typedef_name)
R19 TYPEDEF_TYPE = 0
TYPEDEF_NAME = 1
------------------------------------------------------------------------
------------------------------------------------------------------------
L74 typedef_type = type_arr[j][:typedef_type]
typedef_name = type_arr[j][:typedef_name]
R75 typedef_type = type_arr[j][TYPEDEF_TYPE]
typedef_name = type_arr[j][TYPEDEF_NAME]
------------------------------------------------------------------------
------------------------------------------------------------------------
L88 type_arr[j][:typedef_type].sub!(/\w+/, primary_t)
R89 type_arr[j][TYPEDEF_TYPE].sub!(/\w+/, primary_t)
------------------------------------------------------------------------
------------------------------------------------------------------------
L91 if type_arr[j][:typedef_type] =~ /\[([A-Z]\w*)\]/ then
type_arr[j][:typedef_type].sub!($1,define_lookup($1,define_hash))
R92 if type_arr[j][TYPEDEF_TYPE] =~ /\[([A-Z]\w*)\]/ then
type_arr[j][TYPEDEF_TYPE].sub!($1,define_lookup($1,define_hash))
------------------------------------------------------------------------
------------------------------------------------------------------------
L186 return $typedef_rec.new("enum", enum_name)
R187 return ["enum", enum_name]
------------------------------------------------------------------------
------------------------------------------------------------------------
L202 return $typedef_rec.new(typedef_type, typedef_name)
R203 return [typedef_type, typedef_name]
------------------------------------------------------------------------
------------------------------------------------------------------------
L546 type_arr.each do |x|
print(x[:typedef_type], "\t\t", x[:typedef_name], "\n")
R547 type_arr.each do |typedef_type, typedef_name|
print(typedef_type, "\t\t", typedef_name, "\n")
------------------------------------------------------------------------
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
MenTaLguY
Guest
Posts: n/a
 
      10-16-2007
If type_arr[j] is a struct, then try type_arr[j].typedef_type
rather than type_arr[j][:typedef_type], and see if that makes
a difference.

-mental



 
Reply With Quote
 
Wayne Magor
Guest
Posts: n/a
 
      10-16-2007
Mental Guy wrote:
> If type_arr[j] is a struct, then try type_arr[j].typedef_type
> rather than type_arr[j][:typedef_type], and see if that makes
> a difference.


Well, I tried it and, as expected, the syntax change made no difference.
The one with Struct's still takes 27 seconds and doesn't work correctly.
It's not clear to me why it should be different than just using a
2-element array (shrug).


--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      10-16-2007
On 16.10.2007 22:00, Wayne Magor wrote:
> Mental Guy wrote:
>> If type_arr[j] is a struct, then try type_arr[j].typedef_type
>> rather than type_arr[j][:typedef_type], and see if that makes
>> a difference.

>
> Well, I tried it and, as expected, the syntax change made no difference.
> The one with Struct's still takes 27 seconds and doesn't work correctly.
> It's not clear to me why it should be different than just using a
> 2-element array (shrug).


Did you actually also use the same block call semantics?

L546 type_arr.each do |x|
print(x[:typedef_type], "\t\t", x[:typedef_name], "\n")
R547 type_arr.each do |typedef_type, typedef_name|
print(typedef_type, "\t\t", typedef_name, "\n")

Make the latter

R547 type_arr.each do |x|
print(x.typedef_type, "\t\t", x.typedef_name, "\n")

Where x is your struct type.

robert
 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      10-17-2007
On 16.10.2007 19:05, Alex Fenton wrote:
> Wayne Magor wrote:
>> I have a script in which I was using a 2-element array where a struct
>> would be used in another language, so I decided to give the Ruby class
>> Struct a try.
>>
>> My script went from taking 2 seconds to taking 27 seconds from this
>> simple change!

>
> This doesn't sound likely, even if your script did nothing else but use
> the Struct class. I'd look elsewhere for the source of slowness (try
> running your script with -rprofile).
>
> A quick benchmark suggests that Struct is somewhat slower to instantiate
> (+100%), marginally slower to set values in (+33%), and the same speed
> to fetch values from as an Array:
>
> BENCHMARK:
>
> require 'benchmark'
>
> GC.disable
> Foo = Struct.new(:foo, :bar)
>
> repetitions = 500_000
>
> puts 'struct-init', Benchmark::measure {
> repetitions.times { f = Foo.new('x', 666) }
> }
>
> puts 'array-init', Benchmark::measure {
> repetitions.times { f = ['x', 666] }
> }
>
> puts 'struct-get', Benchmark::measure {
> f = Foo.new('x', 666)
> repetitions.times { g = f.foo }
> }
>
> puts 'array-get', Benchmark::measure {
> f = ['x', 666]
> repetitions.times { g = f[0] }
> }
>
> puts 'struct-set', Benchmark::measure {
> f = Foo.new('x', 666)
> repetitions.times { f.foo = 'y' }
> }
>
> puts 'array-set', Benchmark::measure {
> f = ['x', 666]
> repetitions.times { f[0] = 'y' }
> }
>
>
> __END__
>
> RESULTS (ruby 1.8.4 (2005-12-24) [i386-mswin32])
>
> struct-init
> 1.359000 0.031000 1.390000 ( 1.390000)
> array-init
> 0.563000 0.016000 0.579000 ( 0.579000)
> struct-get
> 0.281000 0.000000 0.281000 ( 0.281000)
> array-get
> 0.297000 0.000000 0.297000 ( 0.297000)
> struct-set
> 0.422000 0.000000 0.422000 ( 0.422000)
> array-set
> 0.281000 0.000000 0.281000 ( 0.281000)


I'm not sure whether you are familiar with Benchmark#bmbm which does a
rehearsal - personally I rather not switch off GC since in realistic
situations GC time belongs into the mix. But results are rather similar:

Robert@Babelfish2 /cygdrive/c/TEMP
$ ruby array-struct.rb
Rehearsal --------------------------------------------------
struct init 3.812000 0.000000 3.812000 ( 3.923000)
array init 1.672000 0.000000 1.672000 ( 1.709000)
struct get 0.437000 0.000000 0.437000 ( 0.440000)
array get 0.485000 0.000000 0.485000 ( 0.485000)
struct set 0.718000 0.000000 0.718000 ( 0.716000)
array set 0.500000 0.000000 0.500000 ( 0.510000)
----------------------------------------- total: 7.624000sec

user system total real
struct init 3.891000 0.000000 3.891000 ( 3.984000)
array init 1.640000 0.000000 1.640000 ( 1.690000)
struct get 0.438000 0.000000 0.438000 ( 0.450000)
array get 0.469000 0.000000 0.469000 ( 0.469000)
struct set 0.703000 0.000000 0.703000 ( 0.715000)
array set 0.484000 0.000000 0.484000 ( 0.504000)

Robert@Babelfish2 /cygdrive/c/TEMP
$ cat array-struct.rb
require 'benchmark'

REP = 500_000

Foo = Struct.new :foo, :bar

data = "foo"
c1 = Foo.new data, data
c2 = [data, data]

Benchmark.bmbm 15 do |x|
x.report 'struct init' do
REP.times { Foo.new data, data }
end

x.report 'array init' do
REP.times { [data, data] }
end

x.report 'struct get' do
REP.times { c1.bar }
end

x.report 'array get' do
REP.times { c2[1] }
end

x.report 'struct set' do
REP.times { c1.bar = data }
end

x.report 'array set' do
REP.times { c2[1] = data }
end
end

Kind regards

robert
 
Reply With Quote
 
Sylvain Joyeux
Guest
Posts: n/a
 
      10-17-2007
> I'm not sure whether you are familiar with Benchmark#bmbm which does a
> rehearsal - personally I rather not switch off GC since in realistic
> situations GC time belongs into the mix. But results are rather
> similar:

Sure. GC does belong to the mix. Now, if GC is enabled you are not able to
compare anything. Let's assume that GC runs during 'array init', you will
say 'hey, struct init is faster'. Now, if GC runs during 'struct init' the
result may change ...

Keeping GC is meaningful when benchmarking a whole application. In
microbenchmarks like these, it is simply noise.
--
Sylvain Joyeux

 
Reply With Quote
 
Joel VanderWerf
Guest
Posts: n/a
 
      10-17-2007
Sylvain Joyeux wrote:
>> I'm not sure whether you are familiar with Benchmark#bmbm which does a
>> rehearsal - personally I rather not switch off GC since in realistic
>> situations GC time belongs into the mix. But results are rather
>> similar:

> Sure. GC does belong to the mix. Now, if GC is enabled you are not able to
> compare anything. Let's assume that GC runs during 'array init', you will
> say 'hey, struct init is faster'. Now, if GC runs during 'struct init' the
> result may change ...
>
> Keeping GC is meaningful when benchmarking a whole application. In
> microbenchmarks like these, it is simply noise.


For fairness, you could do it this way (assuming REP is large enough):

...
Benchmark.bmbm 15 do |x|
GC.start
x.report 'struct init' do
REP.times { Foo.new data, data }
GC.start
end

GC.start
x.report 'array init' do
REP.times { [data, data] }
GC.start
end
...

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Can *common* struct-members of 2 different struct-types, that are thesame for the first common members, be accessed via pointer cast to either struct-type? John Reye C Programming 28 05-08-2012 12:24 AM
Re: slow slow slow! Expert lino fitter Computer Support 5 12-12-2008 04:00 PM
Re: slow slow slow! Beauregard T. Shagnasty Computer Support 2 12-10-2008 09:03 PM
Re: slow slow slow! Expert lino fitter Computer Support 0 12-10-2008 02:33 PM
struct my_struct *p = (struct my_struct *)malloc(sizeof(struct my_struct)); Chris Fogelklou C Programming 36 04-20-2004 08:27 AM



Advertisments