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

AOT Compilation Canary #7458

Draft
wants to merge 10 commits into
base: v1.6
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions build-system/azure.aot.template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
parameters:
name: ''
displayName: ''
vmImage: ''
run_if: true
timeoutInMinutes: 10

jobs:
- job: ${{ parameters.name }}
condition: eq( ${{ parameters.run_if }}, true )
displayName: ${{ parameters.displayName }}
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
pool:
vmImage: ${{ parameters.vmImage }}
steps:
- task: UseDotNet@2
displayName: 'Use .NET 8 SDK 8.0.402'
inputs:
version: 8.0.402


# Option 1: Use inline script to handle paths properly
- task: PowerShell@2
inputs:
targetType: 'inline'
script: |
./tools/test-aot-compatibility.ps1 net8.0
Copy link
Member Author

@Aaronontheweb Aaronontheweb Jan 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This uses a PowerShell script to tabulate the total number of AOT trim warnings and throw an exception if they're above 0 - taken from one of Microsoft's blogs on AOT support for library authors

pwsh: true

- script: 'echo 1>&2'
failOnStderr: true
displayName: 'If above is partially succeeded, then fail'
condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues')
12 changes: 12 additions & 0 deletions build-system/pr-validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,15 @@ jobs:
scriptArgs: CreateNuget nugetprerelease=dev incremental
outputDirectory: "bin/nuget"
artifactName: "nuget_pack-$(Build.BuildId)"

- template: azure.aot.template.yaml
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do AOT on both Windows and Linux just in-case there are platform-specific issues. Should never happen, but you never know.

parameters:
name: "aot_linux"
displayName: "AOT Compilation (Linux)"
vmImage: "ubuntu-latest"

- template: azure.aot.template.yaml
parameters:
name: "aot_windows"
displayName: "AOT Compilation (Windows)"
vmImage: "windows-latest"
17 changes: 17 additions & 0 deletions src/Akka.sln
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClusterToolsExample.Node",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.TestKit.Xunit2.Tests", "contrib\testkits\Akka.TestKit.Xunit2.Tests\Akka.TestKit.Xunit2.Tests.csproj", "{95017C99-E960-44E5-83AD-BF21461DF06F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AOT", "AOT", "{2E11BBFC-EA1F-4C20-8076-0D8542397264}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.AOT.App", "aot\Akka.AOT.App\Akka.AOT.App.csproj", "{6732F90D-59C9-45BA-801A-24BE2A12EB62}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1357,6 +1361,18 @@ Global
{95017C99-E960-44E5-83AD-BF21461DF06F}.Release|x64.Build.0 = Release|Any CPU
{95017C99-E960-44E5-83AD-BF21461DF06F}.Release|x86.ActiveCfg = Release|Any CPU
{95017C99-E960-44E5-83AD-BF21461DF06F}.Release|x86.Build.0 = Release|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Debug|x64.ActiveCfg = Debug|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Debug|x64.Build.0 = Debug|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Debug|x86.ActiveCfg = Debug|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Debug|x86.Build.0 = Debug|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Release|Any CPU.Build.0 = Release|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Release|x64.ActiveCfg = Release|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Release|x64.Build.0 = Release|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Release|x86.ActiveCfg = Release|Any CPU
{6732F90D-59C9-45BA-801A-24BE2A12EB62}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1484,6 +1500,7 @@ Global
{ED00E6F4-2B5C-4F16-ADE4-45E4A73C17B8} = {7735F35A-E7B7-44DE-B6FB-C770B53EB69C}
{337A85B5-4A7C-4883-8634-46E7E52A765F} = {7735F35A-E7B7-44DE-B6FB-C770B53EB69C}
{95017C99-E960-44E5-83AD-BF21461DF06F} = {7625FD95-4B2C-4A5B-BDD5-94B1493FAC8E}
{6732F90D-59C9-45BA-801A-24BE2A12EB62} = {2E11BBFC-EA1F-4C20-8076-0D8542397264}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {03AD8E21-7507-4E68-A4E9-F4A7E7273164}
Expand Down
18 changes: 18 additions & 0 deletions src/aot/Akka.AOT.App/Actors/AotReceiveActor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// -----------------------------------------------------------------------
// <copyright file="AotReceiveActor.cs" company="Akka.NET Project">
// Copyright (C) 2009-2025 Lightbend Inc. <http://www.lightbend.com>
// Copyright (C) 2013-2025 .NET Foundation <https://github.com/akkadotnet/akka.net>
// </copyright>
// -----------------------------------------------------------------------

using Akka.Actor;

namespace Akka.AOT.App.Actors;

