Performance of ArcObjects


In this topic


About performance of ArcObjects

ArcObjects is based on the Component Object Model (COM). For .NET objects to interoperate with COM objects, an intermediate layer is needed. The .NET Framework contains the interop application programming interface (API), which acts as the intermediate layer between .NET and COM. The interop API provides Runtime Callable Wrappers (RCWs) as the mechanism that allows the use of COM objects in .NET.
The following code example shows how to define a COM object in .NET:
[C#]
ESRI.ArcGIS.Geometry.Point pt = new ESRI.ArcGIS.Geometry.Point();
[VB.NET]
Dim pt As ESRI.ArcGIS.Geometry.Point = New ESRI.ArcGIS.Geometry.Point()
An RCW object is defined instead of the COM object. When the object is instantiated (using the new keyword), the RCW object creates the appropriate COM object. When you call the members of the object in .NET, the parameters of the method call will be marshaled from the .NET process to the COM process, and the return value will be marshaled back.

Looping ArcObjects geometry operations (example 1)

To analyze the performance of ArcObjects in .NET, consider the overhead of creating wrapper objects and marshaling, as compared to the actual running time of your ArcObjects code. The following code example shows this comparison:
The code example is not intended as a benchmark of ArcObjects performance in .NET but demonstrates possible differences in the speed of execution of ArcObjects code, which you might want to consider when creating applications. The code example was run on a machine with a processor speed of 3 Gigahertz, with NET Framework 2.0, using Visual Studio.
Create a Windows application in C# or VB .NET, add a form with one button, then perform some simple geometry operations in a loop when the button is clicked.
[C#]
private void button1_Click(object sender, System.EventArgs e)
{
    // Prepare the objects.
    ESRI.ArcGIS.Geometry.IPoint p1, p2;
    p1 = new ESRI.ArcGIS.Geometry.Point();
    p2 = new ESRI.ArcGIS.Geometry.Point();
    p1.PutCoords(1, 2);
    p2.PutCoords(3, 4);
    ESRI.ArcGIS.Geometry.ILine pLine = new ESRI.ArcGIS.Geometry.Line();

    // Time a loop of geometry operations.
    int tick1, tick2, tick3;
    tick1 = System.Environment.TickCount;
    for (long i = 0; i <= 10000000; i++)
    {
        pLine.PutCoords(p1, p2);
    }
    tick2 = System.Environment.TickCount;
    tick3 = tick2 - tick1;

    System.Windows.Forms.MessageBox.Show(tick3.ToString());
}
[VB.NET]
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    ' Prepare the objects.
    Dim p1, p2 As ESRI.ArcGIS.Geometry.IPoint
    p1 = New ESRI.ArcGIS.Geometry.Point
    p2 = New ESRI.ArcGIS.Geometry.Point
    p1.PutCoords(1, 2)
    p2.PutCoords(3, 4)
    Dim pLine As ESRI.ArcGIS.Geometry.ILine = New ESRI.ArcGIS.Geometry.Line
    
    ' Time a loop of geometry operations.
    Dim tick1, tick2, tick3 As Integer
    tick1 = System.Environment.TickCount
    Dim i As Integer
    For i = 0 To 10000000
        pLine.PutCoords(p1, p2)
    Next i
    tick2 = System.Environment.TickCount
    tick3 = tick2 - tick1
    
    System.Windows.Forms.MessageBox.Show(tick3.ToString())
End Sub
The preceding code took an average of 30 seconds to run in C# and VB .NET. For comparison, use Visual C++ to create a standard executable (EXE). (The GetTickCount Windows API call replaces the .NET Framework TickCount property.)
The equivalent Visual C++ code takes five seconds to execute, making the code about six times faster than .NET. However, performing a small operation thousands of times that executes very quickly is an extreme case. In cases like this, the time spent in the interoperation between COM and .NET is likely to dominate the total running time.

Creating and populating a geodatabase (example2)

Consider instead example code that creates and populates a personal geodatabase. A personal geodatabase is created, then populated with features by importing the shapefiles that comprise the sample data. Subtypes are created and a geometric network with connectivity rules is built. A composite relationship class is also created. In contrast to example 1, this code consists of operations that take longer to execute.
In C# and VB .NET, this code takes an average of 25 seconds to run, and in VB6, the execution time also averages 25 seconds. How can the .NET code execute just as quickly, considering the extra instructions required for the interop layer? The VB6 code is executed by the Visual Basic runtime, which can be less efficient than the .NET Framework. For this example, no difference is seen in performance between the environments.

Creating a proxy class in Managed C++ (example 1 revisited)

Realistically, you might need to perform the kind of operation that took longer in .NET (large iterations of small operations). Do you have to take the performance hit? Not necessarily. You have the choice to write a proxy class in Managed C++ where you can place ArcObjects code that heavily uses the interop layer. Once you expose this code as public methods, you can call the methods from your C# or VB .NET code. Since the interop layer is only required when you call the methods of this proxy class, the execution time can be greatly reduced.
For example, to perform the previous operations, you can create a proxy class in Managed C++. This class contains a function that performs the loop of geometry operations. See the following code example:
[C++]
#using "C:\Program Files\ArcGIS\DeveloperKit10.0\Dotnet\ESRI.ArcGIS.System.dll"
#using "C:\Program Files\ArcGIS\DeveloperKit10.0\Dotnet\ESRI.ArcGIS.Geometry.dll"
  
namespace MCpp
{
  public __gc class AOWrapper
  {
    public:
      AOWrapper()
    {
      ::CoInitialize(0);
    }
    ~AOWrapper()
    {
      ::CoUninitialize();
    }
    public:
      int line_test()
    {
      IPointPtr ipPt1(CLSID_Point);
      IPointPtripPt2(CLSID_Point);
      ipPt1->PutCoords(1, 2);
      ipPt2->PutCoords(2, 3);
      ILinePtr ipLine(CLSID_Line);
      for(long i = 0;  i < =  10000000; i++)
      {
        ipLine->PutCoords(ipPt1,ipPt2);
      }
      return 0;
    }
  };
}
The preceding function can be called from a .NET application using code like the following (remember to add a reference to the .dll previously created):
[C#]
private void button1_Click(object sender, System.EventArgs e)
{
    int tick1, tick2, tick3;
    MCpp.AOWrapper w = new MCpp.AOWrapper();
    tick1 = System.Environment.TickCount;
    w.line_test();
    tick2 = System.Environment.TickCount;
    tick3 = tick2 - tick1;
    System.Windows.Forms.MessageBox.Show(tick3.ToString());
}
[VB.NET]
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim tick1, tick2, tick3 As Integer
    Dim w As MCpp.AOWrapper = New MCpp.AOWrapper()
    tick1 = System.Environment.TickCount
    For i = 0 To 10000000
        pLine.PutCoords(p1, p2)
    Next i
    tick2 = System.Environment.TickCount
    tick3 = tick2 - tick1
    
    System.Windows.Forms.MessageBox.Show(tick3.ToString())
End Sub
By using the proxy class written in Managed C++, the average running time is improved to five seconds.
One disadvantage of using Managed C++ is that the assembly written in Managed C++ cannot use the verification mechanism of .NET security; therefore, it needs to run in a trusted environment. Future releases of Visual C++ .NET might add additional functionality that could alter this situation.
The key to improving performance is to find the performance delay in your application, which might or might not be the interop time. For most ArcObjects applications, developing in .NET will not significantly deteriorate the performance of your code. If you find the interop is the delay, writing Managed C++ proxy classes for parts of your code could provide a solution.


See Also:

Managed Extensions for C++ Programming
Dr. GUI on Visual C++ .NET