[GHC] #13193: Integer (gmp) performance regression?
GHC
ghc-devs at haskell.org
Fri Jan 27 18:18:13 UTC 2017
#13193: Integer (gmp) performance regression?
-------------------------------------+-------------------------------------
Reporter: j.waldmann | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.0.1
Resolution: | Keywords: newcomer
Operating System: Linux | Architecture: x86_64
Type of failure: Runtime | (amd64)
performance bug | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by rwbarton):
Yes, the additional allocations do have to do with the new integer-gmp,
though they aren't entirely the integer-gmp library's fault. The
additional allocations occur in subtraction (in `pred`).
{{{
-- | Subtract one 'Integer' from another.
minusInteger :: Integer -> Integer -> Integer
minusInteger x (S# 0#) = x
minusInteger (S# 0#) (S# INT_MINBOUND#) = Jp# (wordToBigNat
ABS_INT_MINBOUND##)
minusInteger (S# 0#) (S# y#) = S# (negateInt# y#)
minusInteger (S# x#) (S# y#)
= case subIntC# x# y# of
(# z#, 0# #) -> S# z#
(# 0#, _ #) -> Jn# (wordToBigNat2 1## 0##)
(# z#, _ #)
| isTrue# (z# ># 0#) -> Jn# (wordToBigNat ( (int2Word# (negateInt#
z#))))
| True -> Jp# (wordToBigNat ( (int2Word# z#)))
-- more cases, that aren't (S# _) (S# _)
}}}
Based on looking at the assembly, this seems to have been compiled in
7.10.1 to something like
{{{
minusInteger x y = case y of {
S# y# -> case y# of {
0# -> ...
INT_MINBOUND# -> ...
__DEFAULT__ -> let minusY = S# (negateInt# y#)
in case x of {
S# x# -> ...
Jp# {} -> ...
Jn# {} -> ...
}
}
Jp# {} -> ...
Jn# {} -> ...
}
}}}
Note that we allocate `S# (negateInt# y#)` even though we're unlikely to
actually need it, and will never need it more than once.
I see two issues here:
* There are many special cases in `minusInteger`, that are almost never
helpful, and harmful in the common case of small integers (i.e., `S#`).
The old code which began
{{{
minusInteger (S# i) (S# j) = case subIntC# i j of ...
}}}
was much better. But, by itself this shouldn't cause additional
''allocations'', just additional work in the form of conditionals and
branches.
* GHC floated out `S# (negateInt# y#)`, which was a bad choice: increased
allocations, and never any gain, as far as I can see.
Aha, now that I look at the rest of `minusInteger`, `(negateInt# y#)`
does appear again in some branches like
{{{
minusInteger (Jp# x) (S# y#)
| isTrue# (y# >=# 0#) = bigNatToInteger (minusBigNatWord x (int2Word#
y#))
| True = Jp# (plusBigNatWord x (int2Word# (negateInt#
y#)))
}}}
But it's never used more than once per branch, and the `S#` box that we
allocated is still not used.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13193#comment:6>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list