MemberWiseClone speed and implementation?

A

Anders Borum

Hello!

I accidentally posted this as a reply to another posting. It is a seperate
posting - sorry :)

I am programming a cloning service (which is essential to the framework),
and am currently using a custom implementation of the ICloneable interface.
With this in mind, I am wondering if I would be better off just using the
MemberWiseClone method of the inherited base object class.

Having measured the differences in speed, the MemberWiseClone implementation
was is approx. 25% slower than the custom implementation. We were debating
this at work and some suggested that I would benefit from future
improvements in the CLR implementation.

However, as this is a critical part of the framework, I believe a 25%
degradation would make the code suffer too much. Also, I could just run the
tests again when .NET 2.0 is released at a later time and change the cloning
service implementation if necessary.

The MemberWiseClone method forwards the call to an external method. I am
interested in the details of this implementation. Is the CLR using
reflection to clone the objects?

Thanks in advance.
 
D

Daniel O'Connell [C# MVP]

Anders Borum said:
Hello!

I accidentally posted this as a reply to another posting. It is a seperate
posting - sorry :)

I was wondering why that was posted there, ;).
I am programming a cloning service (which is essential to the framework),
and am currently using a custom implementation of the ICloneable
interface.
With this in mind, I am wondering if I would be better off just using the
MemberWiseClone method of the inherited base object class.

Having measured the differences in speed, the MemberWiseClone
implementation
was is approx. 25% slower than the custom implementation. We were debating
this at work and some suggested that I would benefit from future
improvements in the CLR implementation.

However, as this is a critical part of the framework, I believe a 25%
degradation would make the code suffer too much. Also, I could just run
the
tests again when .NET 2.0 is released at a later time and change the
cloning
service implementation if necessary.

The MemberWiseClone method forwards the call to an external method. I am
interested in the details of this implementation. Is the CLR using
reflection to clone the objects?

I do not believe so, no. If memory serves, MemberwiseClone is effectivly a
memcopy, copying the whole object into a new location and doing whatever bit
twiddling needs to be done to establish a new object. However, by all tests
I've run it looks like custom cloning is even faster on empty objects. It is
a curiosity to say the least.

Some crucial differences to consider:

A manual clone involves a new object creation and thus a constructor
invocation, MemberwiseClone does not invoke a constructor, so if your
constructor does things you want or don't want to happen, you'll need to
make yoru choices based on that.

MemberwiseClone is a bit more version proof. Much like copy constructors, an
IClonable::Clone method is hard to implement virtually, you end up with an
effective hiearchy of virtual Clone(T) implemetnations with every subsequent
class implementing ICloneable::Clone() anew so that the proper class is
created and passed down, any other mechanism will generate a different type.
By using MemberwiseClone you can simply implement the virtual Clone(T)
method and provide a single implementation of IClonable::Clone() which calls
MemberwiseClone and passes the returned object down the Clone hiearchy(or
have it passed up, as you will).

MemberwiseClone is shallow, so for deep copy semantics you'll have to use
some form of custom cloning code.
 
A

Anders Borum

Hello Daniel
I was wondering why that was posted there, ;).

Yes, I can't even find that posting now and sat waiting for it to appear in
the topics list. It's friday, what can I say .. sat till 02:30 AM in the
morning coding as usual (while the family was sleeping =o)
I do not believe so, no. If memory serves, MemberwiseClone is effectivly a
memcopy, copying the whole object into a new location and doing whatever bit
twiddling needs to be done to establish a new object. However, by all tests
I've run it looks like custom cloning is even faster on empty objects. It is
a curiosity to say the least.

Not sure I put the numbers correct in the original posting, but these are
the results from the performance test. I'm initiating a cloning of some 12,3
mio. objects just to push some numbers.

Initiating cloning of 12800000 objects ..
Calculating custom cloning .. 2,921875 seconds.
Calculating MemberWiseClone .. 4,234375 seconds.

This is the release code with default (release) optimizations from VS .NET
2003 on a Dual 1.2Ghz AthlonMP workstation. The VS .NET console project is
available here:

http://adsl.sphereworks.dk/ClonePerformanceConsole.rar
Some crucial differences to consider:

A manual clone involves a new object creation and thus a constructor
invocation, MemberwiseClone does not invoke a constructor, so if your
constructor does things you want or don't want to happen, you'll need to
make yoru choices based on that.

Didn't know that about MemberWiseClone, but I am not dependend on any
constructor calls (the models are, so to speak, just models and are served
from a set of service factories that sets state).
MemberwiseClone is a bit more version proof. Much like copy constructors, an
IClonable::Clone method is hard to implement virtually

Yes, that's true. However, the current architecture contains sealed models
(where the cloning is imlemented currently), so I am in control of the
cloning process. But I do agree that in the case where you'd offer
inheritance from your models, it's a safer path using MemberWiseClone.

My problem is that tests showed MemberWiseClone to be quite slow compared to
the custom implementation. I am, again, not sure if the test I made are 100%
perfect. This is also why I'm asking for your oppinion.
By using MemberwiseClone you can simply implement the virtual Clone(T)
method and provide a single implementation of IClonable::Clone() which calls
MemberwiseClone and passes the returned object down the Clone hiearchy(or
have it passed up, as you will).

That's the technique I'm using in the performance test.
MemberwiseClone is shallow, so for deep copy semantics you'll have to use
some form of custom cloning code.

Yes, I'm aware of the differences. However, all my models use valuetypes
internally and those are the values I'm interested in cloning. This is also
the reason for considering MemberWiseClone at all (if a deep copy was
required, I'd probably stick with ICloneable as per .NET recommendations).
 
D

Daniel O'Connell [C# MVP]

Didn't know that about MemberWiseClone, but I am not dependend on any
constructor calls (the models are, so to speak, just models and are served
from a set of service factories that sets state).


Yes, that's true. However, the current architecture contains sealed models
(where the cloning is imlemented currently), so I am in control of the
cloning process. But I do agree that in the case where you'd offer
inheritance from your models, it's a safer path using MemberWiseClone.

My problem is that tests showed MemberWiseClone to be quite slow compared
to
the custom implementation. I am, again, not sure if the test I made are
100%
perfect. This is also why I'm asking for your oppinion.

Ahh, I'm sorry if I misphrased myself originally, but my tests support
yours, I can't get MemberwiseClone to outperform ICloneable.Clone, although
I'm showing about a considerable difference. Since you make it clear later
on that there is nothing else requiring you to use MemberwiseClone, I would
recommend using ICloneable::Clone until such a point where MemberwiseClone
is required.

FWIW, preliminary tests on the 2.0 framework were no better.

My results for 1 million clone iterations over an emtpy object:

MemberwiseClone Time: 00:00:00.1406250
Clone Time: 00:00:00.0156250
 
A

Anders Borum

Hello!
Ahh, I'm sorry if I misphrased myself originally, but my tests support
yours, I can't get MemberwiseClone to outperform ICloneable.Clone, although
I'm showing about a considerable difference.

The test I've performed indicates that the larger number of fields to be
cloned, the larger difference.
Since you make it clear later
on that there is nothing else requiring you to use MemberwiseClone, I would
recommend using ICloneable::Clone until such a point where MemberwiseClone
is required.

I came to the same conclusion, but I thought I'd better be safe than sorry.
FWIW, preliminary tests on the 2.0 framework were no better.

My results for 1 million clone iterations over an emtpy object:

MemberwiseClone Time: 00:00:00.1406250
Clone Time: 00:00:00.0156250

That's a considerable difference. Looking at these numbers, I am quite sure
I won't be using the MemberWiseClone approach. The cloning service is
crucial to the performance of the application so I need to squeze as much
performance from the CLR as possible.

If possible, could I get a copy of your test solution?

Thanks for helping out btw!
 
D

Daniel O'Connell [C# MVP]

Anders Borum said:
Hello!


The test I've performed indicates that the larger number of fields to be
cloned, the larger difference.


I came to the same conclusion, but I thought I'd better be safe than
sorry.


That's a considerable difference. Looking at these numbers, I am quite
sure
I won't be using the MemberWiseClone approach. The cloning service is
crucial to the performance of the application so I need to squeze as much
performance from the CLR as possible.

If possible, could I get a copy of your test solution?

Sure, this is just a basic "take a shot and see waht happens thing", I
didn't put much effort into it:

using System;

public class Test : ICloneable
{
public Test()
{
//Console.WriteLine("Constructor!"); //uncomment this if you want to test
constructor calls.
}

public object Clone()
{
return new Test();
}
public static void Main(string[] args)
{
Test a = new Test();
a.MemberwiseClone(); //warming the paths a little
a.Clone();

DateTime start, finish;
start = DateTime.Now;
for (int i = 0; i < 1000000; i++)
a.MemberwiseClone();

finish = DateTime.Now;
Console.WriteLine("MemberwiseClone Time: " + (finish - start));
start = DateTime.Now;
for (int i = 0; i < 1000000; i++)
a.Clone();

finish = DateTime.Now;
Console.WriteLine("Clone Time: " + (finish - start));

}
}

It lacks subtlety, but the difference was significant enough I decided not
to go for the slightly more complicated tick count approach or the
considerably more accurat high performance timer approach. I'm lazy that
way, ;).

One interesting possibility is that Clone may well be inlinable(I can't
remember if interface membership excludes inlining off hand), while
MemberwiseClone probably is not. That could be a significant issue across a
huge number of execuations on its own.

My tests were run on a dual 2.2 ghz Xeon, btw.
 
A

Anders Borum

Hello!
It lacks subtlety, but the difference was significant enough I decided not
to go for the slightly more complicated tick count approach or the
considerably more accurat high performance timer approach. I'm lazy that
way, ;).

Yes, I'm that way too .. the initial pointers told me I didn't need that
kind of precision to make up my mind. I would, however, argue that my
provided solution is more tidy that your example ;-)

Session ended from Nostromo.
Ripley signing out ..
 

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

Top