dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.92k stars 4.64k forks source link

Very Poor ImageSharp Performance in MAUI Android #71210

Open david-maw opened 2 years ago

david-maw commented 2 years ago

Description

A piece of code which executes in under 100 ms in Xamarin forms on Android or Windows and under 50 ms in Windows MAUI takes over 30 seconds in Android MAUI.

Steps to Reproduce

  1. Clone repository https://github.com/david-maw/ResizeImageMaui.git from github
  2. Build the project
  3. Run it on Windows
  4. Click the button, on Windows the image will be converted to greyscale in under a second (50 ms in my case).
  5. Try it again on Android, this time the conversion will take much longer (in my case it was over 30 seconds but less than a minute.

FYI there's a similar Xamarin Forms project at https://github.com/david-maw/ResizeImageXamarin.git, in my testing this took about 90 ms to load on Window (so MAUI was almost twice as fast), and just under a second on the Android emulator (so MAUI was 30+ times slower).

This uses SixLabors.ImageSharp to do the image processing so it is likely the implementation of something in that library that's wildly slow on .NET 6 on Android.

Version with bug

6.0 Release Candidate 3

Last version that worked well

Unknown/Other

Affected platforms

Android, I was not able test on other platforms

Affected platform versions

Android 11

Did you find any workaround?

No

Relevant log output

No response

jfversluis commented 2 years ago

@jonathanpeppers this seems like something for you :)

janseris commented 2 years ago

Did you try Release configuration for the benchmarking?

jonathanpeppers commented 2 years ago

@david-maw yes you should try a Release build, and maybe try "full" AOT:

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
  <RunAOTCompilation>true</RunAOTCompilation>
  <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
</PropertyGroup>

Release builds use profiled AOT by default, and SixLabors.ImageSharp would not be in our built-in profile.

NonameMissingNo commented 2 years ago

@jonathanpeppers Mi 11i (Android): Debug: 35.841 Seconds Release: 7.212 Seconds (2nd run: 7.137 Seconds) Release with full AOT: 7.151 Seconds

For reference Windows (Ryzen 5 5500U): Debug: 210 ms Release: 165 ms

dotnet-issue-labeler[bot] commented 2 years ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

NonameMissingNo commented 2 years ago

Release is a lot better, but I don't think it should be 43 times slower than the windows Release build

jonathanpeppers commented 2 years ago

@NonameMissingNo did you already get a .speedscope file, to see where the problem is?

https://github.com/xamarin/xamarin-android/blob/main/Documentation/guides/tracing.md

I'll do this myself when I get a chance to look at this, but that might point out specifically where the problem is.

david-maw commented 2 years ago

@janseris no, I wasn't actually trying to benchmark, I was trying to debug some code which calls SixLabors.ImageSharp, I did give it a try with the additions suggested by @jonathanpeppers though, alas release builds do not seem to be working for me. This one fails with

1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Mono Ahead of Time compiler - compiling assembly C:\Users\david\Documents\Develop\Samples\ResizeImageMaui\ResizeImageMaui\obj\Release\net6.0-android\android-arm\aot-in\Mono.Android.dll
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : AOTID AE96AD80-0388-6F60-8F1D-297A5B9027D9
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Compiled: 155736/155736
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Executing the native assembler: "C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\tools\binutils\arm-linux-androideabi-as"   -mfpu=vfp3 -o obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp.s.o obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp.s
1>Done building project "ResizeImageMaui.csproj" -- FAILED.

Not much of a problem for me actually, I'm mostly interested in debug builds, I don't move to a release build until the pre-release performance checks.

Just as well @NonameMissingNo tested it, thanks for that.

jonathanpeppers commented 2 years ago

@david-maw if a general Release build fails, you might file an issue here with a diagnostic MSBuild log:

https://github.com/xamarin/xamarin-android/issues

Thanks!

NonameMissingNo commented 2 years ago

@jonathanpeppers It would seem like that the ImageSharp is the one doing the work image maui-app_20220616_184909.speedscope.zip

jonathanpeppers commented 2 years ago

Thanks!

So I wonder if the code here:

https://github.com/SixLabors/ImageSharp/blob/7bd0e03792d2b5141fcfb046cb92329e9c0df582/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs#L168-L199

