Skip to content
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

Dotnet 8, Avalonia UI migration #617

Open
praful-hunde opened this issue Dec 12, 2023 · 11 comments
Open

Dotnet 8, Avalonia UI migration #617

praful-hunde opened this issue Dec 12, 2023 · 11 comments

Comments

@praful-hunde
Copy link

praful-hunde commented Dec 12, 2023

The Problem
The current Dotnet framework build works great for the purpose. But for large source code with hundreds of .RESX files, the first read takes a few minutes. In my case reading more than 20k entries from a few hundred files takes about 2.5 minutes. As per observation, the subsequent reads are faster and only take a few seconds. However, the first read is more painful for daily use. There is indeed no need to read all RESX files every time, for typical use. However, we do it to reuse the translations from the past. This feature is in our internal copy of the code. The existing translations can be re-used if an exact match is found. The motivation is to avoid the double cost of translations by a third party.

The Solution
Migrating to Dotnet 8 is one potential solution. My collogue tried a PoC with Dotnet 8 and Avalonia UI to check read and render performance. With AOT build the app is blazingly fast, even for the first read. The code is available at https://github.com/sps014/Localizer.
Apart from gaining performance potentially, the tool can become cross-platform by adopting Dotnet 8 and Avalonia UI

The alternatives
In my local copy, I could gain performance benefits with Parallel Foreach, PLINQ, and WPF Async binding. The performance improvement is not as significant as observed in PoC. But this is still can be a good gain with minimal changes.

@tom-englert
Copy link
Collaborator

@praful-hunde

As per observation, the subsequent reads are faster and only take a few seconds

The first read is slow because all files need to be read from disk. The second read is faster, because the OS has cached the files. So I wonder how DotNet 8 can improve this.

And if we don't read all RESX files, how can we detect missing entries?

@sps014
Copy link

sps014 commented Dec 13, 2023

Hello @tom-englert,

With the introduction of .NET 8, a multitude of performance enhancements have been implemented. These improvements become particularly noticeable when compared to the .NET Framework.

By utilizing Ahead-of-Time (AOT) compilation when building your application, you can reap the benefits of faster startup times and improved performance. Furthermore, AOT compilation of ResourceReader and Writer (using a custom implementation with XDocument) also contributed to superior performance.

@tom-englert
Copy link
Collaborator

@praful-hunde
Copy link
Author

@tom-englert My understanding is the same as yours i.e. subsequent reads must be faster due to the OS cache. The file read time with AOT and DotNet framework should be same. I did a quick test with a set of 2K .resx files for three languages, each with ten strings. So total (2000x10x3) 60K strings. Time measured with a stopwatch. So, it is approx. value. The RESX Manager took 15 seconds and Localizer PoC took less than 2.5 seconds. I have no clear understanding about the reasons. These readings were for subsequent reads. The time is for read + render.
It will be interesting if there are reasons to prefer docker to distribute RESX Manger. Post migration DotNet Framework, DOTNET 8 & AOT builds seems to be possible with same code. In my view migration can be two step first to DOTNET 8 (WPF remains) and then Avalonia. Getting app on Linux and OSx is also a considerable benefit.

@tom-englert
Copy link
Collaborator

Maybe the difference here is because you compare an minimal prototype with a full featured application.
Integrity and consistency checks, validation, filtering, spell checking etc. all take some time, that you don't spent in your prototype.

Also to mention: The primary use case is Visual Studio extension, the standalone app is just a nice to have side effect, so before starting any migration, we would have to ensure this will still run in the context of Visual Studio. Maybe https://learn.microsoft.com/en-us/visualstudio/extensibility/visualstudio.extensibility/visualstudio-extensibility is the key to run an extension out of process.

@tom-englert
Copy link
Collaborator

To get the diff between NetFramework and DotNet8, you can just add Net8 to the target frameworks of the projects in ResXManager, then you can try it for both frameworks with ResXManager.

@tom-englert
Copy link
Collaborator

@praful-hunde any new findings?

@praful-hunde
Copy link
Author

praful-hunde commented Dec 28, 2023

@tom-englert & @sps014 So far findings are as below:

  1. The WPF build is Windows-specific which means it is not portable. The TargetFramework identifier is "net8.0-windows".
  2. If the AOT flag is enabled, trimming is also enabled implicitly. For WPF app trimming is not supported. It is not supported to disable trimming with AOT. So AOT is not supported for WPF apps with .net8. Trimming incapabilities are listed here. It is also mentioned that there is an issue in progress for WPF-specific limitations. So, there is a chance that the limitation will be removed in the future. A similar issue is there for Windows Forms as well.
  3. For the Nuget package "WindowsAPICodePack-Shell" the .net8 version is not resolved. This generates a warning.
  4. I got this error -> MSBUILD: error: Fody: PEVerify of the assembly failed. Not sure exactly why.
  5. A build with target "net8.0-windows" was feasible without AOT. However, with two issues, A) multi-targeting with .net472 was not building B) The test project was failing to build even if the target is set the same as "net8.0-windows".
  6. Not 100% sure but the mentioned issues may be solvable, but it's not possible to enable AOT with WPF. Replacing WPF unfortunately may not be possible quickly, even with Avalonia.
  7. By observation .net8 build performed similar to .net472.

@shapeh
Copy link

shapeh commented Feb 16, 2024

My two cents:

Would it be possible to disable many of the features, so that they do not start up immediately?

I too get very slow performance in Visual Studio using the vsix extension.
The standalone version performs much better.

  • Tested on my normal dev machine: Core i9-12950HX, 64 Gb DDR5 mem, and a Samsung SSD 990 Pro disk.
  • 6 files resx files in project (neutral base language English, and 5 additional languages).
  • All values are short / less than 20 words, and most are around 1-3 words.
  • Total amount of values for one language: 750, so total 4500 for all languages.

@tom-englert
Copy link
Collaborator

Would it be possible to disable many of the features, so that they do not start up immediately?

What features are you thinking of?

The time on startup is spent on enumerating all files in the project and collecting the .resx files.

In the standalone version the file system is used to enumerate all files, while in Visual Studio the DTE interfaces are used to enumerate all projects and their files, so here it's Visual Studio causing some slow down.

However file system seems to be the bottle neck, even in Visual Studio when opening the solution a second time it is much faster.

@shapeh
Copy link

shapeh commented Feb 16, 2024

I am not sure what features - it's all good :)

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

No branches or pull requests

4 participants