Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Avalonia 0.9.0 With Corert Takes forever to Compile! #7920

Closed
Shadow4walker opened this issue Dec 18, 2019 · 22 comments · Fixed by dotnet/reactive#1116
Closed

Avalonia 0.9.0 With Corert Takes forever to Compile! #7920

Shadow4walker opened this issue Dec 18, 2019 · 22 comments · Fixed by dotnet/reactive#1116

Comments

@Shadow4walker
Copy link

I'm using Corert with 'Avalonia latest Released Build' and all were good till V0.9.0 Now my app Takes so much Time To Compile 'I had to Give Up after more than 2 Hours' and this was an issue with every Avalonia Nightly Build and Now I'm Facing it with he latest Released 0.9.0 the 0.8.3 and before was all good!!

@Suchiman
Copy link
Contributor

It is possible, that they've started using a problematic (recursive) generic type / method.
Easiest way to find what caused that is probably bisecting avalonia.

@jkotas
Copy link
Member

jkotas commented Dec 18, 2019

Here is how you can diagnose the recursive generics:

  1. Add this to your .csproj file:
  <ItemGroup>
    <IlcArg Include="--verbose" />
    <IlcArg Include="--singlethreaded" />
  </ItemGroup>
  1. Run non-Release publish with verbose logging, e.g. dotnet publish -v:d -c Debug -r win-x64

If it is a recursive generic instantiation, you should be able to see the methods that are involved in the recursive cycle.

@Shadow4walker
Copy link
Author

Shadow4walker commented Dec 19, 2019

i think it's something to do with Avalonia.ReactiveUI Library I keep seeing [System.Reactive]
somethings like this

Compiling [System.Reactive]System.Reactive.Concurrency.SynchronizationContextScheduler.Schedule<ValueTuple2<__Canon,ValueTuple3<ValueTuple2<__Canon,int64>,__Canon,__Canon>>>(ValueTuple2<__Canon,ValueTuple3<ValueTuple2<__Canon,int64>,__Canon,__Canon>>,Func3<IScheduler,ValueTuple2<__Canon,ValueTuple3<ValueTuple2<__Canon,int64>,__Canon,__Canon>>,IDisposable>)...

IDK what to do next :/ here's the sample I'm working on with the RD.xml https://github.com/Shadow4walker/AVCoret.git

@jkotas
Copy link
Member

jkotas commented Dec 19, 2019

System.Reactive is known to be unfriendly to AOT compilation due to infinite and/or very extensive generic expansions.

Does it work without System.Reactive?

@Shadow4walker
Copy link
Author

System.Reactive is known to be unfriendly to AOT compilation due to infinite and/or very extensive generic expansions.

Does it work without System.Reactive?

IDK about System.Reactive it self , but Avalonia uses their own Fork 'or somthing!' for the ReactiveUI https://reactiveui.net/docs/getting-started/installation/avalonia and in previous released of Avalonia the Avalonia.ReactiveUI Lib is working with CoreRT without any issues!
However I've tried to To Not use Avalonia.ReactiveUI in the latest version I'm facing the issue with, but still the same infinity wait and I'm still seeing System.Reactive when Compiling so i think "System.Reactive" is something has been built in within Avalonia Package it self which i cannot Control!

@jkotas
Copy link
Member

jkotas commented Dec 23, 2019

Here is how the infinite recursion happens:

  1. IScheduler.Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action) method gets called with TState=MyStruct

  2. This is generic virtual method. It means that the compiler needs to instantiate this method with TState=MyStruct on all types that implement this interface

  3. One of the types is SynchronizationContextScheduler.Schedule. The implementation of this method calls IScheduler.Schedule recursively with TState=(SynchronizationContextScheduler, action, MyStruct)

  4. The compiler needs to instatiate this generic virtual method on on all types with TState=(SynchronizationContextScheduler, action, MyStruct) that implement this interface.

  5. ad infinitum

This problem was introduce by https://github.com/dotnet/reactive/pull/500/files#diff-8e3d6e5fc08a3627f0d55495e5559ac9L100 . This change saved a few allocations by introducing much worse code bloat problems. It is likely that the code bloat problems have much worse negative effect on performance than the few allocations even without full AOT.

jkotas added a commit to jkotas/reactive that referenced this issue Dec 24, 2019
The infinitive generics recursion interacts poorly with AOT. The AOT compilers have hard figuring
out where the stop generating the code for generics with infinite recursion. They either fail or
produce large images by giving up once the generics get too complex.

This change reverts a small part of dotnet#500 that introduced infinite generic recusion and adds comment.

Fixes dotnet/corert#7920
jkotas added a commit to jkotas/reactive that referenced this issue Dec 24, 2019
The infinitive generics recursion interacts poorly with AOT. The AOT compilers have hard figuring
out where the stop generating the code for generics with infinite recursion. They either fail or
produce large images by giving up once the generics get too complex.

This change reverts a small part of dotnet#500 that introduced infinite generic recursion and adds comment.

Fixes dotnet/corert#7920
@jkotas
Copy link
Member

jkotas commented Dec 24, 2019

I have submitted dotnet/reactive#1116 to System.Reactive to fix the infinite recursion. I have verified that your sample compiles successfully with this fix.

clairernovotny pushed a commit to dotnet/reactive that referenced this issue Dec 24, 2019
The infinitive generics recursion interacts poorly with AOT. The AOT compilers have hard figuring
out where the stop generating the code for generics with infinite recursion. They either fail or
produce large images by giving up once the generics get too complex.

This change reverts a small part of #500 that introduced infinite generic recursion and adds comment.

Fixes dotnet/corert#7920
@jkotas jkotas closed this as completed Dec 24, 2019
clairernovotny pushed a commit to dotnet/reactive that referenced this issue Dec 24, 2019
The infinitive generics recursion interacts poorly with AOT. The AOT compilers have hard figuring
out where the stop generating the code for generics with infinite recursion. They either fail or
produce large images by giving up once the generics get too complex.

This change reverts a small part of #500 that introduced infinite generic recursion and adds comment.

Fixes dotnet/corert#7920
@MichalStrehovsky
Copy link
Member

I have submitted dotnet/reactive#1116 to System.Reactive to fix the infinite recursion

Thank you!!!

@kekekeks
Copy link

kekekeks commented Jan 3, 2020

@jkotas
AvaloniaUI/Avalonia#3366 (comment) - still happens with 4.3.2

         Compiling [System.Reactive]System.Reactive.Concurrency.DefaultScheduler+LongRunning.ScheduleLongRunning<ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`2<__Canon,__Canon>>>>>>>>>>>>>>>>>>(ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`2<__Canon,__Canon>>>>>>>>>>>>>>>>>,Action`2<ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`3<__Canon,__Canon,ValueTuple`2<__Canon,__Canon>>>>>>>>>>>>>>>>>,ICancelable>)...```

@PJB3005
Copy link

PJB3005 commented Jan 3, 2020

CatchSchedulerLongRunning seems to be the culprit this time and it's doing the same thing of avoiding closure allocation.

@PJB3005
Copy link

PJB3005 commented Jan 3, 2020

Opened a PR to (hopefully) fix it: dotnet/reactive#1121

@hez2010
Copy link

hez2010 commented Apr 2, 2020

@PJB3005 @jkotas
Seems that there's another infinite recursive generics:

[System.Reactive]System.Reactive.Concurrency.CatchScheduler`1+CatchSchedulerPeriodic+PeriodicallyScheduledWorkItem`1<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.ValueTuple`2<System.__Canon,System.__Canon>>>>>>>>>>>>>>>>>>>.Tick(ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,ValueTuple`2<__Canon,__Canon>>>>>>>>>>>>>>>>>>

At https://github.com/dotnet/reactive/blob/c6c8d6f774386e185cc78e95415bf47c7a00f116/Rx.NET/Source/src/System.Reactive/Concurrency/CatchScheduler.cs#L111

But I don't know how to fix it....

@MichalStrehovsky
Copy link
Member

Even if we untangle the generic recursion, the CatchScheduler class is not going to work at runtime because it will hit #3460.

It's likely this code is only getting pulled into the app because the compiler by default tries to compile all code to ensure reflection will work if someone tries to access anything dynamically. Try adding <RootAllApplicationAssemblies>false</RootAllApplicationAssemblies> to a PropertyGroup in your csproj just to see if it goes away. Adding this option will likely introduce (solvable) problems at runtime.

@hez2010
Copy link

hez2010 commented Apr 2, 2020

@MichalStrehovsky
After adding <RootAllApplicationAssemblies>false</RootAllApplicationAssemblies> I built it with CoreRT successfully, though I got exception Unhandled Exception: System.IO.FileNotFoundException: Cannot load assembly 'Avalonia.Themes.Default'. No metadata found for this assembly. at runtime.

@MichalStrehovsky
Copy link
Member

Yeah, you'll have to specify those dependencies in an RD.XML file now.

This file might be a good starting point: https://github.com/wieslawsoltes/Draw2D/blob/863cbd0d1d2bb9c573f379124887937a2115a4d2/src/Draw2D/Draw2D.rd.xml

(The line with "Avalonia.Themes.Default" would fix the exception you're seeing.)

You add it to your project like this:
https://github.com/wieslawsoltes/Draw2D/blob/863cbd0d1d2bb9c573f379124887937a2115a4d2/src/Draw2D/Draw2D.csproj#L53

@hez2010
Copy link

hez2010 commented Apr 2, 2020

Thanks. Issues with loading assemblies were gone, but failed with loading native libraries:

System.DllNotFoundException: Unable to load DLL 'libSkiaSharp': The specified module could not be found.
   at System.Runtime.InteropServices.NativeLibrary.LoadLibErrorTracker.Throw(String) + 0x8b
   at Internal.Runtime.CompilerHelpers.InteropHelpers.FixupModuleCell(InteropHelpers.ModuleFixupCell*) + 0x1c4
   at Internal.Runtime.CompilerHelpers.InteropHelpers.ResolvePInvokeSlow(InteropHelpers.MethodFixupCell*) + 0x45
   at Internal.Runtime.CompilerHelpers.InteropHelpers.ResolvePInvoke(InteropHelpers.MethodFixupCell*) + 0x3e
   at SkiaSharp.SkiaApi.sk_typeface_create_default() + 0x31
   at SkiaSharp.SKTypeface.CreateDefault() + 0x1a

@MichalStrehovsky
Copy link
Member

Did you try copying the DLL to where the EXE is?

@hez2010
Copy link

hez2010 commented Apr 2, 2020

Thanks! After copying native dll to output directory, all issues were gone.

@hez2010
Copy link

hez2010 commented Apr 2, 2020

I managed to get the way to fix the infinite recursive generics in System.Reactive and sent a PR. It will be fixed via dotnet/reactive#1177.

After this PR merged, although CatchScheduler won't work at runtime after compiled with CoreRT since #3460, it can be compiled with CoreRT with no issue.

@hez2010
Copy link

hez2010 commented Apr 2, 2020

@MichalStrehovsky
After above PR merged I test again without <RootAllApplicationAssemblies>false</RootAllApplicationAssemblies>.
This time it can be compiled successfully but failed while linking objects, I got

AvaloniaApp.obj : error LNK2001: unresolved external symbol WindowsCreateString [C:\Users\hez20\source\AvaloniaApp\AvaloniaApp.csproj]
bin\Debug\netcoreapp3.1\win-x64\native\AvaloniaApp.exe : fatal error LNK1120: 1 unresolved externals [C:\Users\hez20\source\AvaloniaApp\AvaloniaApp.csproj]

obj/Debug/netcoreapp3.1/win-x64/native/link.rsp:

"obj\Debug\netcoreapp3.1\win-x64\native\AvaloniaApp.obj"
/OUT:"bin\Debug\netcoreapp3.1\win-x64\native\AvaloniaApp.exe"
/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\ATLMFC\lib\x64"
/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\lib\x64"
/LIBPATH:"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x64"
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\lib\10.0.18362.0\ucrt\x64"
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\lib\10.0.18362.0\um\x64"
"obj\Debug\netcoreapp3.1\win-x64\native\AvaloniaApp.res"
"C:\Users\hez20\.nuget\packages\runtime.win-x64.microsoft.dotnet.ilcompiler\1.0.0-alpha-28802-02\sdk\bootstrapper.lib"
"C:\Users\hez20\.nuget\packages\runtime.win-x64.microsoft.dotnet.ilcompiler\1.0.0-alpha-28802-02\sdk\Runtime.lib"
"C:\Users\hez20\.nuget\packages\runtime.win-x64.microsoft.dotnet.ilcompiler\1.0.0-alpha-28802-02\sdk\System.Private.TypeLoader.Native.lib"
"kernel32.lib"
"ntdll.lib"
"user32.lib"
"gdi32.lib"
"winspool.lib"
"comdlg32.lib"
"advapi32.lib"
"shell32.lib"
"ole32.lib"
"oleaut32.lib"
"uuid.lib"
"bcrypt.lib"
"normaliz.lib"
"crypt32.lib"
/NOLOGO /MANIFEST:NO
/DEBUG
/INCREMENTAL:NO
/SUBSYSTEM:WINDOWS /ENTRY:wmainCRTStartup
/NATVIS:"C:\Users\hez20\.nuget\packages\microsoft.dotnet.ilcompiler\1.0.0-alpha-28802-02\build\CoreRTNatVis.natvis"

@MichalStrehovsky
Copy link
Member

Can you try if adding this to an ItemGroup in your project resolves the linking issue?

      <NativeLibrary Include="runtimeobject.lib" />

@hez2010
Copy link

hez2010 commented Apr 3, 2020

Thank you, the linking issue got resolved after adding <NativeLibrary Include="runtimeobject.lib" />.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants