xamarin-macios/tests
Alex Soto 73038144e7
[net9.0] Reenable dedup optimization for all AOT modes (#20941)
Backport of #20936

---

## Description

As part of the fix for: https://github.com/dotnet/runtime/issues/99248
we disabled dedup optimization in partial/hybrid AOT mode (when both
interpreter and AOT compiler are enabled). This change got backported to
.NET 8 and with the latest servicing release regressed build times and
app sizes significantly as reported in:
https://github.com/xamarin/xamarin-macios/issues/20848

However, it turns out that disabling dedup optimization is not required
to fix https://github.com/dotnet/runtime/issues/99248 but instead we
should correct the Xamarin SDK integration with this optimization which
this PR is doing. The following section describes the initial problem in
more details.

## Overview of AOT modes and dedup optimization

When the repro project from
https://github.com/dotnet/runtime/issues/99248 is built with dedup
enabled in hybrid AOT+interpreter mode, the app crashes with:
```
024-07-23 14:32:37.524110+0200 IvansApp[12711:20244208] debug: AOT NOT FOUND: (wrapper other) object:gsharedvt_out_sig (intptr).
2024-07-23 14:32:37.524120+0200 IvansApp[12711:20244208] error: * Assertion at /Users/ivan/repos/runtime-mono-iOS/src/mono/mono/mini/interp/interp.c:2667, condition `is_ok (error)' not met, function:init_jit_call_info, Attempting to JIT compile method '(wrapper other) void object:gsharedvt_out_sig (intptr)' while running in aot-only mode. See https://learn.microsoft.com/xamarin/ios/internals/limitations for more information.
```

To track down why these wrappers which are used to transition from
interpreter to AOT code, are not generated we need to understand when
they are compiled in different AOT modes with and without dedup
optimization enabled:

- In full AOT setup - all assemblies AOT compiled
    - `gsharedvt_out_sig` methods are never generated

- In hybrid AOT + interpreter setup - all assemblies AOT compiled:
`MtouchInterpreter=-all`
    - Dedup OFF:
- `gsharedvt_out_sig` methods are generated in AOT images of every
assembly (to enable interpreter calling into each specific assembly -
here wrappers with same signatures are duplicated)
    - Dedup ON:
- `gsharedvt_out_sig` methods are generated only in `aot-instances` AOT
image
- during AOT compilation of individual assemblies generation of
`gsharedvt_out_sig` is skipped
- during AOT compilation of `aot-instances` assembly we collect all
`gsharedvt_out_sig` variants from the full program scope and generate
code for them in `aot-instances` AOT image

- In hybrid AOT + interpreter setup - all assemblies interpreted except
a given assembly: `MtouchInterpreter=all,-MyAssembly`
    - Dedup OFF:
- `gsharedvt_out_sig` methods are generated in AOT image of `MyAssembly`
(to enable interpreter calling into it)
    - Dedup ON: <- $${\color{red} ISSUE }$$ 
- `gsharedvt_out_sig` methods *should* be generated only in
`aot-instances` AOT image, but the `aot-instances` image is missing
    - explanation:
- what happens is that generation of `gsharedvt_out_sig` is skipped
during AOT compilation of `MyAssembly` (as expected).
- But, the build does not mark `aot-instances` assembly as the one that
should be AOT compiled.
- The reason for this is that we have a global `_IsDedupEnabled` flag,
but when custom linker step analysis `aot-instances.dll` it does not see
it as an assembly which should not be interpreted.
- To explain that better: we mark *all* assemblies as to be interpreted
(via: `MtouchInterpreter=all`), but exclude only `MyAssembly` (via:
`MtouchInterpreter=all,-MyAssembly`).
- So when custom linker step processes `aot-instaces.dll` it treats it
as an assembly to be interpreted, so it does not mark it for AOT
compilation.
- This further results with `aot-instances` AOT image missing, and all
the methods which we skipped during AOT compilation never get generated.

## The fix

To fix this and address regressions reported in:
https://github.com/xamarin/xamarin-macios/issues/20848 we are reenabling
dedup optimization whenever AOT compilation is requested and fixing the
issue where the custom linker step for generating AOT parameters always
treates the dedup assembly as the one to be AOTed.

Once approved this should be backported to .NET 8 as servicing releases
are also affected with it.

---------

Co-authored-by: Ivan Povazan <ivan.povazan@gmail.com>
Co-authored-by: GitHub Actions Autoformatter <github-actions-autoformatter@xamarin.com>
2024-07-26 14:47:25 -04:00
..
.nuget/packages
BundledResources
EmbeddedResources
api-shared [monotouch-test] Sprinkle UnconditionalSuppressMessage wherever needed to fix trimmer warnings. (#20429) 2024-04-16 17:03:36 +02:00
bcl-test [tests] Bump min OS versions in all tests. 2024-01-29 15:24:30 +01:00
bgen [bgen] Add support for binding constructors in protocols. Fixes #14039. (#20583) 2024-05-24 11:29:53 +02:00
bindings-framework-test [tests] Skip framework-test on iOS and tvOS. (#20590) 2024-05-30 10:34:14 +02:00
bindings-test [xcode15.3] Bump to Xcode 15.3 bindings (#20780) 2024-07-11 11:41:31 +02:00
bindings-test2
bindings-xcframework-test [tests] Skip framework-test on iOS and tvOS. (#20590) 2024-05-30 10:34:14 +02:00
cecil-tests [xcode15.4] Update bindings to Xcode 15.4 (#20865) 2024-07-11 14:09:52 -04:00
common Merge remote-tracking branch 'origin/main' into net9.0 2024-07-19 15:26:35 -04:00
dotnet [net9.0] Reenable dedup optimization for all AOT modes (#20941) 2024-07-26 14:47:25 -04:00
framework-test [tests] Bump min OS versions in all tests. 2024-02-28 12:08:24 +01:00
fsharp [tests] Bump min OS versions in all tests. 2024-01-29 15:24:30 +01:00
fsharplibrary
generator [net9.0] Merge main into net9.0. 2024-07-08 18:45:06 +02:00
interdependent-binding-projects [tests] Bump min OS versions in all tests. 2024-01-29 15:24:30 +01:00
introspection Merge remote-tracking branch 'xamarin/main' into dev/alex/main-net9.0 2024-07-11 18:53:54 -04:00
linker [net9.0] Update dependencies from dotnet/sdk (#20794) 2024-07-11 19:58:14 +02:00
mac-binding-project [tests] Bump min OS versions in all tests. 2024-02-28 12:08:24 +01:00
misc
mmp-regression [tests] Bump min OS versions in all tests. 2024-02-28 12:08:24 +01:00
mmptest [test] Ignore mmp test that doesn't work anymore. 2024-02-28 12:09:27 +01:00
mono-native [tests] Bump min OS versions in all tests. 2024-02-28 12:08:24 +01:00
monotouch-test Merge remote-tracking branch 'origin/main' into net9.0 2024-07-19 15:26:35 -04:00
msbuild [net9.0] Merge main into net9.0. 2024-06-21 11:19:27 +02:00
mtouch Merge remote-tracking branch 'xamarin/main' into dev/alex/main-net9.0 2024-07-11 18:53:54 -04:00
perftest [tests] Bump min OS versions in all tests. 2024-02-28 12:08:24 +01:00
qa-regression [tests] Bump min OS versions in all tests. 2024-02-28 12:08:24 +01:00
sampletester [tests] Bump min OS versions in all tests. 2024-01-29 15:24:30 +01:00
scripted
scriptingbridge
templates [tests] Bump min OS versions in all tests. 2024-01-29 15:24:30 +01:00
test-libraries Merge remote-tracking branch 'xamarin/main' into dev/alex/main-net9.0 2024-07-11 18:53:54 -04:00
xammac_tests [tests] Bump min OS versions in all tests. 2024-02-28 12:08:24 +01:00
xcframework-test [tests] Bump min OS versions in all tests. 2024-02-28 12:08:24 +01:00
xharness Merge remote-tracking branch 'xamarin/main' into dev/alex/main-net9.0 2024-07-11 18:53:54 -04:00
xtro-sharpie [xtro] Get libclang-mono.dylib from where sharpie is. (#20815) 2024-07-12 18:40:21 +02:00
.gitignore
ComputeRegistrarConstant.targets
Directory.Build.props [tests] Update 'KnownFrameworkReference' and 'KnownRuntimePack' to the reference the correct dotnet/runtime version when using a custom dotnet/runtime. (#20838) 2024-07-09 14:17:58 +02:00
Directory.Build.targets [dotnet] Limit custom dotnet/runtime selection to the current .NET version. (#20840) 2024-07-10 16:30:34 +02:00
HtmlTransform.xslt
Makefile [xharness] Add launch.json/tasks.json for xharness. (#20428) 2024-04-16 17:36:15 +02:00
README.md
nunit.framework.targets [msbuild] Unify MonoBundlingExtraArgs and MtouchExtraArgs into AppBundleExtraOptions. Fixes #12807. (#20594) 2024-05-28 14:57:52 +02:00
nunit.framework.xml
package-dotnet-tests.sh
package-mac-tests.sh [tests] Fix condition to not build packaged macOS tests in parallel in CI. (#19838) 2024-01-19 14:35:29 -05:00
packaged-macos-tests.mk
run-with-timeout.csharp Simplify argument logic in the C# scripts. (#19805) 2024-01-15 16:51:36 +01:00
run-with-timeout.sh
test-dependencies.sh
tests-mac.sln
tests.sln

README.md

Various tests to be executed prior to releases

Test permissions

There are a number of tests that acccess the file system and the bluetooh. For these tests to correctly execute you have to ensure that the terminal application that you are using to execute the tests has access to the full filesystem and the bluetooth. If you do not do this step the macOS tests will crash.

Test solutions

Many of the test solutions and test projects are generated, and will only be available after running make once.

  • tests.sln: This is the base test solution for Xamarin.iOS, which targets iOS using the Unified API. Not generated.
  • tests-tvos.sln: All the TVOS test projects. Generated.
  • tests-watchos.sln: All the WatchOS test projects. Generated.
  • tests-mac.sln: This is the base test solution for Xamarin.Mac. Not generated.

Test solution/project generation

The tool that generates the test solutions / projects is called xharness, and lives in the xharness subdirectory.

Types of Tests

Unit Tests

Most of the projects are using NUnit[Lite] and looks like unit tests. They are meant to be executed on the target: simulator, devices, OSX.

In reality most of them are regression tests - but that does not change the need to execute and continually expand them to cover new code.

Introspection Tests

Introspection tests are executed on target (both simulator and device for iOS) or a specific version of OSX. The application proceed to analyze itself using:

  • System.Reflection for managed code; and
  • the ObjectiveC runtime library for native code

and compare the results. E.g. if using .NET reflection it can see a binding for a NSBundle type then it should be able to find a native NSBundle type using the ObjC runtime functions. Otherwise an error is raised...

Since the application analyze itself it must contains everything we wish to test. That's why the introspection tests are part of the dontlink.app application (for iOS) and the dontlink-mac project (for OSX).

Pros

  • They always tell the truth, which can differ from documentation

Cons

  • Incomplete - Not everything is encoded in the metadata / executable;
  • Too complete - Not every truth is good to be known (or published)

Extrospection Tests

Extrospection tests takes data from some outside sources and see if our implementation match the information, e.g.

  • Header files from the SDK;
  • Rules, like Gendarme or FxCop;

Since this is done externally there's no need to run them on the devices, simulator or even a specific version of OSX.

Pro

  • There is more data available, e.g. information lost when compiling

Con

  • The data might not represent the truth (errors, false positives...)

Xamarin.Mac

Many tests when run for macOS use a integration hack which helps handle a number of issues:

  • Allowing command line arguments to tests while excluding "psn" arguments passed in while debugging with Visual Studio for Mac
  • Invoking _exit to work around a number of post-test hangs. See the bug for details.
  • Add a number of "default" excludes for mono BCL tests

One very useful "hack" this support adds is the ability to run a single test from the command line via the XM_TEST_NAME environmental variable. For example

XM_TEST_NAME=MonoTouchFixtures.Security.KeyTest.CreateRandomKeyWithParametersTests make run-mac-unified-xammac_tests

Test Suites

*-tests : where * is the assembly name, e.g. monotouch

Use the project defaults for linking, i.e.

  • "Don't link" for simulator

  • "Link SDK assemblies only" for devices

  • regression testing without using the linker

  • both simulator and devices are set to "Don't link"

linkall

  • regression testing using the linker on the all assemblies

  • "Link all assemblies" for both simulator/devices

linksdk

  • regression testing using the linker on the SDK assemblies

  • "Link SDK assemblies only" for both simulator/devices

bcl-test

These are the Mono BCL test suite tweaked to run on the mobile profile. It reuse the files directly from mono's repository (linking, not copying).

As other unit tests the configuration is set to mimick normal apps, e.g.

  • "Don't link" for simulator

  • "Link SDK assemblies only" for devices

Common make targets

Run every test in both the simulator and on device, using both the compat and the new profile (for the simulator both in 32 and 64bit mode).

$ make run

Run every test in the simulator, using both the compat and the new profile (both 32 and 64bit simulators).

$ make run-all-sim

Run every test on device, using both the compat and the new profile

$ make run-all-dev

Detailed make targets

  • Main target

    • run-what-where-project: Builds, installs (if applicable) and runs the specified test project on the specified platform. This is the most common target to use.
    • build-what-where-project: Will build the specified test project for the specified platform and target.
    • install-what-where-project: Will install the specified test project on a connected device. There's currently no way to select the device, so ensure you've only one connected (if many devices are connected, it's random which will used).
    • exec-what-where-project: Will run the specified test project in the simulator or on a device.
  • What

    • -ios-: iOS.
    • -tvos-: TVOS.
    • -watchos-: WatchOS

    If "What" is skipped, all variations are executed sequentially.

  • Where

    • -simclassic-: Simulator using the Classic API. Only applicable when platform is iOS.
    • -simunified-: Simulator using Unified API. The build will contain both an i386 and an x86_64 binary. Only applicable to the build-* target, while the -sim32- and -sim64- are only applicable to the exec-* targets. Only applicable when the platform is iOS.
    • -sim32-: 32bits iOS simulator using the Unified API. Not applicable to other platforms.
    • -sim64-: 64bits iOS simulator using the Unified API. Not applicable to other platforms.
    • -sim-:
      • iOS: Both the -simclassic- and -simunified- versions.
      • WatchOS/TVOS: The WatchOS/TVOS simulator.
    • -devclassic-: Device using the Classic API. Only applicable when the platform is iOS.
    • -devunified-: Device using the Unified API. The build will contain both an armv7 and an arm64 binary. It's not possible to select a 32/64bit version, you'll run what your device supports. Only applicable when the platform is iOS.
    • -dev-:
      • iOS: Both the -devclassic- and -devunified- versions.
      • WatchOS/TVOS: A Watch or TV device.
  • Examples

    $ make run-ios-sim32-monotouchtest: This will run monotouch-test using the Unified API in a 32-bit simulator. $ make run-tvos-dev-dont\ link: This will run dont link on an Apple TV device.

Utility run-* targets

These targets will build, install (if applicable) and run the specified project(s).

  • Simulator

    • run-sim-project: Builds and runs the specified test project in the simulator in compat, 32 and 64bit mode.
    • run-sim: Builds and runs all the non-bcl test projects in the simulator in compat, 32 and 64bit mode.
  • Device

    • run-dev-project: Builds and runs the specified non-bcl test project on a device in compat and native mode (if it's 32 and 64bit depends on the device; 64bit devices will run in 64bit mode and the same for 32bit devices).
    • run-devcompat: Run all the non-bcl test projects on device, in compat mode.
    • run-devdual: Run all the non-bcl test projects on device, in native mode (if it's 32 and 64bit depends on the device; 64bit devices will run in 64bit mode and the same for 32bit devices).
    • run-dev: Run all the non-bcl test projects on device, in both compat and native mode.