Reputation: 4958
I was profiling my class library and optimizing things, when I've noticed this strange issue:
There's a base class, and I have other classes, derived from it. Base class has a public property. I'm doing Linq queries that involve this property elsewhere in the code.
Now, doing 100,000 iterations (not even a million) I can see that if I also add a property with the same name to the derived class (intellisense highlights it with a tooltip "This property hides inherited member"), thus making basically a 'Shortcut' (but also a duplication of the property) - Code runs significantly faster... to me 350 ms. over an iteration of 100,000 is quite significant.
Why is it, please ? :) What can be done ?
More details:
Base class:
public abstract class ContentItem: IContent
{
internal ContentItem() { }
[DataMember]
[IndexedField(true, false)]
public string Guid { get; set; }
[DataMember]
[IndexedField(false, true)]
public string Title { get; set; }
}
Derived "POCO":
[IndexedClass]
public class Channel : ContentItem, IContent
{
[DataMember(IsRequired = false, EmitDefaultValue = false)]
[ContentField]
public string TitleShort { get; set; }
}
Repository class (doing the linq queries): (Generic repository)
public virtual T ByTitle(string title)
{
return All.Find(item => item.Title == title);
}
Where All
is a List<Channel>
and has 2700 items.
Code for testing:
private static void test(Content.Repository<Content.Channel> channels)
{
int iterations = 100000;
var watch = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
var channel = channels.ByTitle("Unique-Title");
}
watch.Stop();
Console.WriteLine("Done in {0} ms.", watch.ElapsedMilliseconds);
}
Upvotes: 1
Views: 385
Reputation: 6301
The difference in call and callvirt is really small.
I simplified your code. Please run it and tell us what answer do you have. I have no difference in using both properties.
public abstract class ContentItem
{
public string Title { get; set; }
public string AnotherTitle { get; set; }
}
public class Channel : ContentItem
{
public string AnotherTitle { get; set; }
}
private static void Main(string[] args)
{
var channels = new List<Channel>();
for (int i = 0; i < 3000; i++)
{
channels.Add(new Channel(){Title = i.ToString(), AnotherTitle = i.ToString()});
}
int iterations = 100000;
System.Diagnostics.Stopwatch watch;
var difs = new List<int>();
int rounds = 10;
for (int k = 0; k < rounds ; k++)
{
watch = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
var channel = channels.Find(item => item.Title == "2345");
}
watch.Stop();
long timerValue = watch.ElapsedMilliseconds;
watch = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
var channel = channels.Find(item => item.AnotherTitle == "2345");
}
watch.Stop();
difs.Add((int)(timerValue - watch.ElapsedMilliseconds));
}
Console.WriteLine("result middle dif " + difs.Sum()/rounds);
}
Update
Also in this case you do not have any call
methods in IL.
both Title
and AnotherTitle
look like
IL_0008: callvirt instance string ConsoleApplication4.Program/ContentItem::get_Title()
IL_0016: callvirt instance string ConsoleApplication4.Program/Channel::get_AnotherTitle()
The problem you have has nothing to do with call
or callvirt
. Probably the difference is in code, that you don't show to us.
Upvotes: 0
Reputation: 7367
If you examine the generated IL, when your code is using the derived class' local property, it's generating a call
rather than a callvirt
, which is just plain cheaper.
This seems like a premature optimization unless you're in a time critical loop.
Worrying about the difference between call
and callvirt
performance when building iteration using linq seems.... particularly premature.
Upvotes: 3
Reputation: 203819
When you're hiding the property you're making it a non-virtual call, rather than a virtual call to a member. Virtual dispatch does have a certain cost associated with it, which is why you're able to declare non-virtual properties/methods.
That said, in most applications the costs associated with a virtual method/property are not a problem at all. There is a difference, yes, but it's not much at all in the context of most programs.
Upvotes: 3