-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Boxing Cache? #7079
Comments
I would guess that this makes boxing slower. Who's benefiting from that? 👽s? |
Even if it was faster, it is a bad idea since boxed value types can have their values modified. Not expressible in C# (without interface tricks), but possible in IL and C++/CLI:
|
Right, I was about the write the same comment as @JanielS
|
Or reflection: object x = 1;
x.GetType().GetField("m_value", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(x, 42);
Console.WriteLine(x); // prints 42 |
Is changing the value of a boxed value directly that common? To prevent subtle errors, could allocate boxes from a single page, then mark them as Obviously if its common practice then couldn't do that... |
I'd say not. But is it worth the risk? What kind of code does a lot of boxing, uses a limited enough range of numeric values and expects good performance? |
I don't really think it matters all that much, but spec-wise, modifying these unboxed values seems to be disallowed. |
String.Format https://github.com/dotnet/corefx/issues/1514
Well, that works both ways; introducing a cache would likely slow down boxing slightly; but ease up on GC. For reference I think the asm JIT_BoxFastMP_InlineGetThread is the fastest version of boxing? Is common practice in Java; so Integer i0 = 127;
Integer i1 = 127;
System.out.println(i0 == i1); // Prints true, reference equality
Integer i2 = 128;
Integer i3 = 128;
System.out.println(i2 == i3); // Prints false, different references Which confuses people; but Integer has a different equality to int; which I think also confuses people. Whereas in C# for reference equality it would need to be a clearer |
int x = 42;
for (int i = 0; i < 10000000; i++)
{
String.Format("hello {0}", x);
} and change the type of x from
Eh, the old story about GC. Let's cache everything because GC can't handle it. But GC handles short lived objects pretty well so it's not clear how much this will "ease up on GC".
Considering that even with generics Java can't store integers in collections without boxing I'd say that it needs such caching more than .NET does. Besides, that Stackoverflow question is a good enough reason to not attempt to implement such a trick in .NET. Because this is a trick and a rather ugly one. This is something that user code can do reasonably well when truly needed. For example WPF does this for |
Added a few more examples; longer lived would be typed documents in memory; Json, Csv, Xaml etc as your example of WPF
And people create their own boxing caches again and again https://github.com/dotnet/corefx/issues/6533, LinqExpressions |
Exactly. You do not actually care whether there are thousands GCs or no GC. What you care about is how fast a thing runs and what the GC pauses are. And caching short-lived objects does not improve either.
People who do not measure do... . The example from Expressions make sense because of these objects seem to be long-lived. It is a rare case. The CustomAttributeDecoder example makes less sense. |
Maybe I should have led with a repo you can try locally and some metrics for it Integer Box Caching
Boolean Box Caching
Updated summary |
Microbenchmark is good, but it does not tell the full story. This would need to be looked at in the context of real workloads like Roslyn or ASP.NET. |
Roslyn caches boxes for true, false, all zeros, int32 1, chars 0 - 127 https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/Collections/Boxes.cs But I take your point |
That might mean that the framework should provide some kind of mechanism to help with this issue. But it doesn't necessarily mean that the mechanism should be built into the boxing operation itself. A |
From my benchmark tests; what I was attempting to do was the wrong approach as it was a (virtual) call in the runtime; and about half of the gain is already lost if its not inlined. So (if automatic) it would either need to be a code replace in jit or something like a Roslyn generator - depending how that plays out? dotnet/roslyn#5561 And... I'd guess the second would be preferred as it would be a user choice/reference install? |
Boxing is required in the C# language specification and in the CLR specification to allocate a new object instance. This is trivially observable in user code. So the proposed "optimization" would violate both specifications. |
Revisiting https://github.com/dotnet/coreclr/issues/111
Using repo example manged code; shows pre-cached boxes for common values can improve the performance of boxing (see below). Is there a way of building this into the jit or runtime?
Or is this just madness?
Integer Box Caching
Boolean Box Caching
Suggestion, cache boxes for:
bool: true, falue
byte: 0 to 255
char: 0 to 127
int/short: -128 to 127
Maybe others?
Gave it a go benaadams/coreclr@2f7726d, but not entirely sure what I'm doing, so you probably have a bunch of really weird Dr Watson reports...
Edit Updated with metrics post https://github.com/dotnet/coreclr/issues/8423#issuecomment-264500921
The text was updated successfully, but these errors were encountered: