Hi Sergey,
You're right! The calculation called via the C API and via COM performs about the same (maybe the COM is even marginally faster).
I tested a bit with the .dna file copied below, in my Excel 2010 (32-bit Excel, 64-bit Win 7 SP1, i7-2620 @ 2.7 GHz).
I found the following, testing different function signatures and combinations of (calculations x cells):
(The functions are defined in the .dna file, and I show the elapsed and resulting calculations per second.)
calcs x cells elapsed per second
=RAND() - C API
10,000 x 500 1.117 4 474 673
=RAND() - COM
10,000 x 500 1.075 4 652 894
=RAND()
1 x 1,000,000 0.155 6 451 613
=MultiThreadDangerous(RAND())
10,000 x 500 4.886 1 023 262
1 x 1,000,000 0.859 1 163 693
=Dangerous(RAND())
10,000 x 500 6.318 791 390
1 x 1,000,000 1.173 852 878
=MultiThread(RAND())
10,000 x 500 17.335 288 438
1 x 1,000,000 3.550 281 690
=DoubleToDouble(RAND())
10,000 x 500 28.828 173 444
1 x 1,000,000 5.892 169 712
=ObjectToString(RAND())
10,000 x 100 11.917 83 911
1 x 1,000,000 11.026 90 692
=Uniform_variant(1,2,RAND(),3)
10,000 x 100 12.580 79 493
1 x 500,000 5.804 86 147
1 x 1,000,000 11.493 87 009
So for Excel-DNA function the calcs-per-second range from 1,000,000 per second to 80,000 per second, depending on the signature, multithread and try-catch choices.
Dangerous (IsExceptionSafe=true) means unhandled exceptions will crash Excel - normally Excel-DNA wraps the function in a try-catch and returns 'object'.
The fastest function is just a double->double, marked IsThreadSafe and IsExceptionSafe.
Your Uniform_variant function calculates about 80,000 cells per second.
So I agree those calls won't be as fast as I suggested.
Do you find about the same?
Regards,
Govert
<DnaLibrary Name="Performance Tests" Language="C#" RuntimeVersion="v4.0">
<Reference Name="Microsoft.Office.Interop.Excel" />
<![CDATA[
using System;
using System.Diagnostics;
using Microsoft.Office.Interop.Excel;
using ExcelDna.Integration;
public static class PerformanceTest
{
[ExcelCommand(Name = "OnCalculateActiveSheetOnce", MenuName = "CalculateSheet", MenuText = "Calculate Sheet once via C API")]
public static void OnCalculateActiveSheetOnce()
{
XlCall.Excel(XlCall.xlcEcho, false);
var stopwatch = Stopwatch.StartNew();
XlCall.Excel(XlCall.xlcCalculateDocument);
stopwatch.Stop();
XlCall.Excel(XlCall.xlcEcho, true);
XlCall.Excel(XlCall.xlcMessage, true, stopwatch.Elapsed.TotalSeconds.ToString("F3"));
}
[ExcelCommand(Name = "OnCalculateActiveSheetOnce2", MenuName = "CalculateSheet", MenuText = "Calculate Sheet once via COM")]
public static void OnCalculateActiveSheetOnce2()
{
var xlApp = (Application)ExcelDnaUtil.Application;
Worksheet activeSheet = (Worksheet)xlApp.ActiveSheet;
xlApp.ScreenUpdating = false;
var stopwatch = Stopwatch.StartNew();
activeSheet.Calculate();
stopwatch.Stop();
xlApp.ScreenUpdating = true;
xlApp.StatusBar = stopwatch.Elapsed.TotalSeconds.ToString("F3");
}
[ExcelCommand(Name = "OnCalculateActiveSheet", MenuName = "CalculateSheet", MenuText = "Calculate Sheet via C API")]
public static void OnCalculateActiveSheet()
{
XlCall.Excel(XlCall.xlcEcho, false);
var stopwatch = Stopwatch.StartNew();
for (var i = 0; i < 10000; i++)
{
XlCall.Excel(XlCall.xlcCalculateDocument);
}
stopwatch.Stop();
XlCall.Excel(XlCall.xlcEcho, true);
XlCall.Excel(XlCall.xlcMessage, true, stopwatch.Elapsed.TotalSeconds.ToString("F3"));
}
[ExcelCommand(Name = "OnCalculateActiveSheet2", MenuName = "CalculateSheet", MenuText = "Calculate Sheet via COM")]
public static void OnCalculateActiveSheet2()
{
var xlApp = (Application)ExcelDnaUtil.Application;
Worksheet activeSheet = (Worksheet)xlApp.ActiveSheet;
xlApp.ScreenUpdating = false;
var stopwatch = Stopwatch.StartNew();
for (var i = 0; i < 10000; i++)
{
activeSheet.Calculate();
}
stopwatch.Stop();
xlApp.ScreenUpdating = true;
xlApp.StatusBar = stopwatch.Elapsed.TotalSeconds.ToString("F3");
}
public static object Uniform_variate(double val1, double val2, object obj1, object obj2)
{
return obj1;
}
[ExcelFunction(IsExceptionSafe=true, IsThreadSafe=true)]
public static double MultiThreadDangerous(double val1)
{
return val1 + 1.0;
}
[ExcelFunction(IsExceptionSafe=true)]
public static double Dangerous(double val1)
{
return val1 + 1.0;
}
[ExcelFunction(IsThreadSafe=true)]
public static double MultiThread(double val1)
{
return val1 + 1.0;
}
public static double DoubleToDouble(double val1)
{
return val1 + 1.0;
}
public static string DoubleToString(double val1)
{
return val1.ToString();
}
public static string ObjectToString(object obj1)
{
return obj1.ToString();
}
}
]]>
</DnaLibrary>