Roslyn slow startup time
c#, roslyn
Solution
I think one issue is using a memory stream, instead you should try using a dynamic module and ModuleBuilder instead. Overall the code is executing faster but still has a heavier first load scenario. I'm pretty new to Roslyn myself so I'm not sure why this is faster but here is the changed code.
var iters = 300;
foreach (var i in Enumerable.Range(0, iters))
{
// Parse the source file using Roslyn
SyntaxTree syntaxTree = SyntaxTree.ParseText(@"public class Foo" + i + @" { public void Exec() { } }");
// Add all the references we need for the compilation
var references = new List<MetadataReference>();
references.Add(new MetadataFileReference(typeof(int).Assembly.Location));
var compilationOptions = new CompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary);
// Note: using a fixed assembly name, which doesn't matter as long as we don't expect cross references of generated assemblies
var compilation = Compilation.Create("SomeAssemblyName", compilationOptions, new[] { syntaxTree }, references);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new System.Reflection.AssemblyName("CustomerA"),
System.Reflection.Emit.AssemblyBuilderAccess.RunAndCollect);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MyModule");
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
// if we comment out from this line and down, the runtime drops to ~.5 seconds
var emitResult = compilation.Emit(moduleBuilder);
watch.Stop();
System.Diagnostics.Debug.WriteLine(watch.ElapsedMilliseconds);
if (emitResult.Diagnostics.LongCount() == 0)
{
var type = moduleBuilder.GetTypes().Single(t => t.Name == "Foo" + i);
System.Diagnostics.Debug.Write(type != null);
}
}
By using this technique the compilation took just 96 milliseconds, on subsequent iterations it takes around 3 - 15ms. So I think you could be right in terms of the first load scenario adding some overhead.
Sorry I can't explain why it's faster! I'm just researching Roslyn myself and will do more digging later tonight to see if I can find any more evidence of what the ModuleBuilder provides over the memorystream.
Problem
I've noticed that the startup time for Roslyn parsing/compilation is a fairly significant one-time cost. EDIT: I am using the Roslyn CTP MSI (the assembly is in the GAC). Is this expected? Is there any workaround? Running the code below takes almost the same amount of time with 1 iteration (~3 seconds) as with 300 iterations (~3 seconds). ``` [Test] public void Test() { var iters = 300; foreach (var i in Enumerable.Range(0, iters)) { // Parse the source file using Roslyn SyntaxTree syntaxTree = SyntaxTree.ParseText(@"public class Foo" + i + @" { public void Exec() { } }"); // Add all the references we need for the compilation var references = new List<MetadataReference>(); references.Add(new MetadataFileReference(typeof(int).Assembly.Location)); var compilationOptions = new CompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary); // Note: using a fixed assembly name, which doesn't matter as long as we don't expect cross references of generated assemblies var compilation = Compilation.Create("SomeAssemblyName", compilationOptions, new[] {syntaxTree}, references); // Generate the assembly into a memory stream var memStream = new MemoryStream(); // if we comment out from this line and down, the runtime drops to ~.5 seconds EmitResult emitResult = compilation.Emit(memStream); var asm = Assembly.Load(memStream.GetBuffer()); var type = asm.GetTypes().Single(t => t.Name == "Foo" + i); } } ```