Pergunta

I am trying to increase the speed of some UI Automation operations. I stumbled across the (not so well) documented caching possibility.

From what I have understood, the whole operation (if you have a large GUI-tree) is so slow, because for every single function call there has to be a process-change (kind of like going to kernel-mode, I suppose, speed-wise?!). So.. in comes caching.

Simply tell the function to cache an element and its children, and then work on it lightning-fast. (From what I understand, you only have one context-change, and assemble all the data you need in one go.)

Good idea, but.. it is just as slow for me as the uncached variation. I wrote some simple testcode, and could not see an improvement.

AutomationElement ae; // element whose siblings are to be examined, thre are quite a few siblings
AutomationElement sibling;

#region non-cached
watch.Start();
for (int i = 0; i < 10; ++i)
{
    sibling = TreeWalker.RawViewWalker.GetFirstChild(TreeWalker.RawViewWalker.GetParent(ae));
    while (sibling != null)
    {
        sibling = TreeWalker.RawViewWalker.GetNextSibling(sibling);
    }
}
watch.Stop();
System.Diagnostics.Debug.WriteLine("Execution time without cache: " + watch.ElapsedMilliseconds + " ms.");
#endregion

#region cached
watch.Reset();
watch.Start();

CacheRequest cacheRequest = new CacheRequest();
cacheRequest.TreeScope = TreeScope.Children | TreeScope.Element; // for testing I chose a minimal set
AutomationElement parent;

for (int j = 0; j < 10; ++j)
{
    using (cacheRequest.Activate())
    {
        parent = TreeWalker.RawViewWalker.GetParent(ae, cacheRequest);
    }
    int cnt = parent.CachedChildren.Count;
    for (int i = 0; i < cnt; ++i)
    {
        sibling = parent.CachedChildren[i];
    }
}
watch.Stop();
System.Diagnostics.Debug.WriteLine("Execution time parentcache: " + watch.ElapsedMilliseconds + " ms.");
#endregion

The setup is: you get an element and want to check on all its (many) siblings. Both implementations, without and with cache, are given.

The output (debug mode): Execution time without cache: 1130 ms. Execution time parentcache: 1271 ms.

Why is this not working? How to improve?

Thanks for any ideas!!!

Foi útil?

Solução 2

Actually, recently I found the time to check it again, and also against different UI elements. For caching to be faster, one first has to specify all (and only) the needed elements. There is a real performance difference if you e. g. look at a ComboBox with 100 elements inside or something similar, like a very complicated GUI with a lot of elements on the same hierarchy level - and you actually need the data from all of them. So.. caching is not a solution for everything but rather a performance-optimization-tool that has to be applied with.. knowledge about the situation, the requirements and the internal working. BTW, talking about performance, I found out that each .current access to a UI element take very roughly 20ms, so for complex operations this really can reach a significant time.

Outras dicas

I would not expect the two loops to differ much in their running time, since in both cases the parent's children must be fully walked (in the first explicitly, and in the second to populate the cache.) I do think, though, that the time required for looping through the parent.CachedChildren array is much lower than your initial walk code. At that point, the elements should be cached, and you can use them without re-walking the tree.

The general point is that you can't get performance for free, since you need to invest the time to actually populate the cache before it becomes useful.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top