Slow performance on first usage

Hi there,

I’m a happy user of GemBox Spreadsheet and GemBox Document. Something that has been bugging me for a while is that, the first time I manipulate and save a document, it takes about one second to complete (even small documents). I haven’t profiled which function is the bottleneck, but it is strange, because after the first document, all other documents are processed much faster.

Before I dig in to find out what’s going on, I wanted to ask if this is a known issue. Some things that come to mind and might be the source:

  1. Maybe the library is just big, and .NET needs time to load it on first use
  2. Maybe GemBox needs time to unlock itself after providing the license

For reference, I’m on Windows 11 using .NET 7. I see no difference between Debug and Release builds of my app.

Best regards,
Adolfo

Hi Adolfo,

I haven’t experienced this issue, but your first idea might be the reason.
Perhaps the time you’re experiencing is related to assembly being loaded into a runtime.

Regards,
Mario

Thanks! I did some additional testing and observed about 140ms of overhead in first usages compared to second usages (loading the assemblies beforehand made no difference). I guess it must be the JIT.

Since I’m investigating this purely out of curiosity, I think I’ll leave the investigation here for the time being, and maybe in the future experiment with AOT compilation.

Thanks for the great library by the way :slight_smile:

PS: if you are intersted in the code I used to test this, see below

public void Benchmark()
{
    // Preload GemBox.Spreadsheet and all the assemblies it references
    var loaded = new List<string>();
    var loadAssembly = Measure(() =>
    {
        var stack = new Stack<string>();
        stack.Push("GemBox.Spreadsheet");

        while (stack.Count > 0)
        {
            var name = stack.Pop();
            var assembly = Assembly.Load(name);
            loaded.Add(name);
            foreach (var referenced in assembly.GetReferencedAssemblies())
            {
                stack.Push(referenced.Name!);
            }
        }
    });

    var setLicense = Measure(() => SpreadsheetInfo.SetLicense(GemBoxLicense.Key));
    var newFile1 = Measure(() => new ExcelFile());
    var newFile2 = Measure(() => new ExcelFile());

    var saveFile1 = Measure(() =>
    {
        var stream = new MemoryStream();
        var file = new ExcelFile();
        var sheet = file.Worksheets.Add("Test");
        sheet.Rows.InsertEmpty(0);
        sheet.Rows[0].Cells[0].Value = "Hello world";
        file.Save(stream, SaveOptions.XlsxDefault);
    });

    var saveFile2 = Measure(() =>
    {
        var stream = new MemoryStream();
        var file = new ExcelFile();
        var sheet = file.Worksheets.Add("Test");
        sheet.Rows.InsertEmpty(0);
        sheet.Rows[0].Cells[0].Value = "Hello world";
        file.Save(stream, SaveOptions.XlsxDefault);
    });
}

long Measure(Action action)
{
    var stopwatch = Stopwatch.StartNew();
    action();
    stopwatch.Stop();
    return stopwatch.ElapsedMilliseconds;
}
1 Like