Archive for março \14\UTC 2010

Another interesting code using Template Haskell

14/3/2010 (domingo)

While writing the post about performance, I got interested in Template Haskell, specially in the $(lift) construction.  Investigating a little bit about it, I got to the following code:

{-# LANGUAGE TemplateHaskell #-}

import Language.Haskell.TH.Syntax
import X

main :: IO ()
main = print $(lift $ x)

With X.hs:

module X where

import System.IO.Unsafe

x :: Int
x = read $ unsafePerformIO $ putStr "Number: " >> getLine

The result was a surprise to me. It asked for the number in compilation time.

$ ghc --make main
[2 of 2] Compiling Main             ( main.hs, main.o )
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package array-0.3.0.0 ... linking ... done.
Loading package containers-0.3.0.0 ... linking ... done.
Loading package pretty-1.0.1.1 ... linking ... done.
Loading package template-haskell ... linking ... done.
Number: 5
Linking main ...
marcot@zezinho:~/codigo/haskell$ ./main
5

Anúncios

Performance of IORef

13/3/2010 (sábado)

I’ve tried to see how slower can ghc be compared to gcc in compiling a simple
imperative program. I’ve written this small test program in C:

/* loop.c */
#include 

int
main(int argc, char **argv)
{
    int i, j, k, t = 0;
    for(i = 0; i < 1000; i++)
        for(j = 0; j < 1000; j++)
            for(k = 0; k < 1000; k++)
                if(i * i + j * j + k * k % 7 == 0)
                    t++;
    printf("%d\n", t);
    return 0;
}

And a similar version in imperative Haskell, being as similar as possible to
the original C code:

-- loop.hs
import Control.Applicative
import Control.Monad
import Data.IORef

main :: IO ()
main
  = do
    i <- int
    j <- int
    k <- int
    t <- int
    for (i =: 0) (i <: 1000) (inc i)
      $ for (j =: 0) (j <: 1000) (inc j)
        $ for (k =: 0) (k <: 1000) (inc k)
          $ do
            i_ <- readIORef i
            j_ <- readIORef j
            k_  a -> IO ()
(=:) = writeIORef

( IORef a -> a -> IO Bool
i <: v = (< v)  readIORef i

inc :: Enum a => IORef a -> IO ()
inc i = modifyIORef i succ

for :: IO () -> IO Bool -> IO () -> IO () -> IO ()
for preface condition step code
  = preface >> for_ condition step code

for_ :: IO Bool -> IO () -> IO () -> IO ()
for_ condition step code
  = condition >>= flip when (code >> step >> for_ condition step code)

A functional version:

-- functional.hs
main :: IO ()
main
  = print
    $ length
      [i
        | i <- [0 :: Int .. 999]
          , j <- [0 .. 999]
          , k <- [0 .. 999]
          , i * i + j * j + k * k `mod` 7 == 0]

And a version using Template Haskell.

{-# LANGUAGE TemplateHaskell #-}

import Language.Haskell.TH.Syntax

main :: IO ()
main
  = print
    $ $(lift $ length
      [i
        | i <- [0 :: Int .. 999]
          , j <- [0 .. 999]
          , k <- [0 .. 999]
          , i * i + j * j + k * k `mod` 7 == 0])

The results:

$ time gcc -O3 -o loop -Wall loop.c

real    0m0.256s
user    0m0.148s
sys     0m0.040s
$ time ./loop
143

real    0m13.652s
user    0m11.629s
sys     0m0.052s
$ time ghc --make -O3 loop.hs

real    0m0.209s
user    0m0.160s
sys     0m0.020s
$ time ./loop
143

real    3m46.834s
user    3m24.313s
sys     0m0.712s
$ time ghc --make -O3 functional.hs
[1 of 1] Compiling Main             ( functional.hs, functional.o )
Linking functional ...

real    0m1.420s
user    0m1.016s
sys     0m0.220s
$ time ./functional
143

real    1m29.057s
user    1m25.809s
sys     0m0.224s
$ time ghc --make -O3 th.hs
[1 of 1] Compiling Main             ( th.hs, th.o )
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package array-0.3.0.0 ... linking ... done.
Loading package containers-0.3.0.0 ... linking ... done.
Loading package pretty-1.0.1.1 ... linking ... done.
Loading package template-haskell ... linking ... done.

real    90m54.226s
user    87m32.024s
sys     0m14.785s
marcot@zezinho:~/codigo/haskell$ time ./th
143

real    0m0.005s
user    0m0.000s
sys     0m0.004s

The time to build the code with TH is not the best, but the execution time
surely is. Maybe we could use this technic to improve the execution time of all
of the codes, interpreting a part of the code in build time automaticly,
without user indication.

The results in a table:

Version Build time (s) Execution time (s)
C 0.256 13.652
Imperative Haskell (IORefs) 0.209 136.834
Functional Haskell 1.420 89.057
Template Haskell 5454.226 0.005

Micro BSP

7/3/2010 (domingo)

I and Rafael Cunha de Almeida got together today with the purpose of closing as much RC-bugs in Debian as we could.  I must say it was better than what I’d expect.

We started with #570348 .  This bug was introduce with an upload that tried to fix #569586 which, in turn, was related to a change in libc6.  It would be easy to introduce an ifdef in the code but, as we tried to read and understand the code, we didn’t see the need of the function that was causing the problem.  It seems to make the same thing as alphasort from dirent.h, with the disadavantage that it was not locale-sensitive.  So we removed the customized alphasort and made it use the library one.

Then we headed to the strange #504947.  As the maintainer didn’t seem satisfied with the new patch system introduced by the last NMU, we simply made a patch that removes the patch system and applies the patch directly in .diff.gz.  Hope it helps.

Searching for another thing to work, we noticed that #571791 was not happening in my box, and asked if anyone could reproduce it.

So we found #571748.  The first thing about this bug we noticed is that its package causes a division by 0 error in popcon, which made us report a bug about it.  We thought that this was a sign that the package was not widely used.  Anyway, we decided to fix this bug, which was very fun indeed!  After a lot of trials, some succesful, some not, we got to a very simple and nice patch, which was submitted.  We also submited other bugs to the same package, that we found while using it.  It’s a cool package, you should try it out to avoid that division by 0 in popcon.