I bet there are some runtime optimizations for Span/Vector4 that we have on Windows + CoreClr, and we don't have those in Mono.

david-maw commented 2 years ago

@jonathanpeppers

Thanks for the hint on the diagnostic MSBuild Log. I'll look into the Release build issue a bit more and file a bug if it does not seem to be a local problem. The issue was building the MAUI Android version, not Xamarin.Forms Android. The error was in the AOT compiler which is presumably why the Debug build was ok.

Back to the original topic,

The Xamarin.Forms Android Release Build completed the second and subsequent image conversions in under 500 ms and a Debug build took 1.5 s, both a far cry from the MAUI Android numbers (just over 33 s for Debug, I can't test Release).

If the Android performance differential is a mono limitation why is the performance of the same app in Xamarin so much better? Is it that it is a different Mono version?

jonathanpeppers commented 2 years ago

Debug builds also default to UseInterpreter=true (this enables hot reload). This isn't an option at all in Xamarin.

So you could turn it off in your project, but then hot reload wouldn't work either.

david-maw commented 2 years ago

Thanks, that would probably work for the occasional test but so far at least it looks easier said than done, since for now isn't recognized (I note there are a number of Issues relating to handling it for multi-targeted project files.

jonathanpeppers commented 2 years ago

I had a conversation with some of the Mono folks -- going to move this to dotnet/runtime.

jonathanpeppers commented 2 years ago

/cc @steveisok @lambdageek

lambdageek commented 2 years ago
  1. We should try running this on the net7 runtime packs. There's been arm64 intrinsics work in net7 in mono.
  2. The code that @jonathanpeppers pointed out (https://github.com/SixLabors/ImageSharp/blob/7bd0e03792d2b5141fcfb046cb92329e9c0df582/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs#L168-L199) looks like it could be tested in a console app. that should make it easier to look at what the JIT is doing.
ghost commented 2 years ago

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger See info in area-owners.md if you want to be subscribed.

Issue Details
### Description A piece of code which executes in under 100 ms in Xamarin forms on Android or Windows and under 50 ms in Windows MAUI takes over 30 seconds in Android MAUI. ### Steps to Reproduce 1. Clone repository https://github.com/david-maw/ResizeImageMaui.git from github 2. Build the project 3. Run it on Windows 4. Click the button, on Windows the image will be converted to greyscale in under a second (50 ms in my case). 5. Try it again on Android, this time the conversion will take much longer (in my case it was over 30 seconds but less than a minute. FYI there's a similar Xamarin Forms project at https://github.com/david-maw/ResizeImageXamarin.git, in my testing this took about 90 ms to load on Window (so MAUI was almost twice as fast), and just under a second on the Android emulator (so MAUI was 30+ times slower). This uses SixLabors.ImageSharp to do the image processing so it is likely the implementation of something in that library that's wildly slow on .NET 6 on Android. ### Version with bug 6.0 Release Candidate 3 ### Last version that worked well Unknown/Other ### Affected platforms Android, I was *not* able test on other platforms ### Affected platform versions Android 11 ### Did you find any workaround? No ### Relevant log output _No response_
Author: david-maw
Assignees: -
Labels: `area-CoreLib-mono`, `os-ios`
Milestone: -
ghost commented 2 years ago

Tagging subscribers to 'arch-android': @steveisok, @akoeplinger See info in area-owners.md if you want to be subscribed.

Issue Details
### Description A piece of code which executes in under 100 ms in Xamarin forms on Android or Windows and under 50 ms in Windows MAUI takes over 30 seconds in Android MAUI. ### Steps to Reproduce 1. Clone repository https://github.com/david-maw/ResizeImageMaui.git from github 2. Build the project 3. Run it on Windows 4. Click the button, on Windows the image will be converted to greyscale in under a second (50 ms in my case). 5. Try it again on Android, this time the conversion will take much longer (in my case it was over 30 seconds but less than a minute. FYI there's a similar Xamarin Forms project at https://github.com/david-maw/ResizeImageXamarin.git, in my testing this took about 90 ms to load on Window (so MAUI was almost twice as fast), and just under a second on the Android emulator (so MAUI was 30+ times slower). This uses SixLabors.ImageSharp to do the image processing so it is likely the implementation of something in that library that's wildly slow on .NET 6 on Android. ### Version with bug 6.0 Release Candidate 3 ### Last version that worked well Unknown/Other ### Affected platforms Android, I was *not* able test on other platforms ### Affected platform versions Android 11 ### Did you find any workaround? No ### Relevant log output _No response_
Author: david-maw
Assignees: -
Labels: `os-android`, `area-Codegen-meta-mono`, `os-ios`
Milestone: 7.0.0
steveisok commented 2 years ago

@mkhamoyan The work we did for arm64 intrinsics only applies for AOT+LLVM. Android currently does not use LLVM when they run profiled AOT. That is something @jonathanpeppers is going to work on. Once he enables it, we can pick this back up and validate against .NET 7.

jonathanpeppers commented 2 years ago

You can set <EnableLLVM>true</EnableLLVM> in your project, if you would like to try it in the current .NET 6 release.

We're investigating if this can be on by default, because not many would use it otherwise.

eddyjd commented 2 years ago

Any progress with this? I'm having very poor ImageSharp performance in MAUI Android as well. Just opening a jpg takes between 40 and 50 seconds.

This is the code that appears to takes long in the HuffmanScanDecoder.cs module:

    private void ParseBaselineDataInterleaved()
    {
        int mcu = 0;
        int mcusPerColumn = this.frame.McusPerColumn;
        int mcusPerLine = this.frame.McusPerLine;
        ref JpegBitReader buffer = ref this.scanBuffer;

        for (int j = 0; j < mcusPerColumn; j++)
        {
            this.cancellationToken.ThrowIfCancellationRequested();

            // decode from binary to spectral
            for (int i = 0; i < mcusPerLine; i++)
            {
                // Scan an interleaved mcu... process components in order
                int mcuCol = mcu % mcusPerLine;
                for (int k = 0; k < this.scanComponentCount; k++)
                {
                    int order = this.frame.ComponentOrder[k];
                    var component = this.components[order] as JpegComponent;

                    ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DcTableId];
                    ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.AcTableId];

                    int h = component.HorizontalSamplingFactor;
                    int v = component.VerticalSamplingFactor;

                    // Scan out an mcu's worth of this component; that's just determined
                    // by the basic H and V specified for the component
                    for (int y = 0; y < v; y++)
                    {
                        Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y);
                        ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);

                        for (int x = 0; x < h; x++)
                        {
                            if (buffer.NoData)
                            {
                                // It is very likely that some spectral data was decoded before we've encountered 'end of scan'
                                // so we need to decode what's left and return (or maybe throw?)
                                this.spectralConverter.ConvertStrideBaseline();
                                return;
                            }

                            int blockCol = (mcuCol * h) + x;

                            this.DecodeBlockBaseline(
                                component,
                                ref Unsafe.Add(ref blockRef, blockCol),
                                ref dcHuffmanTable,
                                ref acHuffmanTable);
                        }
                    }
                }

                // After all interleaved components, that's an interleaved MCU,
                // so now count down the restart interval
                mcu++;
                this.HandleRestart();
            }

            // Convert from spectral to actual pixels via given converter
            this.spectralConverter.ConvertStrideBaseline();
        }
    }
eddyjd commented 2 years ago

During my testing mcusPerColumn = 120 and mcusPerLine = 252 So the "// decode from binary to spectral" section loops 30240 times.

jonathanpeppers commented 2 years ago

@eddyjd did you try a Release build with EnableLLVM enabled? https://github.com/dotnet/runtime/issues/71210#issuecomment-1178060240

eddyjd commented 2 years ago

Just tried that, huge improvement. The whole process of what I was trying to do (which includes sending the image to a remote server) now only takes about 8 seconds. I can live with performance issue while debugging. Thanks.

jonathanpeppers commented 2 years ago

Ok, great. We're thinking EnableLLVM=true is the solution here for Android, as that is where you'll get better support for "vectorization" like ImageSharp is using.

We're looking into making EnableLLVM=true the default in a future .NET release.

antonfirsov commented 2 years ago

This is ~likely~ could be caused by the mono runtime running generic code that is not "pre-seeded". See #52559. The mono runtime falls back to extremely slow implementations to run such code.

steveisok commented 2 years ago

Glad you found enabling LLVM to make things faster. Most of our perf gains will be found with LLVM on. As a result, I'm going to close this issue.

david-maw commented 2 years ago

@steveisok when I tried enabling LLVM and rebuilding the example I provided earlier using a release build the build failed (abbreviated output below). Since MAUI in .NET 6 has enough open problems I can't go to production with it anyway I'd decided to wait until .NET 7 to worry about this issue, but just in case it matters...

