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:
- Maybe the library is just big, and .NET needs time to load it on first use
- 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
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