Почему производительность падает, когда функция перемещается в другой модуль? - PullRequest
6 голосов
/ 27 мая 2019

Я наблюдаю, что один и тот же fn дает разную производительность в зависимости от того, находится ли он в том же модуле, где он используется, или в модуле рядом с ним.Любые идеи, что может быть причиной этого?

Вот функция: 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)

В моем тестовом проходе я использую Data.Array.IO.newArray, чтобы создать массив, а затем передать его test.

Вот как можно наблюдать разницу в производительности (второе значение, мс):

$ ./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: оба newArray и test оба живут вMain => нормально, производительность (первый прогон 2010 мс, вероятно, плох из-за прогрева, но остальные выглядят хорошо)
  • SomeModule.test: newArray живет в Main, но test импортируетсяот SomeModule.test => гораздо худшая производительность

Код test одинаков в обоих модулях: https://github.com/oshyshko/polymodperf/blob/master/src/Main.hs#L41-L55 https://github.com/oshyshko/polymodperf/blob/master/src/SomeModule.hs#L9-L17

Используемый MArrayКлассы типов и fns readArray, writeArray импортированы из одного и того же модуля в обоих случаях:

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

Есть идеи, что может вызвать разницу в производительности?

1 Ответ

5 голосов
/ 27 мая 2019

Как указано в комментарии leftaroundabout, добавление INLINE прагмы решило проблему:

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

...