Build started...
1>------ Build started: Project: ResizeImageMaui, Configuration: Release Any CPU ------
1>You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
1>Skipping analyzers to speed up the build. You can execute 'Build' or 'Rebuild' command to run analyzers.
1>ResizeImageMaui -> C:\Users\david\Documents\Develop\Samples\ResizeImageMaui\ResizeImageMaui\bin\Release\net6.0-android\ResizeImageMaui.dll
1>[1/266] ResizeImageMaui.dll -> ResizeImageMaui.dll.so
1>[1/266] System.Net.NameResolution.dll -> System.Net.NameResolution.dll.so, System.Net.NameResolution.dll-llvm.o
1>[1/266] ResizeImageMaui.dll -> ResizeImageMaui.dll.so, ResizeImageMaui.dll-llvm.o
1>[2/266] Microsoft.CSharp.dll -> Microsoft.CSharp.dll.so
.
.
.
1>[262/266] Xamarin.Kotlin.StdLib.Jdk7.dll -> Xamarin.Kotlin.StdLib.Jdk7.dll.so, Xamarin.Kotlin.StdLib.Jdk7.dll-llvm.o
1>[263/266] Xamarin.Kotlin.StdLib.Jdk8.dll -> Xamarin.Kotlin.StdLib.Jdk8.dll.so, Xamarin.Kotlin.StdLib.Jdk8.dll-llvm.o
1>[264/266] Xamarin.KotlinX.Coroutines.Android.dll -> Xamarin.KotlinX.Coroutines.Android.dll.so, Xamarin.KotlinX.Coroutines.Android.dll-llvm.o
1>[265/266] Xamarin.KotlinX.Coroutines.Core.Jvm.dll -> Xamarin.KotlinX.Coroutines.Core.Jvm.dll.so, Xamarin.KotlinX.Coroutines.Core.Jvm.dll-llvm.o
1>[266/266] System.Private.CoreLib.dll -> System.Private.CoreLib.dll.so, System.Private.CoreLib.dll-llvm.o
1>[Mono.Android.dll] Exec (with response file contents expanded) in C:\Users\david\Documents\Develop\Samples\ResizeImageMaui\ResizeImageMaui: MONO_PATH=C:\Users\david\Documents\Develop\Samples\ResizeImageMaui\ResizeImageMaui\obj\Release\net6.0-android\android-arm\aot-in; MONO_ENV_OPTIONS= C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.android-arm\6.0.6\Sdk\..\tools\mono-aot-cross.exe --debug --llvm "--aot=asmwriter,temp-path=obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android,nodebug,llvm-path=C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.android-arm\6.0.6\Sdk\..\tools,mtriple=armv7-linux-gnueabi,tool-prefix=C:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\arm-linux-androideabi-,outfile=obj\Release\net6.0-android\android-arm\aot\Mono.Android.dll.so,llvm-outfile=obj\Release\net6.0-android\android-arm\aot\Mono.Android.dll-llvm.o,ld-name=ld.EXE,ld-flags=\"-LC:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\";\"-LC:\Program Files (x86)\Android\android-sdk\ndk-bundle\platforms\android-21\arch-arm\usr\lib\";\"-LC:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\..\sysroot\usr\lib\arm-linux-androideabi\";\"C:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\libgcc.a\";\"C:\Program Files (x86)\Android\android-sdk\ndk-bundle\platforms\android-21\arch-arm\usr\lib\libc.so\";\"C:\Program Files (x86)\Android\android-sdk\ndk-bundle\platforms\android-21\arch-arm\usr\lib\libm.so\" -s" "obj\Release\net6.0-android\android-arm\aot-in\Mono.Android.dll"
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Precompiling failed for C:\Users\david\Documents\Develop\Samples\ResizeImageMaui\ResizeImageMaui\obj\Release\net6.0-android\android-arm\aot-in\Mono.Android.dll.
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : C:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\arm-linux-androideabi-ld.EXE: internal error in arm_branch_common, at /buildbot/src/android/binutils/toolchain/binutils/binutils-2.27/gold/arm.cc:4063
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : AOT of image obj\Release\net6.0-android\android-arm\aot-in\Mono.Android.dll failed.
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Mono Ahead of Time compiler - compiling assembly C:\Users\david\Documents\Develop\Samples\ResizeImageMaui\ResizeImageMaui\obj\Release\net6.0-android\android-arm\aot-in\Mono.Android.dll
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : AOTID 30948110-ED14-453C-C97F-9C54458A4135
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Executing opt: "C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.android-arm\6.0.6\Sdk\..\tools\opt" -f -O2 -disable-tail-calls -place-safepoints -spp-all-backedges -o "obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp.opt.bc" "obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp.bc"
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Executing llc: "C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.android-arm\6.0.6\Sdk\..\tools\llc"  -enable-implicit-null-checks -disable-fault-maps -mattr=+vfp2,-neon -asm-verbose=false -mtriple=armv7-linux-gnueabi -disable-gnu-eh-frame -enable-mono-eh-frame -mono-eh-frame-symbol=mono_aot_Mono_Android_eh_frame -disable-tail-calls -relocation-model=pic -filetype=obj -o "obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp-llvm.o" "obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp.opt.bc"
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Compiled: 155741/155741
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Executing the native assembler: "C:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\arm-linux-androideabi-as"   -mfpu=vfp3 -o obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp.s.o obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp.s
1>C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\32.0.415\targets\Microsoft.Android.Sdk.Aot.targets(78,5): error : Executing the native linker: "C:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\arm-linux-androideabi-ld.EXE" -Bsymbolic -shared -o obj\Release\net6.0-android\android-arm\aot\Mono.Android.dll.so.tmp "obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp-llvm.o" obj\Release\net6.0-android\android-arm\aot\armeabi-v7a\Mono.Android\temp.s.o "-LC:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x" "-LC:\Program Files (x86)\Android\android-sdk\ndk-bundle\platforms\android-21\arch-arm\usr\lib" "-LC:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\..\sysroot\usr\lib\arm-linux-androideabi" "C:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\libgcc.a" "C:\Program Files (x86)\Android\android-sdk\ndk-bundle\platforms\android-21\arch-arm\usr\lib\libc.so" "C:\Program Files (x86)\Android\android-sdk\ndk-bundle\platforms\android-21\arch-arm\usr\lib\libm.so" -s
1>Done building project "ResizeImageMaui.csproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
========== Deploy: 0 succeeded, 0 failed, 0 skipped ==========
janseris commented 2 years ago

Just tried that, huge improvement. The whole process of what I was trying to do (which includes sending the image to a remote server) now only takes about 8 seconds. I can live with performance issue while debugging. Thanks.

Why cant you resize using MAUI Graphics? Resize now works on Android (or in next release, cant remember)

eddyjd commented 2 years ago

Just tried that, huge improvement. The whole process of what I was trying to do (which includes sending the image to a remote server) now only takes about 8 seconds. I can live with performance issue while debugging. Thanks.

Why cant you resize using MAUI Graphics? Resize now works on Android (or in next release, cant remember)

If you're replying to me, my use is different than david-maw's. All I wanted to do was modify the Exif data for an image and ImageSharp is the only way I've been able to get it done so far.

david-maw commented 2 years ago

As far as i know you can resize using MAUI graphics in my case I needed to resize and convert to greyscale to minimize the image size. It also turned out I had to correct the orientation value in the EXIF data, but I think that was probably a bug.

I was experimenting with migrating existing code to MAUI so rewriting it wasn't the objective, when MAUI gets to the point where I can consider using it in production (which is a few bug fixes away, for me at least) image processing is on the list of things I could do differently there.

JimBobSquarePants commented 2 years ago

Are we sure closing this is wise? Even with LLVM enabled those numbers are alarmingly high.

