ruby-prof vs. Object#clone

  • Thread starter Victor 'Zverok' Shepelev
  • Start date
V

Victor 'Zverok' Shepelev

For some reasons I extensively use this technique:

obj =3D MyClass=2Enew(=2E=2E=2E)
obj=2Einstance_eval{
def my_cool_method
end
}

#create 1000 clones of the obj, call #my_cool_method
(1=2E=2E1000)=2Ecollect{
clon =3D obj=2Eclone
clon=2Emy_cool_method
}

The problem is ruby-prof shows each clone's #my_cool_method as separate on=
e in the report, so I see 1000 lines with 1 calls of #my_cool_method inste=
ad of 1 line with 1000 calls=2E Is it bug or by design? May this problem b=
e result of the fact I use latest Ruby 1=2E9 version?

Thanks=2E

V=2E
 
J

Jan Svitok

For some reasons I extensively use this technique:

obj = MyClass.new(...)
obj.instance_eval{
def my_cool_method
end
}

#create 1000 clones of the obj, call #my_cool_method
(1..1000).collect{
clon = obj.clone
clon.my_cool_method
}

The problem is ruby-prof shows each clone's #my_cool_method as separate one in the report, so I see 1000 lines with 1 calls of #my_cool_method instead of 1 line with 1000 calls. Is it bug or by design? May this problem be result of the fact I use latest Ruby 1.9 version?

This is what I've found in the sources:
My_cool_method is a singleton instance method (not an ordinary
instance method). singleton methods are cloned by creating proxy
method, so they are not identical.

object.c: rb_obj_clone()
class.c : rb_singleton_class_clone() and clone_method()

try:

o1 = Object.new
# this creates singleton method
o1.instance_eval { def m ; end }

o2 = o1.clone

p o1.method:)m) #=> #<Method: #<Object:0x393c328>.m>
p o2.method:)m) #=> #<Method: #<Object:0x393c198>(#<Object:0x393c328>).m>

o3 = o1.clone
p o3.method:)m) #=> #<Method: #<Object:0x393bcd4>(#<Object:0x393c328>).m>

# now this creates normal method:
o1.class.module_eval { def c ; end }
p o1.method:)c) #=> #<Method: Object#c>
p o2.method:)c) #=> #<Method: Object#c>
p o3.method:)c) #=> #<Method: Object#c>

However it should be possible to patch ruby-prof to take account for this.

IMHO the most simple way is to define normal instance methods via

obj.class.module_eval, i.e. MyClass.module_eval.

(Please note that I might be wrong, I'm no expert on ruby internals,
this is what I learned in a few minutes looking into sources...)
 
V

Victor 'Zverok' Shepelev

Jan Svitok (jan=2Esvitok@gmail=2Ecom)
26/10/2006 13:56:01
This is what I've found in the sources:
My_cool_method is a singleton instance method (not an ordinary
instance method)=2E singleton methods are cloned by creating proxy
method, so they are not identical=2E

OK, I've got it=2E
Thanks=2E
IMHO the most simple way is to define normal instance methods via

obj=2Eclass=2Emodule_eval, i=2Ee=2E MyClass=2Emodule_eval=2E

Not for me, unfortunately :(
One of reasons, why I use those strange techniques, is to have different s=
ets of methods in different sets of objects of same class=2E

More specially, all those objects are HTML DOM nodes, and I want to have #=
cell(col, row) method for <table> node, #click method for <button> node an=
d even more special cases, like have some special methods for <table class=
=3Dgrid>=2E My approach is on-the-fly per-CSS-selector extending of certai=
n nodes, and it works well, except for profiling :(

The issue still open=2E

V=2E
 
J

Jan Svitok

Jan Svitok ([email protected])
26/10/2006 13:56:01


OK, I've got it.
Thanks.


Not for me, unfortunately :(
One of reasons, why I use those strange techniques, is to have different sets of methods in different sets of objects of same class.

More specially, all those objects are HTML DOM nodes, and I want to have #cell(col, row) method for <table> node, #click method for <button> node and even more special cases, like have some special methods for <table class=grid>. My approach is on-the-fly per-CSS-selector extending of certain nodes, and it works well, except for profiling :(

The issue still open.

Maybe you can create new subclasses instead:

my_new_class = Class.new(MyClass)
my_new_class.module_eval {...}

and optionally
Object.const_set(my_new_class_name, mynewclass)

NB: class_eval is an alias for module_eval.
 
V

Victor 'Zverok' Shepelev

Jan Svitok ([email protected])
26/10/2006 14:38:01
Maybe you can create new subclasses instead:

my_new_class = Class.new(MyClass)
my_new_class.module_eval {...}

and optionally
Object.const_set(my_new_class_name, mynewclass)

Hmmm... Sounds reasonable. I'll try.
Thanks, Jan!

V.
 
R

Rick DeNatale

Jan Svitok ([email protected])
26/10/2006 13:56:01


OK, I've got it.
Thanks.


Not for me, unfortunately :(
One of reasons, why I use those strange techniques, is to have different sets of methods in different sets of objects of same class.

More specially, all those objects are HTML DOM nodes, and I want to have #cell(col, row) method for <table> node, #click method for <button> node and even more special cases, like have some special methods for <table class=grid>. My approach is on-the-fly per-CSS-selector extending of certain nodes, and it works well, except for profiling :(

Will something like this meet your needs?

rick@frodo:/public/rubyscripts$ cat mycool.rb
class MyClass
end

module MyCoolModule
def my_cool_method
end
end
obj = MyClass.new
obj.extend MyCoolModule

#create 1000 clones of the obj, call #my_cool_method
(1..1000).collect{
clon = obj.clone
clon.my_cool_method
}

rick@frodo:/public/rubyscripts$ ruby -r profile mycool.rb
% cumulative self self total
time seconds seconds calls ms/call ms/call name
53.04 0.61 0.61 1 610.00 1140.00 Range#each
28.70 0.94 0.33 1000 0.33 0.40 Kernel.clone
11.30 1.07 0.13 1000 0.13 0.13
MyCoolModule.my_cool_method
6.09 1.14 0.07 1000 0.07 0.07 Kernel.initialize_copy
0.00 1.14 0.00 1 0.00 0.00 Module#extended
0.00 1.14 0.00 1 0.00 0.00 Kernel.extend
0.00 1.14 0.00 1 0.00 0.00 Class#new
0.00 1.14 0.00 1 0.00 0.00 Class#inherited
0.00 1.14 0.00 1 0.00 1140.00 Enumerable.collect
0.00 1.14 0.00 1 0.00 0.00 Object#initialize
0.00 1.14 0.00 1 0.00 0.00 Module#extend_object
0.00 1.14 0.00 1 0.00 0.00 Module#method_added
0.00 1.15 0.00 1 0.00 1150.00 #toplevel
rick@frodo:/public/rubyscripts$
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,830
Latest member
ZADIva7383

Latest Threads

Top