将单个记录字段更改为严格会导致性能下降

aug*_*tss 16 haskell

我有一个程序使用haskell-src-exts,并提高性能我决定严格记录字段.这导致了更糟糕的表现.

这是我正在改变的完整模块:

{-# LANGUAGE DeriveDataTypeable, BangPatterns #-}
module Cortex.Hackage.HaskellSrcExts.Language.Haskell.Exts.SrcSpan(
    SrcSpan, srcSpan, srcSpanFilename, srcSpanStartLine,
    srcSpanStartColumn, srcSpanEndLine, srcSpanEndColumn,
    ) where

import Control.DeepSeq
import Data.Data

data SrcSpan = SrcSpanX
    { srcSpanFilename    :: String
    , srcSpanStartLine   :: Int
    , srcSpanStartColumn :: Int
    , srcSpanEndLine     :: Int
    , srcSpanEndColumn   :: Int
    }
  deriving (Eq,Ord,Show,Typeable,Data)

srcSpan :: String -> Int -> Int -> Int -> Int -> SrcSpan
srcSpan fn !sl !sc !el !ec = SrcSpanX fn sl sc el ec

instance NFData SrcSpan where
    rnf (SrcSpanX x1 x2 x3 x4 x5) = rnf x1
Run Code Online (Sandbox Code Playgroud)

注意,构造a的唯一方法SrcSpan是使用srcSpan所有Ints中严格的函数.

使用此代码,我的程序(抱歉,我无法分享)运行在163s.

现在改变一行,例如,

    , srcSpanStartLine   :: !Int
Run Code Online (Sandbox Code Playgroud)

即,该srcSpanStartLine字段现在标记为严格.我的程序现在运行198秒.因此,严格控制一个字段会使运行时间增加约20%.

这怎么可能?srcSpan函数的代码应该是相同的,因为它已经是严格的.srcSpanStartLine选择器的代码应该更简单一些,因为它不再需要进行评估.

我已经尝试过-funbox-strict-fields,并-funbox-small-strict-field开启和关闭.它没有任何明显的区别.我正在使用ghc 7.8.3.

有没有人见过类似的东西?什么可能导致它的任何好主意?

aug*_*tss 15

通过一些更多的调查,我可以回答我自己的问题.简短的回答是单一的.

答案稍微长一些.在一个地方,我使用uniplate来获取a的孩子Pat(haskell-src-exts类型的模式).呼叫看起来像children p和本实例的类型childrenPat SrcSpanInfo -> [Pat SrcSpanInfo].所以它不进行递归,只返回节点的直接子节点.

Uniplate使用两种截然不同的方法,具体取决于操作类型中是否存在严格字段.如果没有严格的字段,它会很快合理,严格的字段会切换到使用状态gfoldl并且非常慢.即使我使用uniplate没有直接涉及严格的字段,它也放慢了速度.

结论:如果您在任何地方都有严格的视野,请注意提示!

  • 奇怪的是,geniplate是否不足以满足您的需求?它不会避免这个问题,并提供更好的表现吗? (3认同)