Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 单词foldl';isn';t优化以及Int foldl';_Haskell_Optimization_Ghc - Fatal编程技术网

Haskell 单词foldl';isn';t优化以及Int foldl';

Haskell 单词foldl';isn';t优化以及Int foldl';,haskell,optimization,ghc,Haskell,Optimization,Ghc,GHC优化了上述代码,使垃圾收集器甚至不必做任何事情: import Data.List test :: Int -> Int test n = foldl' (+) 0 [1..n] main :: IO () main = do print $ test $ 10^8 但是,如果我将test的类型更改为test::Word->Word,那么会产生大量垃圾,代码运行速度会慢40倍 $ ghc -rtsopts -O2 testInt && ./testInt +

GHC优化了上述代码,使垃圾收集器甚至不必做任何事情:

import Data.List

test :: Int -> Int
test n = foldl' (+) 0 [1..n]

main :: IO ()
main = do
  print $ test $ 10^8
但是,如果我将
test
的类型更改为
test::Word->Word
,那么会产生大量垃圾,代码运行速度会慢40倍

$ ghc -rtsopts -O2 testInt && ./testInt +RTS -s
[1 of 1] Compiling Main             ( testInt.hs, testInt.o )
Linking testInt ...
5000000050000000
          51,752 bytes allocated in the heap
           3,480 bytes copied during GC
          44,384 bytes maximum residency (1 sample(s))
          17,056 bytes maximum slop
               1 MB total memory in use (0 MB lost due to fragmentation)

                                     Tot time (elapsed)  Avg pause  Max pause
  Gen  0         0 colls,     0 par    0.000s   0.000s     0.0000s    0.0000s
  Gen  1         1 colls,     0 par    0.000s   0.000s     0.0001s    0.0001s

  INIT    time    0.000s  (  0.000s elapsed)
  MUT     time    0.101s  (  0.101s elapsed)
  GC      time    0.000s  (  0.000s elapsed)
  EXIT    time    0.000s  (  0.000s elapsed)
  Total   time    0.103s  (  0.102s elapsed)

  %GC     time       0.1%  (0.1% elapsed)

  Alloc rate    511,162 bytes per MUT second

  Productivity  99.8% of total user, 100.9% of total elapsed
为什么会发生这种情况?我以为表演会差不多一样? (我在x86_64 GNU/Linux上使用GHC 8.0.1版)


编辑:我提交了一个错误:

这可能主要是由于存在Int而不是Word的重写规则,尽管不是唯一的。我这么说是因为如果我们在
Int
的情况下使用
-fn不启用重写规则,我们得到的时间就比
Word
的情况更接近,但没有那么糟糕

ghc -rtsopts -O2 testWord && ./testWord +RTS -s
[1 of 1] Compiling Main             ( testWord.hs, testWord.o )
Linking testWord ...
5000000050000000
  11,200,051,784 bytes allocated in the heap
       1,055,520 bytes copied during GC
          44,384 bytes maximum residency (2 sample(s))
          21,152 bytes maximum slop
               1 MB total memory in use (0 MB lost due to fragmentation)

                                     Tot time (elapsed)  Avg pause  Max pause
  Gen  0     21700 colls,     0 par    0.077s   0.073s     0.0000s    0.0000s
  Gen  1         2 colls,     0 par    0.000s   0.000s     0.0001s    0.0001s

  INIT    time    0.000s  (  0.000s elapsed)
  MUT     time    4.551s  (  4.556s elapsed)
  GC      time    0.077s  (  0.073s elapsed)
  EXIT    time    0.000s  (  0.000s elapsed)
  Total   time    4.630s  (  4.630s elapsed)

  %GC     time       1.7%  (1.6% elapsed)

  Alloc rate    2,460,957,186 bytes per MUT second

  Productivity  98.3% of total user, 98.3% of total elapsed
如果我们使用
-ddump rule rewrite
转储重写规则并区分这些规则,那么我们会看到在
Int
案例中触发的规则,而不是在
Word
案例中触发的规则:

% ghc -O2 so.hs -fforce-recomp -fno-enable-rewrite-rules && time ./so
[1 of 1] Compiling Main             ( so.hs, so.o )
Linking so ...
5000000050000000
./so  1.45s user 0.03s system 99% cpu 1.489 total

该特定规则在4.9 GHC基线823中(注意,我自己实际上使用的是GHC 7.10),没有明确提到
Int
。我很好奇为什么它没有为
Word
开火,但现在没有时间进一步调查。

正如dfeuer在这里的评论中指出的那样,
Int
Enum
实例比
Word
的好:

Int

 Rule: fold/build
 Before: GHC.Base.foldr
 ...
现在
Word
实际上使用了
Integer的实现

instance  Enum Int  where
    {-# INLINE enumFromTo #-}
    enumFromTo (I# x) (I# y) = eftInt x y

{-# RULES
"eftInt"        [~1] forall x y. eftInt x y = build (\ c n -> eftIntFB c n x y)
"eftIntList"    [1] eftIntFB  (:) [] = eftInt
 #-}
{- Note [How the Enum rules work]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Phase 2: eftInt ---> build . eftIntFB
* Phase 1: inline build; eftIntFB (:) --> eftInt
* Phase 0: optionally inline eftInt
-}

{-# NOINLINE [1] eftInt #-}
eftInt :: Int# -> Int# -> [Int]
-- [x1..x2]
eftInt x0 y | isTrue# (x0 ># y) = []
            | otherwise         = go x0
               where
                 go x = I# x : if isTrue# (x ==# y)
                               then []
                               else go (x +# 1#)

{-# INLINE [0] eftIntFB #-}
eftIntFB :: (Int -> r -> r) -> r -> Int# -> Int# -> r
eftIntFB c n x0 y | isTrue# (x0 ># y) = n
                  | otherwise         = go x0
                 where
                   go x = I# x `c` if isTrue# (x ==# y)
                                   then n
                                   else go (x +# 1#)
                        -- Watch out for y=maxBound; hence ==, not >
        -- Be very careful not to have more than one "c"
        -- so that when eftInfFB is inlined we can inline
        -- whatever is bound to "c"
哪个使用

enumFromTo n1 n2       = map integerToWordX [wordToIntegerX n1 .. wordToIntegerX n2]
现在,
enumDeltaToInteger
已设置了重写规则,但事实证明,
Word
enumFromTo
从未内联,因此此设置不可能在此处融合


将此函数复制到我的测试代码中会导致GHC内联它,触发
折叠/构建
规则,并严重减少分配,但从和到
整数
(分配)的转换仍然存在。

在这两种情况下生成的核心是什么?您应该向GHC问题跟踪程序提交一个bug()。我提交了一个bug:这是Int-core和Word-core,我还没有研究过,但我打赌
Enum-Word
实例与
Enum-Int
实例不同,阻止枚举与
foldr
融合。首先,
Word
的实例通常首先将值转换为
整数
,然后将结果转换回
Word
。是的,
fold/build
非常重要。正是这种优化消除了在内存中创建列表的过程。很可能
Word
Enum
实现没有使用
build
。以上是7.10版本。使用8.0应该会稍微好一点,因为
remInteger
已经变得很严格了(请参阅)。您或我应该提交错误报告来为Word添加更有效的实例吗?已经完成了:
instance  Enum Integer  where
    enumFromTo x lim       = enumDeltaToInteger x 1     lim