Skip to content

Reflection performance in NativeAOT #66620

Open

Description

@AhmedZero

Description

when I use the following example without NativeAOT, it's very fast, but with NativeAOT, I found it's very slow.

using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Reflection;
namespace MyApp 
{

public static class Utils
 {
     public static string GetDescription(this Enum value)
     {
         FieldInfo field = value.GetType().GetField(value.ToString());

         DescriptionAttribute attribute
                 = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))
                     as DescriptionAttribute;

         return attribute == null ? value.ToString() : attribute.Description;
     }
 }
internal unsafe class Program
 {
     public enum Item
     {
         [Description("Zero")]
         Useless,
         [Description("Test--1")]
         Test1,
         [Description("Test--2")]
         Test2,
         [Description("Test--3")]
         Test3,
         [Description("Test--4")]
         Test4,
         [Description("Test--5")]
         Test5,
         [Description("Test--6")]
         Test6,
         [Description("Test--7")]
         Test7,
         [Description("Test--8")]
         Test8,
         [Description("Test--9")]
         Test9,
         [Description("Test--10")]
         Test10,
         [Description("Test--11")]
         Test11,
         [Description("Test--12")]
         Test12,
         [Description("Test--13")]
         Test13,
         [Description("Test--14")]
         Test14,
         [Description("Test--15")]
         Test15,
         [Description("Test--16")]
         Test16,
         [Description("Test--17")]
         Test17,
         [Description("Test--18")]
         Test18,
         [Description("Test--19")]
         Test19,
         [Description("Test--20")]
         Test20,
         [Description("Test--21")]
         Test21,
         [Description("Test--22")]
         Test22,
         [Description("Test--23")]
         Test23,
         [Description("Test--24")]
         Test24,
         [Description("Test--25")]
         Test25,
         [Description("Test--26")]
         Test26,
         [Description("Test--27")]
         Test27,
         [Description("Test--28")]
         Test28,
         [Description("Test--29")]
         Test29,
         [Description("Test--30")]
         Test30,
         [Description("Test--31")]
         Test31,
         [Description("Test--32")]
         Test32,
         [Description("Test--33")]
         Test33,
         [Description("Test--34")]
         Test34,
         [Description("Test--35")]
         Test35,
         [Description("Test--36")]
         Test36
     }

     static void Main(string[] args)
     {
         Stopwatch sw = new Stopwatch();
         sw.Start();
         List<string> test1 = new List<string>();
         for (int i = 0; i < 100000; i++)
         {
             test1.Add(Item.Test36.GetDescription());
         }
         sw.Stop();
         Console.WriteLine("First Example: " + sw.ElapsedTicks);
         sw.Restart();
         sw.Start();
         List<string> test2 = new List<string>();
         for (int i = 0; i < 100000; i++)
         {
             test2.Add("test--36");
         }
         sw.Stop();
         Console.WriteLine("Second Example: " + sw.ElapsedTicks);

         Console.ReadKey();
     }
}
}

Output

Without NativeAOT

First Example: 1711806
Second Example: 10042

With NativeAOT

First Example: 5760899
Second Example: 20363

Configuration

Win-x64
.NET 6

Activity

  1. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Mar 14, 2022
  2. hez2010 commented on Mar 15, 2022

    @hez2010
    Contributor

    There's some performance degrade but not that huge. For performance test you need to use BenchmarkDotNet to get accurate result, rather than using a StopWatch around a loop iteration whose result can be affected by many other factors.

    I ran it with BenchmarkDotNet and got this result:

    Method Toolchain Mean Error StdDev
    Example1 .NET 6.0 107.742 ms 2.0753 ms 3.1062 ms
    Example2 .NET 6.0 1.033 ms 0.0191 ms 0.0267 ms
    Example1 NativeAOT 155.764 ms 3.4181 ms 5.1160 ms
    Example2 NativeAOT 1.123 ms 0.0222 ms 0.0325 ms

    List itself has no performance difference between JIT and NativeAOT, while reflection in NativeAOT is a bit slower than JIT.

  3. AhmedZero commented on Mar 15, 2022

    @AhmedZero
    Author

    I don't know benchmark.net works with NativeAOT and my program has those conditions and I program it like that.
    when the program add a lot of elements to the list, the performance becomes bad.

  4. jkotas commented on Mar 15, 2022

    @jkotas
    Member

    List itself has no performance difference between JIT and NativeAOT, while reflection in NativeAOT is a bit slower than JIT.

    Yes, this is what I am seeing as well.

  5. AhmedZero commented on Mar 20, 2022

    @AhmedZero
    Author

    NativeAOT

    Method Mean Error StdDev
    Example1 175.341 ms 11.0707 ms 0.6068 ms
    Example2 1.002 ms 0.2061 ms 0.0113 ms

    Without NativeAOT

    Method Mean Error StdDev
    Example1 124.3967 ms 2.4448 ms 3.0919 ms
    Example2 0.8375 ms 0.0163 ms 0.0167 ms

    you're correct @hez2010

  6. added this to the Future milestone on Apr 20, 2022
  7. removed
    untriagedNew issue has not been triaged by the area owner
    on Apr 20, 2022
  8. changed the title [-]List Collection Performance in NativeAOT[/-] [+]Reflection performance in NativeAOT[/+] on Apr 20, 2023
  9. AhmedZero commented on Aug 23, 2025

    @AhmedZero
    Author

    BenchmarkDotNet v0.15.2, Windows 11 (10.0.26100.4946/24H2/2024Update/HudsonValley)
    13th Gen Intel Core i7-13700HX 2.10GHz, 1 CPU, 24 logical and 16 physical cores
    .NET SDK 9.0.304
    [Host] : .NET 9.0.8 (9.0.825.36511), X64 RyuJIT AVX2
    .NET 9.0 : .NET 9.0.8 (9.0.825.36511), X64 RyuJIT AVX2
    NativeAOT 9.0 : .NET 9.0.8, X64 NativeAOT AVX2

    Method Job Runtime Mean Error StdDev
    Example1 .NET 9.0 .NET 9.0 55,481.4 μs 1,096.69 μs 1,386.96 μs
    Example2 .NET 9.0 .NET 9.0 435.5 μs 7.11 μs 6.65 μs
    Example1 NativeAOT 9.0 NativeAOT 9.0 221,162.7 μs 4,321.69 μs 4,976.86 μs
    Example2 NativeAOT 9.0 NativeAOT 9.0 567.2 μs 4.82 μs 4.51 μs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status
      No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions