You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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?
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.
@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.
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.
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.
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.
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 expressionboolIsInterpretedExpression(Delegated)
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).
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.
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?
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.
Reacted by Florian Bernd, Leandro Fernandes and Nathan Phillip Brink
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.
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:
Activity
weshaggard commentedon Aug 2, 2016
cc @VSadov
That is correct for UWP the expressions are interpreted and not compiled at runtime.
clairernovotny commentedon Aug 31, 2016
@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.jsonand 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.davidfowl commentedon Sep 5, 2016
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.
mjracca commentedon Sep 6, 2016
+1
This is a HUGE performance issue for us!
JamesNK commentedon Sep 6, 2016
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.
jkotas commentedon Sep 6, 2016
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.
VSadov commentedon Nov 29, 2016
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?
JonHanna commentedon Nov 29, 2016
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.
JamesNK commentedon Nov 30, 2016
Yes, I see it as an environment query.
IsInterpretedExpressionmight 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).davidfowl commentedon Nov 30, 2016
Yes. It needs to be before not after. Framework code would likely switch logic altogether and use reflection invoke vs expression tree compilation.
stratospheres commentedon Dec 15, 2016
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.
JamesNK commentedon Jan 3, 2017
Another person being hurt by this - JamesNK/Newtonsoft.Json#968 (comment)
JonHanna commentedon Feb 3, 2017
Should such a property live in S.L.Expressions or perhaps elsewhere?
Am I right in thinking that a complementary
CanInterpretwould also be true now, and hence have no value?21 remaining items
Start building a universal System.Linq.Expressions library
Start building a universal System.Linq.Expressions library (#61952)
JoshClose commentedon Nov 23, 2022
Is this still an issue with the .NET 7 AOT stuff? Are compiled lambda expressions in a code generator still interpreted?
jkotas commentedon Nov 23, 2022
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.
JoshClose commentedon Nov 23, 2022
Thanks!
flobernd commentedon Nov 29, 2022
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?
jkotas commentedon Nov 29, 2022
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.
Yortw commentedon Nov 29, 2022
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.
flobernd commentedon Nov 29, 2022
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.
voroninp commentedon Jul 10, 2024
I was expecting an exception when
Compileis 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: