Reputation: 21765
I'm embedding small scripts in a c# application.
To increase performance I compile them when the application starts.
public CompiledCode CompileScript(string script)
{
return engine.CreateScriptSourceFromString(script).Compile();
}
The CompiledCode instances are then stored in a Dictionary so I can reuse them later.
When the time has come to execute them, I use something like:
result = code.Execute(scope);
Where scope is an instance of ScriptScope
maintained by a simple helper class.
That scope is set up when an instance of the helper is created so that variables and assemblies available to the scripts are added properly:
if (variables != null)
{
scope = engine.CreateScope(variables);
}
else
{
scope = engine.CreateScope();
}
if (assemblies != null)
{
assemblies.ForEach(a => scope.Engine.Runtime.LoadAssembly(a));
}
Basically, a list of assemblies is passed to the constructor of the helper class and I reuse the instance of the helper class in various places. (Not a static class, as I do need multiple helper instances for specific scenarios, but in the context of this question we are talking about a single instance)
When using this on a normal PC the overhead of compiling/running the code is neglectable.
However, I'm running this on a RaspberryPI
and noticed that the first time a specific script is executed, it takes a very long time. (Easily up to 40 seconds for a 2 line script)
Subsequent executions of the same CompiledCode
instances execute really fast (200ms).
So I have code that has already been compiled (oddly that first compilation is very fast as well), but the first call to Execute() on a given CompiledCode
instance takes ages.
Now I'm wondering, what is it that Execute()
does the first time and is there a way to perform whatever it is doing at an earlier time without actually executing the code?
There seems to be an additional step between compiling and actually running the code.
I was thinking maybe it's related to the fact that I reuse the scope defined by the
helper class, but of course if I just use the default scope on execute
I don't have any of the variables and assembly references.
Update:
Running it on a RaspberryPI means I'm using Mono.
More specifically Mono 2.10.8.1 (Debian 2.10.8.1-8)
I cannot update Mono as I'm relying on a very specific version of MonoGame
that only works with this exact version of Mono at the time of writing.
Upvotes: 2
Views: 234
Reputation: 7662
Hazarding a guess, I'd say that what's happening is that the IronPython assemblies are getting JITted. THe only issue is that there are other code paths that call into IronPython, and I don't know if Mono's JIT works on the assembly level or the type/method level. You could try doing AOT on the IronPython and DLR assemblies and see if that helps at all.
Upvotes: 2