[GHC] #1349: Generalise the ! and UNPACK mechanism for data
types, to unpack function arguments
GHC
cvs-ghc at haskell.org
Wed Aug 4 18:34:53 EDT 2010
#1349: Generalise the ! and UNPACK mechanism for data types, to unpack function
arguments
---------------------------------+------------------------------------------
Reporter: simonpj | Owner:
Type: task | Status: new
Priority: low | Milestone: 6.14.1
Component: Compiler | Version: 6.6.1
Keywords: | Testcase:
Blockedby: | Difficulty: Unknown
Os: Unknown/Multiple | Blocking:
Architecture: Unknown/Multiple | Failure: None/Unknown
---------------------------------+------------------------------------------
Comment(by kolmodin):
I thought I might share my story too, as I ran into this as well, and got
aware of this ticket.
3 years after Duncan wrote his mail about the need for speed in binary I
ran into the same trouble, again with the binary package.
Duncan wrote about the Put module, which creates lazy Bytestrings from an
DSL.
The Get module reads such Bytestrings with a similar DSL.
I've rewritten the Get module to use CPS, which allows some useful tricks
when parsing.
The Get data type from the non-CPS Get module looks like this:
{{{
-- | The parse state
data S = S {-# UNPACK #-} !B.ByteString -- current chunk
L.ByteString -- the rest of the input
{-# UNPACK #-} !Int64 -- bytes read
-- | The Get monad is just a State monad carrying around the input
ByteString
newtype Get a = Get { unGet :: S -> (# a, S #) }
}}}
While the CPS version looks like this (heavily influenced by attoparsec):
{{{
data S = S { input :: !B.ByteString
, next_input :: !B.ByteString
, read_all :: !Bool
} deriving Show
data Result a = Fail S [String] String
| Partial (Maybe B.ByteString -> Result a)
| Done S a
type Failure r = S -> [String] -> String -> Result r
type Success a r = S -> a -> Result r
-- unrolled codensity/state monad
newtype Get a = C { runCont :: forall r.
S ->
Failure r ->
Success a r ->
Result r }
}}}
Unfortunately, this yields terrible performance.
The old Get gives me about 26mb/s (Core 2 Duo, 1.6Ghz) when reading chunks
of 1 byte at a time, while the CPS version only gives up to 1mb/s! Much
time seems to be spent doing GC, as the bigger Bytestring I read the worse
performance I get.
After reasoning a bit about what GHC actually does, I unpacked the state
into the Get data type:
{{{
type Failure r = B.ByteString -> B.ByteString -> Bool -> [String] ->
String -> Result r
type Success a r = B.ByteString -> B.ByteString -> Bool -> a -> Result r
-- unrolled codensity/state monad
newtype Get a = C { runCont :: forall r.
B.ByteString ->
B.ByteString ->
Bool ->
Failure r ->
Success a r ->
Result r }
}}}
This at least gave me 12mb/s (I think I've even been able to get the same
26mb/s, when further trying to optimize). The price to pay is that the
code is now not as maintainable, it truly looks horrible.
So it still seems this ticket is important in some cases.
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/1349#comment:24>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the Glasgow-haskell-bugs
mailing list