Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does performance drop when a function is moved to another module?

I am observing that the same fn gives different performance, depending on whether it's placed in the same module where it's used or in a module next to it. Any ideas what could be causing it?

Here's the function: https://github.com/oshyshko/polymodperf/blob/master/src/Main.hs#L41-L55

test :: MArray a t m => (t -> t) -> a Int t -> m ()
test f a =
    mapM_ (\ xy -> do
              v <- get a xy
              set a xy (f v))

          [ (x,y) | y <- [0..1000 - 1],
                    x <- [0..1000 - 1],
                    n <- [0..10]]
  where
    get :: MArray a e m => a Int e -> (Int, Int) -> m e
    get a (x,y) = readArray a (x + y * 1000)

    set :: MArray a e m => a Int e -> (Int, Int) -> e -> m ()
    set a (x,y) = writeArray a (x + y * 1000)

In my test pass I use Data.Array.IO.newArray to create an array, then pass it to test.

Here's how to observe the difference in performance (second value, ms):

$ ./scripts/build-exec.sh
...
Main.test
(11000000,2010)
(11000000,239)
(11000000,240)
(11000000,242)
(11000000,237)

SomeModule.test
(11000000,6376)
(11000000,4851)
(11000000,5455)
(11000000,5096)
(11000000,5206)
  • Main.test: both newArray and test both live in Main => okay performance (the first 2010ms run is probably bad due to warmup, but the rest look good)
  • SomeModule.test: newArray lives in Main, but test is imported from SomeModule.test => much worse performance

The code of test is identical in both modules: https://github.com/oshyshko/polymodperf/blob/master/src/Main.hs#L41-L55 https://github.com/oshyshko/polymodperf/blob/master/src/SomeModule.hs#L9-L17

The used MArray typeclass and fns readArray, writeArray imported from the same module in both cases:

import           Data.Array.MArray (MArray, readArray, writeArray)

Any ideas what could be causing the difference in performance?

like image 469
oshyshko Avatar asked May 27 '19 08:05

oshyshko


1 Answers

As leftaroundabout suggested in a comment, adding INLINE pragma solved the problem:

test :: MArray a t m => (t -> t) -> a Int t -> m ()
{-# INLINE test #-}
test f a =
    ...

https://github.com/oshyshko/polymodperf/blob/master/src/SomeModule.hs#L10

like image 130
oshyshko Avatar answered Oct 26 '22 10:10

oshyshko