Fix insert worker/wrapper issues - #416
Conversation
The new pointer equality version of `insert` in `Data.Map` led to a severe regression in the `last-piece` benchmark of `nofib`. It turned out that worker/wrapper was doing absolutely horrible things to `insert`, breaking the pointer equality tests and also leading to completely unnecessary allocation. This commit adds horrible hacks that seem to prevent this from happening.
|
@treeowl, is the unboxing that GHC does here ever profitable? (As in, does it improve anything at all? I haven't looked at the core but it doesn't look there is anything that actually makes use of the unboxed version. Are you talking about the specialized version, maybe? If the unboxing is always unprofitable, it's worth filing a GHC bug with a small test case requesting that GHC become smart enough not to unbox if it can't profitably use the unboxed value. |
|
I believe the unboxed version is used for the comparisons to find the
insertion point. I certainly hope so. We really want to have both boxed and
unboxed here.
On Feb 23, 2017 4:46 AM, "Edward Z. Yang" <notifications@github.com> wrote:
@treeowl <https://github.com/treeowl>, is the unboxing that GHC does here
ever profitable? (As in, does it improve anything at all? I haven't looked
at the core but it doesn't look there is anything that actually makes use
of the unboxed version. Are you talking about the specialized version,
maybe?
If the unboxing is always unprofitable, it's worth filing a GHC bug with a
small test case requesting that GHC become smart enough not to unbox if it
can't profitably use the unboxed value.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#416 (comment)>,
or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_YDAonLnY6CTL9NvdmI8UwBddARUks5rfVV8gaJpZM4MJFYW>
.
|
|
These pointer equality hacks looks horrible to me, what's the motivation for this "better" |
|
We want to share as much structure as possible between the result and the
arguments. The pointer equality tricks allow us to avoid allocating new
structure that's exactly the same as structure we already have.
…On Mar 8, 2017 10:00 PM, "winterland" ***@***.***> wrote:
These pointer equality hacks looks horrible to me, what's the motivation
for this "better" union anyway?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#416 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_YfLOioc_dVdqcQax0Bv4NdqH2Phks5rj2tSgaJpZM4MJFYW>
.
|
|
I mean under what circumstances we would insert sharing values into a Map? From my understanding immutable data structures doesn't work that way. This kind of optimizations never reach a end: |
|
I have no idea what you're getting at.
…On Mar 8, 2017 10:40 PM, "winterland" ***@***.***> wrote:
I mean under what circumstances we would insert sharing values into a Map?
From my understanding immutable data structures doesn't work that way. This
kind of optimizations never reach a end: elem , nub... because I don't
think there is an use case. Correct me if you can find one .
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#416 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_cCmgE4FSVQ93YnL_bP-bYQ6bvf8ks5rj3SngaJpZM4MJFYW>
.
|
|
OK, let me try to put it in another way: under what practical circumstances |
|
@winterland1989 the situation where pointer equality would be true is when the inserted value is pointer-equal to the value that's already there. For |
|
I still have a hard time understand why we introduce this hack. @treeowl , can you show me some use cases of the pointer equality version insert/merge except some benchmark code? |
|
And here is recently discussion on From the discussion above i also doubt current code's safety: if |
|
It can't give a false positive; it can only give a false negative.
…On Nov 23, 2017 1:27 AM, "winterland" ***@***.***> wrote:
And here is recently discussion on reallyUnsafePointerEquality:
https://mail.haskell.org/pipermail/haskell-cafe/2010-June/079532.html
From the discussion above i also doubt current code's safety: if
reallyUnsafePointerEquality give false positive result, insert/merge will
be incorrect.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#416 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_Ufsps_PowBKkUa6fjEpsgVGLZXpks5s5RA7gaJpZM4MJFYW>
.
|
|
The link above is mentioned in recently discussion here(Obviously i posted the wrong link): What i want is a demonstration of why we're doing this. AFAICT if you're facing sharing detection problems in pure functional data structures, you're probably doing it wrong. |
|
The reason to want this is to preserve sharing when possible. I don't
understand this debate about false positives. How can GC *ever* happen
while such a primop is running? It's not like it allocates anything. If
that's a problem, then it's an RTS bug anyway, and not my problem.
…On Nov 23, 2017 4:37 AM, "winterland" ***@***.***> wrote:
The link above is mentioned in recently discussion here(Obviously i posted
the wrong link):
https://mail.haskell.org/pipermail/haskell-cafe/2017-November/128208.html
What i want is a demonstration of why we're doing this. AFAICT if you're
facing sharing detection problems in pure functional data structures, you
must do it wrong.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#416 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_fcT_SId3Z0ptdQMdiRzDzbBumKNks5s5TzbgaJpZM4MJFYW>
.
|
|
I can get what you want to solve from this comment: But the question is, when we will insert a value with a same address? Isn't there something wrong with the algorithm design? Can you provide some use case? |
Summary: This copies over the containers version from 8.2.2 to bring in the following patch haskell/containers#416. This would save us memory when compiling a lot of modules in ghci. Test Plan: Rebuild and ran with ghci Reviewers: simonmar, watashi, sigma Reviewed By: simonmar
Combining any two maps which have some shared values. let usedStuff = usedByA `union` usedByBI know I have written code like that in the past. |
I would be interested if you can provide some code samples (Input and output included). I'm pretty sure there is a way to rewrite the algorithm to eliminate merging sharing values because you can statically know what is shared between maps under immutable settings. |
|
I can't remember the exact project so sadly I can't give the code. And yes you can always rewrite the code to avoid duplicating inserts.
Maybe that work is still more overhead than what we gain. Maybe not. But if you feel this should be removed the way forward is to open an issue and provide benchmarks of improvements for the general case. |
No, we can statically know if two distinct maps share data since inserted data is never changed. e.g. we insert the same binding into two different maps.
The problem is that the patch introduced a special benchmark (above transformation also apply) to benchmark this bogus case. |
|
No, you can't statically know if two maps share data, in general. For example, one map might consist of information obtained from one source and the other may consist of information obtained from another source. When the maps are combined, some information may have been obtained from both sources. @AndreasPK meant that you should come up with benchmarks showing that the pointer equality checks cause significant harm in typical cases. Since the checks are extremely cheap, I think that will be difficult to do, but feel free to try to prove me wrong. |
|
Your argument also applies to all the |
Please explain how can you "statically" know that two maps, constructed from two different dynamically generated heap objects, contain the same data. Clearly both me and @treeowl think differently so it's on you to proof us wrong.
How is that a problem? Just remove the pointer checks, remove that special case and report the change in performance. If it's significant then a discussion about removing it makes sense, otherwise not.
I can give you pseudo code for a Set example: Id's all originate from binds, so they all reference the same heap object. So the pointer equality will hold. This is not a contrived example GHC contains code like this, with the only difference being it uses IntSet. |
|
Your example is convincing so I searched for the old discussion try to remember why I have a problem with pointer equality in general, so here it's (an old discussion started by myself): https://www.reddit.com/r/haskell/comments/4ivvge/why_no_reference_equality/ To sum it up, here're problems with built-in pointer equality as far as I can see:
So I'm still in a position objecting adding implicit pointer equality by default, but maintainers' views differ. Out of curiosity, If those |
It works reliable under specific circumstances. As Augustsson explained:
But it does (for this use case)!
That is fair. We can hate the hack, but it's correct and if it gives better performance then it is a good fit for such a essential package as containers. I also would never use ptr Equality by default.
We can. It's also what GHC does. But if we can better performance for this case without significantly impacting the general case performance why wouldn't we.
Map lookup. I will leave this discussion now. Getting rid of pointer equality because it's hacky won't happen. High performance code tends to be hacky. But if you think it makes containers performance worse and can show that then I don't think there will be a lot of resistance. But if you can do so then open a ticket for it. Discussing it on a closed merge request is kinda pointless. |
|
Fair enough, I will try make a benchmark for this some day. |
The new pointer equality version of
insertinData.Mapled toa severe regression in the
last-piecebenchmark ofnofib.It turned out that worker/wrapper was doing absolutely horrible
things to
insert, breaking the pointer equality tests andalso leading to completely unnecessary allocation. This commit
adds horrible hacks that seem to prevent this from happening.