Skip to content

.NET 10 has ~1.8x higher RPS than .NET 11 preview 7 on a minimal ASP.NET Core app #132951

Description

@EgorBo

A minimal ASP.NET Core app serves ~1.8x fewer requests/sec on .NET 11 preview 7 than on .NET 10.

Source

webbench.cs (file-based app, no project file):

#:sdk Microsoft.NET.Sdk.Web

var builder = WebApplication.CreateSlimBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Warning);
var app = builder.Build();
app.MapGet("/", () => "Hello, World!");
app.Run();

Script

run.sh:

#!/bin/bash
SDKS=${SDKS:-"net10 net11"}
MODES=${MODES:-"jit aot"}
SDK_ROOT=${SDK_ROOT:-$HOME/sdks}
OUT=${OUT:-/tmp/aspnet-repro-out}
BUILD=${BUILD:-1}
URL=http://127.0.0.1:5111

set -e
cd "$(cd "$(dirname "$0")" && pwd)"
trap 'kill $PID 2>/dev/null || true' EXIT

build() {
  local props="-p:PublishAot=false"
  [ "$2" = aot ] && props="-p:PublishAot=true -p:IlcInstructionSet=native"
  rm -rf "$HOME/.local/share/dotnet/runfile/webbench-"*
  DOTNET_ROOT="$SDK_ROOT/$1" PATH="$SDK_ROOT/$1:$PATH" \
    dotnet publish webbench.cs -c Release -r linux-x64 --self-contained $props -o "$OUT/$1-$2" -v q --nologo >/dev/null
}

run() {
  ASPNETCORE_URLS=$URL taskset -c 0-7 "$1/webbench" >/dev/null 2>&1 &
  PID=$!
  for _ in $(seq 1 100); do curl -sf -o /dev/null $URL && break; sleep 0.2; done
  taskset -c 16-23 bombardier -c 32 -d 5s $URL >/dev/null 2>&1
  taskset -c 16-23 bombardier -c 32 -d 10s $URL 2>&1 | awk '/Reqs\/sec/{print $2}'
  kill $PID; wait $PID 2>/dev/null || true
  sleep 1
}

if [ "$BUILD" = 1 ]; then
  rm -rf "$OUT"; mkdir -p "$OUT"
  for s in $SDKS; do for m in $MODES; do build "$s" "$m"; done; done
fi

printf "%-8s %12s %12s\n" sdk "JIT rps" "NAOT rps"
for s in $SDKS; do
  j=""; a=""
  for m in $MODES; do r=$(run "$OUT/$s-$m"); [ "$m" = jit ] && j=$r || a=$r; done
  printf "%-8s %12s %12s\n" "$s" "$j" "$a"
done

Results

Median of 3 runs, requests/sec:

SDK JIT RPS NAOT RPS
10.0.11 326,676 188,161
11.0.0-preview.7.26381.103 177,858 176,568
  • JIT regressed by 45.6% in .NET 11.
  • NAOT was 42.4% slower than JIT in .NET 10.

Environment

  • Linux x64 (WSL2, Ubuntu 24.04), 32 logical cores
  • Server pinned to cores 0-7, load generator pinned to cores 16-23
  • For faster warmup, I recommend disabling Hill Climbing and Tiered Compilation

Prerequisites:

curl -sSL -o dotnet-install.sh https://dot.net/v1/dotnet-install.sh && chmod +x dotnet-install.sh
./dotnet-install.sh --channel 10.0 --install-dir $HOME/sdks/net10 --no-path
./dotnet-install.sh --version 11.0.100-preview.7.26381.103 --install-dir $HOME/sdks/net11 --no-path

curl -sSL -o ~/bin/bombardier https://github.com/codesenberg/bombardier/releases/download/v1.2.6/bombardier-linux-amd64
chmod +x ~/bin/bombardier

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions