Skip to content

Compiled Lambda Expressions and AOT #17973

Open

Description

@JamesNK

Is it correct that compiled lambda expressions on UWP aren't really compiled and are instead interpreted? If so does that mean that on UWP and other AOT platforms like Xamarin/Unity with no support for IL emit it is faster to use MemberInfo and ConstructorInfo?

Related: JamesNK/Newtonsoft.Json#968


If normal reflection is faster on AOT platforms I would like to know is if there is a way at runtime to discover that IL emit isn't supported?

A way to discover this capability at runtime will allow libraries to use compiled lambda expressions to boost on platforms it is available, and to fallback to traditional reflection on platforms where it isn't, while still using a single netstandard assembly.

Activity

  1. weshaggard commented on Aug 2, 2016

    @weshaggard
    Member

    cc @VSadov

    That is correct for UWP the expressions are interpreted and not compiled at runtime.

  2. clairernovotny commented on Aug 31, 2016

    @clairernovotny

    @JamesNK I know you'll hate this answer, but cross-compiling can ensure that each platform gets the most optimized version for it. With project.json and whatever's coming with the 1.1 tooling transitive dependencies will resolve correctly and ensure that the best version of your library wind up in the runtime dir.

  3. davidfowl commented on Sep 5, 2016

    @davidfowl
    Member

    This needs to be a runtime light up API that is netstandard. The project N toolchain and the JIT can treat it as an intrinsic and eliminate it at runtime.

  4. mjracca commented on Sep 6, 2016

    @mjracca

    +1

    This is a HUGE performance issue for us!

  5. JamesNK commented on Sep 6, 2016

    @JamesNK
    MemberAuthor

    I know you'll hate this answer, but cross-compiling can ensure that each platform gets the most optimized version for it.

    That would require knowing every platform that doesn't support compiling expressions and having a different version in the package for each of those platforms, UWP, iOS, Android, Unity, etc

    And as new platforms come out they would get the slow netstandard binary until someone explicitly adds a different version in the package.

    Or we could have a simple property that library authors can use to adapt the netstandard assembly to the platform at runtime. One assembly that works for now and forever.

  6. jkotas commented on Sep 6, 2016

    @jkotas
    Member

    Agree - hardcoding the list of platforms is fragile. It does not work well for new platforms. Also, the answer can differ for given platform over time; or both interpreter-only and compiled System.Linq.Expressions can be available for some platforms.

    Having an API that returns whether expressions are compiled sounds pretty reasonable.

  7. removed their assignment
    on Nov 29, 2016
  8. VSadov commented on Nov 29, 2016

    @VSadov
    Member

    Since now any expression can be asked to be compiled for interpretation, the API would need to take a compiled expression.
    We generally cannot tell if a delegate is a compiled expression (could be not related to expressions at all), but we can recognize interpreted expression delegates.

    Would something like the following work for you?

    /// returns true if d is a delegate that represents an interpreted expression
    bool IsInterpretedExpression(Delegate d)
  9. JonHanna commented on Nov 29, 2016

    @JonHanna
    Contributor

    I read this as more an environment query; code being able to know if calling Compile(false) is going to result in interpretation or not.

  10. JamesNK commented on Nov 30, 2016

    @JamesNK
    MemberAuthor

    Yes, I see it as an environment query.

    IsInterpretedExpression might be useful for some people but I'm interested in discovering whether an environment supports compiled expressions before I choose to use expressions (or not, depending on the environment query result).

  11. davidfowl commented on Nov 30, 2016

    @davidfowl
    Member

    I read this as more an environment query; code being able to know if calling Compile(false) is going to result in interpretation or not.

    Yes. It needs to be before not after. Framework code would likely switch logic altogether and use reflection invoke vs expression tree compilation.

  12. stratospheres commented on Dec 15, 2016

    @stratospheres

    Man, this really burned me - I simply ported some really well working code from an "old" style codebase to UWP and this absolutely hammered me... slowed down by roughly 20x.

    +1 to fixing this... please.

  13. JamesNK commented on Jan 3, 2017

    @JamesNK
    MemberAuthor

    Another person being hurt by this - JamesNK/Newtonsoft.Json#968 (comment)

  14. JonHanna commented on Feb 3, 2017

    @JonHanna
    Contributor

    Should such a property live in S.L.Expressions or perhaps elsewhere?

    Am I right in thinking that a complementary CanInterpret would also be true now, and hence have no value?

  15. 21 remaining items

  16. added this to the 5.0 milestone on Jan 31, 2020
  17. removed
    untriagedNew issue has not been triaged by the area owner
    on Jul 7, 2020
  18. modified the milestones: 5.0.0, Future on Aug 14, 2020
  19. JoshClose commented on Nov 23, 2022

    @JoshClose

    Is this still an issue with the .NET 7 AOT stuff? Are compiled lambda expressions in a code generator still interpreted?

  20. jkotas commented on Nov 23, 2022

    @jkotas
    Member

    Are compiled lambda expressions in a code generator still interpreted?

    Yes, lambda expressions are still interpreted with .NET 7 native aot. Native aot does not have a JIT so it is by design.

    Libraries that want to run great on native AOT should avoid lambda expressions.

  21. JoshClose commented on Nov 23, 2022

    @JoshClose

    Thanks!

  22. flobernd commented on Nov 29, 2022

    @flobernd

    Is the fallback interpreter really that slow, that switching to reflection (which isn't the fastest as well) would speed up things significantly in the majority of cases?

  23. jkotas commented on Nov 29, 2022

    @jkotas
    Member

    Expression tree interpreter uses reflection to invoke methods. It means that expression tree is always slower than reflection when everything is equal. The slowdown is proportional to the amount of interpreted code.

  24. Yortw commented on Nov 29, 2022

    @Yortw

    I just wanted to point out, as in the referenced in the Newtonsoft issue linked in the OP, it's not just that 'compiled expressions' fallback to reflection, but that the internal reflection mechanisms in the runtime used by AOT UWP appear to be "worse" for performance than say the old Xamarin ones, due to less internal caching.

    So you don't get the perf benefit of 'compiled expressions', but you also get worse performance than .Net on desktop/Xamarin even when using reflection (apples to apples comparison). Or at least that was my experience, and I was told the lack of internal caching of reflection types/data was to blame.

  25. flobernd commented on Nov 29, 2022

    @flobernd

    Thanks for clarifying this. I guess I have to do some tests myself as I'm mainly interested in NET7 AOT and not so mich in the Mono or Xamarin stacks.

    I'm not quite sure what do to when results are unpleasant. Code generation is not a proper alternative in many situations.

  26. voroninp commented on Jul 10, 2024

    @voroninp

    I was expecting an exception when Compile is called for expression in AOTed code, and I was very surprised when it worked.
    But I am even more surprised to discover this issue =)
    By the way, AOT Analyzer does not complain about Compile() calls. Should not it?
    Espeshially when it returns:

    IsDynamicCodeSupported = False
    IsDynamicCodeCompiled = False
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions