ForeignPtr reloaded

Donald Bruce Stewart dons at cse.unsw.edu.au
Sun Jun 4 22:20:13 EDT 2006


duncan.coutts:
> 3: strict ByteString version, more like the original elegant pipeline
> version, quite quick.
> 
> time: 0.36s
> 
>         import qualified Data.ByteString.Char8 as B
>         
>         main = print . foldl (\n l -> n + B.readInt l) 0 . B.lines =<< B.getContents
>         
> 5: C version, very quick, reuses a fixed size buffer (which is possibly
> cheating as the Haskell versions will allow any line length).
> 
> time: 0.15s
> 
>         #include <stdio.h>
>         #include <stdlib.h>
>         
>         #define MAXLINELEN 128
>         
>         int
>         main() {
>             int sum = 0;
>             char line[MAXLINELEN];
>         
>             while (fgets(line, MAXLINELEN, stdin)) {
>            	sum += atoi(line);
>             }
>             printf("%d\n", sum);
>             return(0);
>         }
> 
> So our fastest version is similar code to the original naive version and
> is only half the speed of the C version.

Which is a nice result for a one liner. In fact, we can do faster still ..
here's an (ugly, unfortunately) sum.hs in the fps tests/ dir is around 3x
faster than the optimised C version. The C program is hampered by atoi being
quite slow.


    {-# OPTIONS -cpp #-}

    import qualified Data.ByteString as B
    import Data.ByteString.Base (ByteString,unsafeTail,unsafeIndex)
    import Data.Char    -- seems to help!


    main = print . go 0 =<< B.getContents

    --
    -- A faster atoi
    --

    #define STRICT2(f) f a b | a `seq` b `seq` False = undefined

    STRICT2(go)
    go i ps
        | B.null ps = i
        | x == 45   = neg 0 xs
        | otherwise = pos (parse x) xs
        where
            (x, xs) = (ps `unsafeIndex` 0, unsafeTail ps)

            STRICT2(neg)
            neg n qs | x == 10     = go (i-n) xs
                     | otherwise   = neg (parse x + (10 * n)) xs
                     where (x, xs) = (qs `unsafeIndex` 0, unsafeTail qs)

            STRICT2(pos)
            pos n qs | x == 10   = go (i+n) xs
                     | otherwise = pos (parse x + (10 * n)) xs
                     where (x, xs) = (qs `unsafeIndex` 0, unsafeTail qs)

    parse w = fromIntegral (w - 48) :: Int
    {-# INLINE parse #-}

Comparing the running times:

    GCC -O2
    $ time ./c < /home/dons/src/shootout/sum/in
    1280000
    ./c < /home/dons/src/shootout/sum/in  0.67s user 0.02s system 99% cpu 0.692 total

    GHC -O2
    $ time ./sum < /home/dons/src/shootout/sum/in
    1280000
    ./sum < /home/dons/src/shootout/sum/in  0.18s user 0.05s system 92% cpu 0.254 total

-- Don


More information about the Cvs-ghc mailing list