I was curious to see how different Razor functions (using DynamicNode iterators) stacked up, so created a few benchmarks. I populated a bare 4.7.1 site with a large number of nested nodes (around 250) and then ran the benchmarks against this tree. Each benchmark was run a hundred times and the average time noted (using the System.Diagnostics.Stopwatch class).
So you can see that filtering by NodeTypeAlias can speed up traversal when there's a limited number of that type, but makes no difference if all nodes are of that alias.
Even though ALL my pages where visible (umbracoNaviHide not true) adding the where condition to a custom property adds a 2.5 x performance penalty. But that's not too bad, given the extra filtering that is going on.
So we can see that there is little difference, and the penalty for going Up() and Down() is negligible. However, using Ancestors() can give quite a hit (which is understandable as it can potentialy traverse much deeper).
Awesome! Would be interesting to actually package this up and we could use it to trace calls and see if we can improve performance. So the site along with a good range of DynamicNode calls could end up and a performance matrix. Game?
@inherits umbraco.MacroEngines.DynamicNodeContext
@using System.Diagnostics;
@{
long millisecs = 0;
int samples = 10;
int iterations = 5;
int count = 0;
for (int i = 0; i < samples; i++)
{
TimeSpan elapsed = Benchmark(iterations, out count);
<h1>Time: @elapsed.Duration().Milliseconds millseconds</h1>
millisecs += elapsed.Duration().Milliseconds;
}
long average = millisecs / iterations;
<h2>Average: @average milliseconds to count @count nodes @iterations times</h2>
}
@functions
{
TimeSpan Benchmark(int iterations, out int count)
{
count = 0;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < iterations; i++)
{
count = Model.AncestorOrSelf().DescendantsOrSelf().Count();
}
stopwatch.Stop();
return stopwatch.Elapsed.Duration();
}
}
It really could do with a way of passing in the dynamic expression to the benchmark method, but I'm not clever enough to figure out how. Maybe Gareth can help? :)
Razor Benchmarks - Interesting Results
I was curious to see how different Razor functions (using DynamicNode iterators) stacked up, so created a few benchmarks. I populated a bare 4.7.1 site with a large number of nested nodes (around 250) and then ran the benchmarks against this tree. Each benchmark was run a hundred times and the average time noted (using the System.Diagnostics.Stopwatch class).
Here are some results:
Counting All Nodes
Model.AncestorOrSelf().DescendantsOrSelf().Count(); 9 milliseconds
Library.NodeById(-1).Descendants().Count(); 103 milliseconds
I was suprised to find that the first method is 10 times faster than the latter. I would have thought the latter would be the same, or even faster.
Filtering By Alias
In my tree I have just one umbHomepage (at root) and the rest are all umbTextpage
So you can see that filtering by NodeTypeAlias can speed up traversal when there's a limited number of that type, but makes no difference if all nodes are of that alias.
Conditions - Where
Filtering by a "native" property hardly adds any overhead at all.
Even though ALL my pages where visible (umbracoNaviHide not true) adding the where condition to a custom property adds a 2.5 x performance penalty. But that's not too bad, given the extra filtering that is going on.
I'll add more benchmarks later!
Really interesting stuff! Can't wait for more benchmarks :-)
Some more benchmarks (but with more iterations), using the same set-up...
Comparison of "native" methods and "dynamic" methods
These functions do exactly the same thing, but with startingly different results:
So you can see there is quiet an overhead in using "dynamic" methods compared to "native" DynamicNode methods.
And if we use Descendants() instead of Children (even when there is only 1 level of children) we get:
So it seems that we should avoid using deep traversal methods like Ancestors() and Descendants() when we only need Child or Parent nodes.
Up() vs Parent
So we can see that there is little difference, and the penalty for going Up() and Down() is negligible. However, using Ancestors() can give quite a hit (which is understandable as it can potentialy traverse much deeper).
Ordering Results
So order direction makes no discernible difference, as you would expect. But splitting the OrderBy clause up does...
However, not sure if the above give the same ordered results and are directly comparable? Anyone?
Splitting and ANDed "where" clause into two doesn't seem to matter, which is what I'd expect.
Awesome! Would be interesting to actually package this up and we could use it to trace calls and see if we can improve performance. So the site along with a good range of DynamicNode calls could end up and a performance matrix. Game?
My basic benchmark Macro was just this:
It really could do with a way of passing in the dynamic expression to the benchmark method, but I'm not clever enough to figure out how. Maybe Gareth can help? :)
is working on a reply...