public class AotReceiveActor : ReceiveActor
{
public AotReceiveActor()
{
ReceiveAny(o => Sender.Tell(o));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We know ReceiveActors use the ExpressionCompiler in v1.5 and earlier, which should trip AOT warnings. I might need to add a stricter Receive<string> with a predicate prior to this one just to make sure that code gets exercised properly in the test,

}
}
18 changes: 18 additions & 0 deletions src/aot/Akka.AOT.App/Actors/AotUntypedActor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// -----------------------------------------------------------------------
// <copyright file="AotUntypedActor.cs" company="Akka.NET Project">
// Copyright (C) 2009-2025 Lightbend Inc. <http://www.lightbend.com>
// Copyright (C) 2013-2025 .NET Foundation <https://github.com/akkadotnet/akka.net>
// </copyright>
// -----------------------------------------------------------------------

using Akka.Actor;

namespace Akka.AOT.App.Actors;

public class AotUntypedActor : UntypedActor
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UntypedActor is already AOT-friendly, but we should still see that show up.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need to add more cases to the canary over time, such as:

  1. IStash support
  2. IWithTimers support
  3. Custom dispatchers
  4. Custom mailboxes
  5. Routers

Just to gradually add full trim coverage to everything in the default Akka library, minus default serialization (which we know will not work)

{
protected override void OnReceive(object message)
{
Sender.Tell(message);
}
}
22 changes: 22 additions & 0 deletions src/aot/Akka.AOT.App/Akka.AOT.App.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(NetTestVersion)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<PropertyGroup Label="AotSettings">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are all the MSBUILD settings needed to get the compiler to produce the AOT warnings we're looking for

<PublishAot>true</PublishAot>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
<SelfContained>true</SelfContained>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\core\Akka\Akka.csproj"/>
</ItemGroup>

</Project>
27 changes: 27 additions & 0 deletions src/aot/Akka.AOT.App/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Akka.Actor;
using Akka.AOT.App.Actors;

namespace Akka.AOT.App;

class Program
{
static async Task Main(string[] args)
{
var system = ActorSystem.Create("MySystem");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does some end to end messaging and uses the default configuration loading, which currently triggers a number of AOT warnings due to how we load Types from HOCON strings - those are all issues on the #7246 epic we will have to gradually fix before this spec can pass.


// create AotUntypedActor
var untypedActorProps = Props.Create(() => new AotUntypedActor());
var untypedActor = system.ActorOf(untypedActorProps, "untyped-actor");

// create AotReceiveActor
var receiveActorProps = Props.Create(() => new AotReceiveActor());
var receiveActor = system.ActorOf(receiveActorProps, "receive-actor");

// send a message to both actors
Console.WriteLine(await untypedActor.Ask("Hello, untyped actor!"));
Console.WriteLine(await receiveActor.Ask("Hello, receive actor!"));

// terminate the actor system
await system.Terminate();
}
}
64 changes: 64 additions & 0 deletions tools/test-aot-compatibility.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
param([string]$targetNetFramework = "net8.0")

$rootDirectory = Split-Path $PSScriptRoot -Parent
$publishOutput = dotnet publish $rootDirectory/src/aot/Akka.AOT.App/Akka.AOT.App.csproj -nodeReuse:false /p:UseSharedCompilation=false /p:ExposeExperimentalFeatures=true

$actualWarningCount = 0

foreach ($line in $($publishOutput -split "`r`n"))
{
if ($line -like "*analysis warning IL*")
{
Write-Host $line

$actualWarningCount += 1
}
}

# Determine the OS-specific folder
$osPlatform = [System.Runtime.InteropServices.RuntimeInformation]::OSDescription
if ($osPlatform -match "Windows") {
$osFolder = "win-x64"
} else {
$osFolder = "linux-x64"
# Default to linux
}

$testAppPath = Join-Path -Path $rootDirectory/src/aot/Akka.AOT.App/bin/Release/$targetNetFramework -ChildPath $osFolder/publish

if (-Not (Test-Path $testAppPath)) {
Write-Error "Test App path does not exist: $testAppPath"
Exit 1
}

Write-Host $testAppPath
pushd $testAppPath

Write-Host "Executing test App..."
if ($osPlatform -match "Windows") {
./Akka.AOT.App.exe
} else {
# Default to linux
./Akka.AOT.App
}

Write-Host "Finished executing test App"

if ($LastExitCode -ne 0)
{
Write-Host "There was an error while executing AotCompatibility Test App. LastExitCode is:", $LastExitCode
}

popd

Write-Host "Actual warning count is:", $actualWarningCount
$expectedWarningCount = 0

$testPassed = 0
if ($actualWarningCount -ne $expectedWarningCount)
{
$testPassed = 1
Write-Host "Actual warning count:", $actualWarningCount, "is not as expected. Expected warning count is:", $expectedWarningCount
}

Exit $testPassed
Loading