DynamoDS/Dynamo — pull request #2796 by ke-yu (2014-10-20 10:42:41+00:00)
Title: Fix performance issue in MAGN-4891

This pull request fixed performance issue in [MAGN-4891: CompilerInternalException on Creation of Custom Node / HNTB Bridge] (http://adsk-oss.myjetbrains.com/youtrack/issue/MAGN-4891#). That is, Dynamo takes 4 seconds for the first run and takes over 2 minutes to run when converting a bunch of nodes into custom node.

The root cause is in update. Actually there are multiple issues, but this pull request only fixes the most serious one. For a procedure, update mechanism will track how many global variables (``ProcedureNode.updateGlobals``) and how many properties (``ProcedureNode.updateProperties``) changed in the function. For this case, for newly created custom node, there are 900+ global variables and 290+ properties (including all temporary variables, e.g., ``%tSSA_num``, apparently there are some issues here).

And in a routine ``ResolveFinalNodeRef()``, it will iterate all graph nodes and if the right hand side of graph node is a procedure, this function will move all updated global variables and properties in the function to the update list (``GraphNode.updateNodeRefList``) of this graph node. But, an iteration in this function add *a lot* of redundant nodes:
```
...
foreach (ProtoCore.AssiciativeGraph.UpdateNodeRef updateRef in firstProc.updateProperties)
{
if (firstProc.classScope == Constants.kGlobalScope)
{
graphNode.updateNodeRefList.AddRange(firstProc.updateGlobals);
}
...
}
```

Where ``graphNode.updateNodeRefList.AddRange()`` is unnecessarily invoked many times. For this defect, there are 290+ outer loop and 900+ inner loop and totally 277,821 nodes added to ``graphNode``.

Later, for update, there is a loop again:
```
for (int i = 0; i < graphNodeList.Count; ++i)
{
...
var graphNode = graphNodeList[i];
...
if (graphNodeList.DependsOn(executingGraphNode.updateNodeRefList))
...
}
```

As there are around 900+ graph node in ``graphNodeList``, totally 900 x 277821 = 250 million loops!.

We need to review update implementation. But here let me just fix the most serious one.

@lukechurch , please review the change. Thanks.

p.s. The following diff is not so intuitive. The change is from
```
foreach (ProtoCore.AssiciativeGraph.UpdateNodeRef updateRef in firstProc.updateProperties)
{
if (firstProc.classScope == Constants.kGlobalScope)
{
graphNode.updateNodeRefList.AddRange(firstProc.updateGlobals);
}
}
```
to
```
if (firstProc.classScope == Constants.kGlobalScope)
{
graphNode.updateNodeRefList.AddRange(firstProc.updateGlobals);
}
else
{
foreach (...) {...}
}
```