Closed
Description
I was profiling our CPU-heavy application and apparently there are a lot of traces where jit is invoked to compile some lambdas when issuing a LINQ ISession.Query<TRecord>
This is noticable especially when using dotnet counters monitor -p1
, example:
[System.Runtime]
% Time in GC since last GC (%) 8
Allocation Rate (B / 1 sec) 3.2411e+08
CPU Usage (%) 69
Exception Count (Count / 1 sec) 9
GC Committed Bytes (MB) 3,389
GC Fragmentation (%) 27.191
GC Heap Size (MB) 2,344
Gen 0 GC Count (Count / 1 sec) 0
Gen 0 Size (B) 192
Gen 1 GC Count (Count / 1 sec) 0
Gen 1 Size (B) 1.1532e+08
Gen 2 GC Count (Count / 1 sec) 0
Gen 2 Size (B) 8.8658e+08
IL Bytes Jitted (B) 2.3988e+08
LOH Size (B) 4.3898e+08
Monitor Lock Contention Count (Count / 1 sec) 116
Number of Active Timers 312
Number of Assemblies Loaded 305
Number of Methods Jitted 8,407,800
POH (Pinned Object Heap) Size (B) 898,696
ThreadPool Completed Work Item Count (Count / 1 sec) 7,637
ThreadPool Queue Length 0
ThreadPool Thread Count 20
Time spent in JIT (ms / 1 sec) 639.439
Working Set (MB) 3,943
Note Number of Methods Jitted
and Time spent in JIT (ms / 1 sec)
The traces point to NhPartialEvaluatingExpressionVisitor.EvaluateSubtree
as the culprit. See:
Stack trace example where application code looks like:
var record = await db.Query<TRecord>().SingleOrDefaultAsync(
s => s.ColumnA == entityA
&& s.ColumnB == entityB);
Thread (0x71E):
[Native Frames]
System.Private.CoreLib!System.Reflection.Emit.DynamicMethod.CreateDelegate(class System.Type,class System.Object)
System.Linq.Expressions!System.Linq.Expressions.Compiler.LambdaCompiler.Compile(class System.Linq.Expressions.LambdaExpression)
NHibernate!NHibernate.Linq.Visitors.NhPartialEvaluatingExpressionVisitor.EvaluateSubtree(class System.Linq.Expressions.Expression)
NHibernate!NHibernate.Linq.Visitors.NhPartialEvaluatingExpressionVisitor.Visit(class System.Linq.Expressions.Expression)
System.Linq.Expressions!System.Linq.Expressions.ExpressionVisitor.VisitBinary(class System.Linq.Expressions.BinaryExpression)
NHibernate!NHibernate.Linq.Visitors.NhPartialEvaluatingExpressionVisitor.Visit(class System.Linq.Expressions.Expression)
System.Linq.Expressions!System.Linq.Expressions.ExpressionVisitor.VisitBinary(class System.Linq.Expressions.BinaryExpression)
NHibernate!NHibernate.Linq.Visitors.NhPartialEvaluatingExpressionVisitor.Visit(class System.Linq.Expressions.Expression)
System.Linq.Expressions!System.Linq.Expressions.ExpressionVisitor.VisitLambda(class System.Linq.Expressions.Expression`1<!!0>)
NHibernate!NHibernate.Linq.Visitors.NhPartialEvaluatingExpressionVisitor.Visit(class System.Linq.Expressions.Expression)
System.Linq.Expressions!System.Linq.Expressions.ExpressionVisitor.VisitUnary(class System.Linq.Expressions.UnaryExpression)
NHibernate!NHibernate.Linq.Visitors.NhPartialEvaluatingExpressionVisitor.Visit(class System.Linq.Expressions.Expression)
System.Linq.Expressions!System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(class System.Linq.Expressions.ExpressionVisitor,class System.Linq.Expressions.IArgumentProvider)
System.Linq.Expressions!System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(class System.Linq.Expressions.MethodCallExpression)
NHibernate!NHibernate.Linq.Visitors.NhPartialEvaluatingExpressionVisitor.Visit(class System.Linq.Expressions.Expression)
NHibernate!NHibernate.Linq.NhRelinqQueryParser.PreTransform(class System.Linq.Expressions.Expression,class NHibernate.Linq.Visitors.PreTransformationParameters)
NHibernate!NHibernate.Linq.NhLinqExpression..ctor(value class NHibernate.Linq.QueryMode,class System.Linq.Expressions.Expression,class NHibernate.Engine.ISessionFactoryImplementor)
NHibernate!NHibernate.Linq.DefaultQueryProvider.PrepareQuery(class System.Linq.Expressions.Expression,class NHibernate.IQuery&)
NHibernate!NHibernate.Linq.DefaultQueryProvider.ExecuteAsync(class System.Linq.Expressions.Expression,value class System.Threading.CancellationToken)
NHibernate!NHibernate.Linq.DefaultQueryProvider+<ExecuteAsync>d__25`1[System.__Canon].MoveNext()
System.Private.CoreLib!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start(!!0&)
NHibernate!NHibernate.Linq.DefaultQueryProvider.ExecuteAsync(class System.Linq.Expressions.Expression,value class System.Threading.CancellationToken)
NHibernate!NHibernate.Linq.LinqExtensionMethods.SingleOrDefaultAsync(class System.Linq.IQueryable`1<!!0>,class System.Linq.Expressions.Expression`1<class System.Func`2<!!0,bool>>,value class System.Threading.CancellationToken)
(( private application code/scrubbed ))
System.Private.CoreLib!System.Threading.Tasks.TaskSchedulerAwaitTaskContinuation+<>c.<Run>b__2_0(class System.Object)
System.Private.CoreLib!System.Threading.Tasks.Task.ExecuteWithThreadLocal(class System.Threading.Tasks.Task&,class System.Threading.Thread)
System.Private.CoreLib!System.Threading.Tasks.TaskScheduler.TryExecuteTask(class System.Threading.Tasks.Task)
Akka!Akka.Actor.ActorCell.HandleActorTaskSchedulerMessage(class Akka.Dispatch.SysMsg.ActorTaskSchedulerMessage)
Akka!Akka.Actor.ActorCell.SysMsgInvokeAll(value class Akka.Dispatch.SysMsg.EarliestFirstSystemMessageList,int32)
Akka!Akka.Dispatch.Mailbox.ProcessAllSystemMessages()
Akka!Akka.Dispatch.Mailbox.<Run>b__36_0()
Akka!Akka.Actor.ActorCell.UseThreadContext(class System.Action)
Akka!Akka.Dispatch.Mailbox.Run()
System.Private.CoreLib!System.Threading.QueueUserWorkItemCallback.Execute()
System.Private.CoreLib!System.Threading.ThreadPoolWorkQueue.Dispatch()
System.Private.CoreLib!System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart()
Is this performance/jit profile intended, maybe people have workarounds?