DEV Community

Cover image for NPOI Alternative Spreadsheet API Performance Test in C# .NET
Chelsea Devereaux for MESCIUS inc.

Posted on • Updated on • Originally published at grapecity.com

NPOI Alternative Spreadsheet API Performance Test in C# .NET

GrapeCity Documents for Excel (GcExcel) is a fast, high-performance spreadsheet API that requires no dependencies on Excel. With full .NET 6 support, you can generate, load, modify, and convert Excel .xlsx spreadsheets in a .NET Framework, .NET Core, Mono, and Xamarin.

We have continually been monitoring the performance of GcExcel with every release. We recorded the performance time and memory consumed for load, save, and calculation operations of GcExcel in comparison with other competitors on Windows, macOS, and Linux platforms. From our rigorous performance tests, we are confident GcExcel will be an excellent replacement for those looking for an alternative to NPOI or similar other APIs to enhance their current applications' performance.

Performance Metrics and Data

Test Machine Configurations

  • Windows: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz 3.19 GHz, x64-based processor, Windows 10 Pro 20H2 Build 19042.1052
  • MacOS: Intel i9 @ 2.3 GHz / MacOS Catalina v10.15.6
  • Linux: CPU: 4 core Intel(R) Xeon(R) CPU E5-2683 v3 @ 2.00GHz, 4GB

Builds Used for Comparison

This comparison references the following build version of GcExcel and competitor:

Test Data

The first three tests populate 100,000 rows x 30 columns (3,000,000 cells) with type double, string, and date values, measuring the performance for Set ValuesGet Values, and Save to XLSX. The total Memory Used (which is difficult to measure accurately since garbage collection can happen at any time).

These tests look like this (the string test uses the hard-coded string value "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and the date test creates a new Date() object but are otherwise the same):

GcExcel Double Performance Test

   public static void TestSetRangeValues_Double(int rowCount, int columnCount, ref double setTime, ref double getTime, ref double saveTime, ref double usedMem)
    {

                Console.WriteLine();    
                Console.WriteLine(string.Format("GcExcel benchmark for double values with {0} rows and {1} columns", rowCount, columnCount));

                IWorkbook workbook = new Workbook();
                IWorksheet worksheet = workbook.Worksheets[0];

                Stopwatch watch = new Stopwatch();
                watch.Start();

                double[,] values = new double[rowCount, columnCount];

                for (int i = 0; i < rowCount; i++)
                {
                    for (int j = 0; j < columnCount; j++)
                    {
                        values[i, j] = i + j;
                    }
                }

                worksheet.Range[0, 0, rowCount, columnCount].Value = values;
                watch.Stop();

                setTime = watch.ElapsedMilliseconds / 1000d;
                Console.WriteLine(string.Format("GcExcel set double values: {0:N3} s", setTime));

                watch.Start();
                object tmpValues = worksheet.Range[0, 0, rowCount, columnCount].Value;
                watch.Stop();

                getTime = watch.ElapsedMilliseconds / 1000d; ;
                Console.WriteLine(string.Format("GcExcel get double values: {0:N3} s", getTime));

                watch.Start();
                workbook.Save("../../output/gcexcel-saved-doubles.xlsx");
                watch.Stop();
                saveTime = watch.ElapsedMilliseconds / 1000d; ;
                Console.WriteLine(string.Format("GcExcel save doubles to Excel: {0:N3} s", saveTime)); }
Enter fullscreen mode Exit fullscreen mode

The last two tests focus more on calculation performance.

In following test, the workbook loads a large XLSX which contains many formulas using volatile functions that require recalculation each time the worksheet is calculated and measures the performance for Open FileCalculateSave to XLSX, and the total Memory Used.

This test looks like this:

GcExcel Open Large XLSX Performance Test

   public static void TestBigExcelFile(int rowCount, int columnCount, ref double openTime, ref double calcTime, ref double saveTime, ref double usedMem)
    {

                Console.WriteLine();    
                   Console.WriteLine(string.Format("GcExcel benchmark for test-performance.xlsx which is 20.5MB with a lot of values, formulas and styles"));

                IWorkbook workbook = new Workbook();

                Stopwatch watch = new Stopwatch();
                watch.Start();
                workbook.Open("../../files/test-performance.xlsx");
                watch.Stop();

                openTime = watch.ElapsedMilliseconds / 1000d; ;
                Console.WriteLine(string.Format("GcExcel open big Excel: {0:N3} s", openTime));

                watch.Start();
                workbook.Dirty();
                workbook.Calculate();
                watch.Stop();

                calcTime = watch.ElapsedMilliseconds / 1000d; ;
                Console.WriteLine(string.Format("GcExcel calculate formulas for big Excel: {0:N3} s", calcTime));

                watch.Start();
                workbook.Save("../../output/gcexcel-saved-test-performance.xlsx");
                watch.Stop();
                saveTime = watch.ElapsedMilliseconds / 1000d; ;
                Console.WriteLine(string.Format("GcExcel save back to big Excel: {0:N3} s", saveTime));
    }
Enter fullscreen mode Exit fullscreen mode

The following test populates 100,000 rows x 2 columns of double values, then sets formulas to a range of 100,000 rows x 30 columns adjacent to and referencing those double values in the first 2 columns, measuring the performance for Set FormulasCalculateSave to XLSX, and the total Memory Used.

This test looks like this:

GcExcel Formulas Performance Test

    public static void TestSetRangeFormulas(int rowCount, int columnCount, ref double setTime, ref double calcTime, ref double saveTime, ref double usedMem)
    {             
                Console.WriteLine();
                Console.WriteLine(string.Format("GcExcel benchmark for double values with {0} rows and {1} columns", rowCount, columnCount));

                IWorkbook workbook = new Workbook();
                workbook.ReferenceStyle = ReferenceStyle.R1C1;
                IWorksheet worksheet = workbook.Worksheets[0];

                double[,] values = new double[rowCount, 2];

                for (int i = 0; i < rowCount; i++)
                {
                    for (int j = 0; j < 2; j++)
                    {
                        values[i, j] = i + j;
                    }
                }
                worksheet.Range[0, 0, rowCount, 2].Value = values;

                Stopwatch watch = new Stopwatch();
                watch.Start();
                worksheet.Range[0, 2, rowCount - 2, columnCount].Formula = "=SUM(RC[-2],RC[-1])";
                watch.Stop();

                setTime = watch.ElapsedMilliseconds / 1000d; ;
                Console.WriteLine(string.Format("GcExcel set formulas: {0:N3} s", setTime));

                watch.Start();
                workbook.Calculate();
                watch.Stop();

                calcTime = watch.ElapsedMilliseconds / 1000d; ;
                Console.WriteLine(string.Format("GcExcel calculates formula: {0:N3} s", calcTime));

                workbook.ReferenceStyle = ReferenceStyle.A1;

                watch.Start();
                workbook.Save("../../output/gcexcel-saved-formulas.xlsx");
                watch.Stop();
                saveTime = watch.ElapsedMilliseconds / 1000d; ;
                Console.WriteLine(string.Format("GcExcel save formulas to Excel: {0:N3} s", saveTime));
    }

Enter fullscreen mode Exit fullscreen mode

Performance Results

Following are the PerformanceTestResults.xlsx:

GcExcel performs better than other competitors in various operations on loading, modifying, and saving the Excel file. Have a look at the numbers below.

Results

Note: The results were taken on particular machine configurations. If you are running at a different configuration, the values may not match our collected results exactly. If you observe any discrepancies in the overall performance, please leave your comments below.

Also, check out Performance Comparison of older build and Feature comparison with NPOI.

Top comments (0)