-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Add SkipLocalsInit #26598
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add SkipLocalsInit #26598
Conversation
I'm not sure we'd easily be able to tell what breaks. I'd hate to cause an unexpected security bug because we enabled it assembly wide. |
Stackallocs review. These are the stackallocs used in the assemblies with the attribute applied. I haven't reviewed any from code that is synced with runtime. They are already working with attribute applied.
|
cc @GrabYourPitchforks Can you help us out here with an audit? |
TBH I was actually going to try to pull back on our use of SkipLocalsInit within the runtime repo, targeting specifically crypto and serialization and other "sensitive" assemblies. |
@@ -15,6 +16,8 @@ | |||
<Reference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" /> | |||
<Reference Include="Microsoft.AspNetCore.Http.Abstractions" /> | |||
<Reference Include="Microsoft.Extensions.Hosting.Abstractions" /> | |||
|
|||
<Compile Include="$(SharedSourceRoot)SkipLocalsInit.cs" LinkBase="Shared\SkipLocalsInit.cs" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hosting.Abstractions is not on a perf-critical code path and from your review it doesn't contain any stackallocs. Why did you mark this assembly? The same goes for Server.Abstractions and likely some of the others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added it to all projects referenced by Kestrel.Core. Want them removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does it get us if we're not using stackallocs in these assemblies?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stephentoub Is there much benefit to SkipLocalsInit outside of stackalloc usages?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The benefit isn't limited to stackalloc, but is proportional to how much state is on the stack that needs to be cleared (and where clearing can be skipped). As such, it generally is much more impactful with stackalloc, but it can show up as a peanut butter cost elsewhere.
[SkipLocalsInit]
[Benchmark]
public unsafe int WithSkipLocal()
{
Guid g1, g2, g3, g4, g5, g6;
// Do something cheap that let's the benchmark compile and stuff not get optimized away
Unsafe.SkipInit(out g1);
Unsafe.SkipInit(out g2);
Unsafe.SkipInit(out g3);
Unsafe.SkipInit(out g4);
Unsafe.SkipInit(out g5);
Unsafe.SkipInit(out g6);
return *(int*)&g1 + *(int*)&g2 + *(int*)&g3 + *(int*)&g4 + *(int*)&g5 + *(int*)&g6;
}
[Benchmark]
public unsafe int WithoutSkipLocal()
{
Guid g1, g2, g3, g4, g5, g6;
// Do something cheap that let's the benchmark compile and stuff not get optimized away
Unsafe.SkipInit(out g1);
Unsafe.SkipInit(out g2);
Unsafe.SkipInit(out g3);
Unsafe.SkipInit(out g4);
Unsafe.SkipInit(out g5);
Unsafe.SkipInit(out g6);
return *(int*)&g1 + *(int*)&g2 + *(int*)&g3 + *(int*)&g4 + *(int*)&g5 + *(int*)&g6;
}
Method | Mean | Error | StdDev | Code Size |
---|---|---|---|---|
WithSkipLocal | 0.2983 ns | 0.0324 ns | 0.0303 ns | 33 B |
WithoutSkipLocal | 0.7273 ns | 0.0015 ns | 0.0013 ns | 79 B |
If the goal was biggest bang for the buck, though, it's definitely where larger stackallocs are being employed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another place it can show up impactfully is with fixed-size buffers, since as with stackallocs, they can often represent large regions of stack space that need to be cleared, e.g.
[SkipLocalsInit]
[Benchmark]
public unsafe int WithSkipLocal()
{
Data d;
Unsafe.SkipInit(out d);
return d.Ptr[0];
}
[Benchmark]
public unsafe int WithoutSkipLocal()
{
Data d;
Unsafe.SkipInit(out d);
return d.Ptr[0];
}
unsafe struct Data
{
public fixed byte Ptr[1024];
}
Method | Mean | Error | StdDev | Code Size |
---|---|---|---|---|
WithSkipLocal | 0.5009 ns | 0.0047 ns | 0.0041 ns | 64 B |
WithoutSkipLocal | 14.8256 ns | 0.0411 ns | 0.0343 ns | 132 B |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given it comes with a degree of risk, it seems better not to add it unless here's a demonstrated benefit. I also assume you'd be targeting the hot paths like per-request processing. Hosting doesn't have many of those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @Tratcher but we also don't clear the array from the array pool so I don't see how this is different. Still I'd prefer doing this to some key placed in Kestrel rather than the entire assembly. That'll build more confidence.
4ae24c1
to
a6b288a
Compare
a6b288a
to
ac10f7d
Compare
@JamesNK are we doing this PR? |
Do you want it? I investigated how we're using stackalloc to make sure they're safe, but it sounds like a deeper review is required and there is little enthusiasm to do it. |
I don't want it assembly wide, I want to put it on a few hot methods in kestrel to start. |
Replaced by explicit PR. |
Addresses #26586
Enable SkipLocalsInit
almost everywherein Kestrel, HTTP, hosting, routing. Selected because they're the "hot path" assemblies when it comes to startup time and per-request performance.Test to see what breaks.