-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Thread.InitializeCurrentThread
is only called once for the Thread
lifetime, however the method it is used in CurrentThread
is called lots and every async
method has its own call to it (to get ExecutionContext
etc)
runtime/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs
Lines 328 to 335 in bdd6d35
public static Thread CurrentThread | |
{ | |
[Intrinsic] | |
get | |
{ | |
return t_currentThread ?? InitializeCurrentThread(); | |
} | |
} |
Currently the asm generated is a conditional jmp forward for it already being set e.g. from AsyncMethodBuilderCore:Start(byref)
which is bad for static branch prediction.
G_M49992_IG03:
call [CORINFO_HELP_READYTORUN_STATIC_BASE]
mov rax, gword ptr [rax+24]
test rax, rax
jne SHORT G_M49992_IG05
;; bbWeight=1 PerfScore 6.25
G_M49992_IG04:
call [Thread:InitializeCurrentThread():Thread]
;; bbWeight=0.25 PerfScore 0.75
G_M49992_IG05:
mov ...
Reversing the condition in CurrentThread
Thread? currentThread = t_currentThread;
if (currentThread is not null)
{
return currentThread;
}
return InitializeCurrentThread();
While it generates a conditional jmp forward for InitializeCurrentThread
it also then adds a jmp for the regular path:
G_M49992_IG03:
call [CORINFO_HELP_READYTORUN_STATIC_BASE]
mov rax, gword ptr [rax+24]
test rax, rax
je SHORT G_M49992_IG05
;; bbWeight=1 PerfScore 6.25
G_M49992_IG04:
jmp SHORT G_M49992_IG06
;; bbWeight=0.50 PerfScore 1.00
G_M49992_IG05:
call [Thread:InitializeCurrentThread():Thread]
;; bbWeight=0.50 PerfScore 1.50
G_M49992_IG06:
mov ...
Marking it as a cold method should resolve this by moving the call to InitializeCurrentThread
to the end of the method so the regular path didn't have to jump over it?
/cc @EgorBo
category:performance
theme:block-layout
Metadata
Metadata
Assignees
Labels
Type
Projects
Status