You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
mono AOT compiler cannot resolve and inline static virtual calls in gshared methods #75801
using System;
using System.Diagnostics;
using System.Numerics;
public class Tests
{
private interface INegator<T> where T : struct
{
static abstract bool NegateIfNeeded(bool equals);
}
private readonly struct DontNegate<T> : INegator<T> where T : struct
{
public static bool NegateIfNeeded(bool equals) => equals;
}
private readonly struct Negate<T> : INegator<T> where T : struct
{
public static bool NegateIfNeeded(bool equals) => !equals;
}
private static int IndexOfValueType<TValue, TNegator>()
where TValue : struct, INumber<TValue>
where TNegator : struct, INegator<TValue>
{
for (int j = 0; j < 1000; ++j) {
for (int i = 0; i < 100000; ++i)
TNegator.NegateIfNeeded (true);
}
return 0;
}
public static void Main () {
var w = Stopwatch.StartNew ();
IndexOfValueType<byte, DontNegate<byte>> ();
w.Stop ();
Console.WriteLine (w.ElapsedMilliseconds);
}
}
When calling IndexOfValueType<byte, DontNegate<byte>>, the AOT compiler will compile a shared instance for bytes/enums with byte basetype, but inside the shared method it can't resolve the
constrained. !!TNegator
call bool class Tests/INegator`1<!!TValue>::NegateIfNeeded(bool)
call to DontNegate so it doesn't get inlined.
This is hit with the recent BCL changes to SpanHelpers.
I think the lowest risk for net 7.0 is to copy the code back and put it inside ifdefs.
@vargaz I assume that it means that the two workarounds posted above would not help? I have started copying the code and it's a lot of code (hundreds of lines) so it's not minimal risk.
var arr = new int [100000];
var w = Stopwatch.StartNew ();
var span = new Span<int> (arr);
for (int i = 0; i < 100000; ++i)
span.IndexOf ((int)50);
w.Stop ();
Console.WriteLine (w.ElapsedMilliseconds);
Without the span revert: 80s
Without span revert + this PR: 8.4s
With span revert: 8s
So there is still about a 5% slowdown, but it's not that bad anymore.
Reacted by Fan Yang
ghost locked as resolved and limited conversation to collaborators on Nov 26, 2022
Activity
SamMonoRT commentedon Sep 19, 2022
cc @BrzVlad
adamsitnik commentedon Sep 19, 2022
@vargaz As you know I am working on the 7.0 fix and I wonder whether I could avoid copying the old code back. I have two questions:
Thelp?typeofinstead help?vargaz commentedon Sep 19, 2022
I think the lowest risk for net 7.0 is to copy the code back and put it inside ifdefs.
adamsitnik commentedon Sep 19, 2022
@vargaz I assume that it means that the two workarounds posted above would not help? I have started copying the code and it's a lot of code (hundreds of lines) so it's not minimal risk.
jkotas commentedon Sep 19, 2022
You can add copy of the old implementation files verbatim under a different name, and just do minimal changes on top of it to get things compile.
[mono][aot] Prefer specific instances instead of gshared for methods …
adamsitnik commentedon Sep 27, 2022
@vargaz Can I revert #75917 now?
vargaz commentedon Sep 27, 2022
This only solves (part of) the AOT slowdowns, the interpreter slowdowns are still there.
vargaz commentedon Sep 28, 2022
So for a simple test case:
So there is still about a 5% slowdown, but it's not that bad anymore.