Performance concerns when manually manipulating the DOM

C

Carl

I have a fairly complex form that I have created that has performance issues.
After looking at a variety of possible causes I have identified one area that
definitely seems to be the leading culprit. I am programming IP SP1 with C#
and dynamically populating various elements in the underlying xml. In order
to isolate this functionality, I created a test form with a button that, when
clicked, mimics the behavior of the real form. In the xsd I created for the
form I added an unbounded complex type (called Child in the test) containing
2 elements; Name and Value. When the button is clicked code executes a loop
with 1000 iterations adding a "Child" element (including Name and Value
children) on every pass. When I click this after the form first loads (when
the underlying xml is relatively empty), the loop takes about three minutes
to process. Clicking the button a second time (to add an additional 1000
elements) takes nearly 10 minutes. Additionally while this processing is
taking place, CPU usage gets pegged on the IP process. Since my clients are
running slower processors than I, any performance lag that I am seeing is
even worse with them.

Is there something wrong with the technique I am using? I am able to
populate drop-down lists for web services identified as secondary data
sources with similar quantities in a fraction of the time. Since this is also
information being written to the DOM, wouldn't it make sense that this would
be slow as well?

I would appreciate any help or insight you might have.

Here is the main C# processing loop that I have currently implemented:

for(int i = 0; i<1000; i++)
{
IXMLDOMNode nChild = thisXDocument.DOM.createNode(1, "Child",
"urn:www-catalysis-com:test");
IXMLDOMNode nName = thisXDocument.DOM.createNode(1, "Name",
"urn:www-catalysis-com:test");
IXMLDOMNode nValue = thisXDocument.DOM.createNode(1, "Value",
"urn:www-catalysis-com:eek:rders");
nName.text = "Loop: " + i.ToString();
nValue.text = "Time: " + DateTime.Now.ToLongTimeString();
nChild.appendChild(nName);
nChild.appendChild(nValue)
thisXDocument.DOM.selectSingleNode("//tns:TEST/tns:Children").appendChild(nChild);
}

Thanks!
 
S

Steve van Dongen [MSFT]

I have a fairly complex form that I have created that has performance issues.
After looking at a variety of possible causes I have identified one area that
definitely seems to be the leading culprit. I am programming IP SP1 with C#
and dynamically populating various elements in the underlying xml. In order
to isolate this functionality, I created a test form with a button that, when
clicked, mimics the behavior of the real form. In the xsd I created for the
form I added an unbounded complex type (called Child in the test) containing
2 elements; Name and Value. When the button is clicked code executes a loop
with 1000 iterations adding a "Child" element (including Name and Value
children) on every pass. When I click this after the form first loads (when
the underlying xml is relatively empty), the loop takes about three minutes
to process. Clicking the button a second time (to add an additional 1000
elements) takes nearly 10 minutes. Additionally while this processing is
taking place, CPU usage gets pegged on the IP process. Since my clients are
running slower processors than I, any performance lag that I am seeing is
even worse with them.

Is there something wrong with the technique I am using? I am able to
populate drop-down lists for web services identified as secondary data
sources with similar quantities in a fraction of the time. Since this is also
information being written to the DOM, wouldn't it make sense that this would
be slow as well?

I would appreciate any help or insight you might have.

Here is the main C# processing loop that I have currently implemented:

for(int i = 0; i<1000; i++)
{
IXMLDOMNode nChild = thisXDocument.DOM.createNode(1, "Child",
"urn:www-catalysis-com:test");
IXMLDOMNode nName = thisXDocument.DOM.createNode(1, "Name",
"urn:www-catalysis-com:test");
IXMLDOMNode nValue = thisXDocument.DOM.createNode(1, "Value",
"urn:www-catalysis-com:eek:rders");
nName.text = "Loop: " + i.ToString();
nValue.text = "Time: " + DateTime.Now.ToLongTimeString();
nChild.appendChild(nName);
nChild.appendChild(nValue);
thisXDocument.DOM.selectSingleNode("//tns:TEST/tns:Children").appendChild(nChild);
}

Thee things to improve performance:
1. This code doesn't have to execute on every iteration:
tisXDocument.DOM.selectSingleNode("//tns:TEST/tns:Children")
2. XPath searches containing // are much slower particularly on large
DOM.
3. Build your new XML in memory and insert everything into
XDocument.DOM at once. InfoPath will start to rerender the view after
each DOM manipulation.

IXMLDOMNode childrenNode =
thisXDocument.DOM.selectSingleNode("//tns:TEST/tns:Children")
IXMLDOMNode tempNode = childrenNode.cloneNode(true);

for(int i = 0; i<1000; i++)
{
// yada yada yada

tempNode.appendChild(nChild);
}

childrenNode.parentNode.replaceChild(tempNode, childrenNode);

Regards,
Steve
 
C

Carl

Thanks!

Just for kicks I timed the same sample code with the various changes:

First Pass Second Pass
Original Code 3 min 10 min
DisableAutoUpdate 14 sec 32 sec
+Eliminate "//" in xpath 13 sec 30 sec
+Clone Node 3 sec 3 sec
Re-enable AutoUpdate 5 sec 9 sec
(just to see)



Greg Collins said:
Steve's comments are very valid. It can be much faster to work with a cloned copy of your DOM when you have extensive modifications to make all at once.

One other thing you can do is use XDocument.View.DisableAutoUpdate() and EnableAutoUpdate() around the DOM changes. This may or may not be sufficient for what you are doing.

--
Greg Collins [InfoPath MVP]
Please visit: http://www.InfoPathDev.com



I have a fairly complex form that I have created that has performance issues.
After looking at a variety of possible causes I have identified one area that
definitely seems to be the leading culprit. I am programming IP SP1 with C#
and dynamically populating various elements in the underlying xml. In order
to isolate this functionality, I created a test form with a button that, when
clicked, mimics the behavior of the real form. In the xsd I created for the
form I added an unbounded complex type (called Child in the test) containing
2 elements; Name and Value. When the button is clicked code executes a loop
with 1000 iterations adding a "Child" element (including Name and Value
children) on every pass. When I click this after the form first loads (when
the underlying xml is relatively empty), the loop takes about three minutes
to process. Clicking the button a second time (to add an additional 1000
elements) takes nearly 10 minutes. Additionally while this processing is
taking place, CPU usage gets pegged on the IP process. Since my clients are
running slower processors than I, any performance lag that I am seeing is
even worse with them.

Is there something wrong with the technique I am using? I am able to
populate drop-down lists for web services identified as secondary data
sources with similar quantities in a fraction of the time. Since this is also
information being written to the DOM, wouldn't it make sense that this would
be slow as well?

I would appreciate any help or insight you might have.

Here is the main C# processing loop that I have currently implemented:

for(int i = 0; i<1000; i++)
{
IXMLDOMNode nChild = thisXDocument.DOM.createNode(1, "Child",
"urn:www-catalysis-com:test");
IXMLDOMNode nName = thisXDocument.DOM.createNode(1, "Name",
"urn:www-catalysis-com:test");
IXMLDOMNode nValue = thisXDocument.DOM.createNode(1, "Value",
"urn:www-catalysis-com:eek:rders");
nName.text = "Loop: " + i.ToString();
nValue.text = "Time: " + DateTime.Now.ToLongTimeString();
nChild.appendChild(nName);
nChild.appendChild(nValue);
thisXDocument.DOM.selectSingleNode("//tns:TEST/tns:Children").appendChild(nChild);
}

Thee things to improve performance:
1. This code doesn't have to execute on every iteration:
tisXDocument.DOM.selectSingleNode("//tns:TEST/tns:Children")
2. XPath searches containing // are much slower particularly on large
DOM.
3. Build your new XML in memory and insert everything into
XDocument.DOM at once. InfoPath will start to rerender the view after
each DOM manipulation.

IXMLDOMNode childrenNode =
thisXDocument.DOM.selectSingleNode("//tns:TEST/tns:Children")
IXMLDOMNode tempNode = childrenNode.cloneNode(true);

for(int i = 0; i<1000; i++)
{
// yada yada yada

tempNode.appendChild(nChild);
}

childrenNode.parentNode.replaceChild(tempNode, childrenNode);

Regards,
Steve
 
Top