janseris commented 2 years ago

Just tried that, huge improvement. The whole process of what I was trying to do (which includes sending the image to a remote server) now only takes about 8 seconds. I can live with performance issue while debugging. Thanks.

Why cant you resize using MAUI Graphics? Resize now works on Android (or in next release, cant remember)

If you're replying to me, my use is different than david-maw's. All I wanted to do was modify the Exif data for an image and ImageSharp is the only way I've been able to get it done so far.

True, MAUI graphics just silently drops all exif data (most importantly, the rotation/orientation property) (reported) and does not offer a way to read/save/modify. I am however using ExifLibrary successfully for that with relatively good performance. Maybe you can try that one. (my use case is manually reading exif before jpg resize and putting it back after resize)

vargaz commented 2 years ago

This is ~likely~ could be caused by the mono runtime running generic code that is not "pre-seeded". See #52559. The mono runtime falls back to extremely slow implementations to run such code.

That issue is for ios which doesn't have a JIT so it has to aot all instantiations, android does have a JIT.

vargaz commented 2 years ago

Some code like this only supports avx: https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs#L163 and the fallback to Vector4 is not intrinsified on mono in 6.0.

vargaz commented 2 years ago

This is ~likely~ could be caused by the mono runtime running generic code that is not "pre-seeded". See #52559. The mono runtime falls back to extremely slow implementations to run such code.

That issue is for ios which doesn't have a JIT so it has to aot all instantiations, android does have a JIT.

So it does look like that problem is related, because to get good performance requires AOTing with LLVM, and the AOT compiler might not AOT these instantiations.

mkhamoyan commented 2 years ago

Assigning to @vargaz as issues are related.

SamMonoRT commented 2 years ago

From the mono runtime side - There is ongoing work to fix some issues in 7.0 causing some failures with LVM on Android. Along with that, we recently added Vector4 Intrinsics for Arm64 platform. We should re-evaluate the perf numbers once we fix the llvm related issues.

cc @BrzVlad - related to slower interpreter comments above.

JimBobSquarePants commented 2 years ago

Vector4 Intrinsics for Arm64 platform

Now I just need to add ARM64 intrinsics and somehow snag a CI platform to test them in!

fanyang-mono commented 2 years ago

Arm64 intrinsics for Vector4 has been added via https://github.com/dotnet/runtime/pull/72124

hez2010 commented 2 years ago

Maybe in long term we can extend CoreCLR and NativeAOT to support mobile platforms, so that we won't need to suffer from plenty of performance issues of mono?

jjxtra commented 1 year ago

Seeing same poor performance on iOS release builds. Takes 20 seconds to load a png that is 1024x1024. Very odd. Using MAUI .NET 7 in VC MAC 2022, AOT and LLVM enabled.

jjxtra commented 1 year ago

Switched to skiasharp and performance is 100x better

JimBobSquarePants commented 1 year ago

That’s expected since the actual operating code is not powered by the runtime and doesn’t suffer from this issue. On a desktop with a working JIT ImageSharp will comfortably beat SkiaSharp’s performance for both resizing and matrix color transformation

3egirlsdream commented 1 year ago

when can fix this bug?

jjxtra commented 1 year ago

Use skiasharp

JimBobSquarePants commented 1 year ago

That’s not a very productive answer is it?

Managed code should work well cross platform. If there are issues then that is due to limitations of the AOT compiler.

hez2010 commented 1 year ago

is due to limitations of the AOT compiler

The issue is mono-specific, not AOT-specific. I tried NativeAOT and didn't find any performance issues with ImageSharp. The performance of given repro in the top post is parity between RyuJIT and NativeAOT (both under 50ms).

mjsb212 commented 1 year ago

Just ran into this same issue when I ported my Xamarin project to MAUI. Tested with .net 6 & 7 (MAUI) running on ANDROID. ImageSharp loading any files is SUPER SLOW - On XAMARIN everything still loads fine as expected. The original Xamarin code ported to MAUI:

FileStream fs = new FileStream(file.FullPath, FileMode.Open, FileAccess.Read); Image image = SixLabors.ImageSharp.Image.Load(fs);

...Takes about 20 - 30 SECONDS to load any image into stream