有约束的专业化


156

我在让GHC专门化具有类约束的函数时遇到问题。我有我的问题的一个小例子,在这里:Foo.hsMain.hs。这两个文件将编译(GHC 7.6.2,ghc -O3 Main)并运行。

注意: Foo.hs真的被剥夺了。如果您想了解为什么需要约束,可以在此处查看更多代码。如果我将代码放在单个文件中或进行许多其他小的更改,GHC只会内联对的调用plusFastCyc。在实际代码中不会发生这种情况,因为plusFastCyc即使GHC标记为,也无法内联INLINE。关键是要专门针对plusFastCyc,而不是内联它。plusFastCyc在实际代码中的很多地方都调用了,因此即使希望强制GHC进行复制,也无法复制这么大的函数。

感兴趣的代码是plusFastCycin Foo.hs,在此处复制:

{-# INLINEABLE plusFastCyc #-}
{-# SPECIALIZE plusFastCyc :: 
         forall m . (Factored m Int) => 
              (FastCyc (VT U.Vector m) Int) -> 
                   (FastCyc (VT U.Vector m) Int) -> 
                        (FastCyc (VT U.Vector m) Int) #-}

-- Although the next specialization makes `fcTest` fast,
-- it isn't useful to me in my real program because the phantom type M is reified
-- {-# SPECIALIZE plusFastCyc :: 
--          FastCyc (VT U.Vector M) Int -> 
--               FastCyc (VT U.Vector M) Int -> 
--                    FastCyc (VT U.Vector M) Int #-}

plusFastCyc :: (Num (t r)) => (FastCyc t r) -> (FastCyc t r) -> (FastCyc t r)
plusFastCyc (PowBasis v1) (PowBasis v2) = PowBasis $ v1 + v2

Main.hs文件有两个驱动程序:vtTest,运行时间约为3秒,而fcTest使用-O3使用forall'd专业化条件进行编译,则运行时间约为83秒。

核心显示了,对于vtTest测试,添加代码被专用于Unboxed在载体IntS,等,而通用向量代码是用于fcTest。第10行,你可以看到,GHC确实写的专用版本plusFastCyc,相比上线167对专业化的规则是上线225的通用版本,我相信这个规则会被触发线270(main6电话iterate main8 y,所以main8plusFastCyc应该在哪里专门。)

我的目标是做到fcTestvtTest专精一样快plusFastCyc。我发现了两种方法可以做到这一点:

  1. inline来自GHC.Exts中的显式调用fcTest
  2. 取消对的Factored m Int约束plusFastCyc

选项1不能令人满意,因为在实际的代码库中,这plusFastCyc是一个经常使用的操作并且功能非常大,因此不应在每次使用时都内联它。相反,GHC应该调用的专用版本plusFastCyc。选项2并不是真正的选项,因为我需要实际代码中的约束。

我已经尝试了多种选择使用(而不是使用)INLINEINLINABLE以及SPECIALIZE,但似乎没有任何工作。(编辑plusFastCyc为了使我的示例变小,我可能去除了太多内容,因此INLINE可能导致函数内联。在我的真实代码中不会发生这种情况,因为plusFastCyc它太大了。)在此示例中,我不是收到任何match_co: needs more casesRULE: LHS too complicated to desugar(和此处)警告,尽管match_co在最小化示例之前我收到了很多警告。大概,“问题”是Factored m Int规则中的约束;如果我对该约束进行更改,则fcTest运行速度与一样快vtTest

我在做GHC不喜欢的事情吗?GHC为什么不专门研究plusFastCyc,我该怎么做?

更新

该问题在GHC 7.8.2中仍然存在,因此此问题仍然相关。


3
我只是尝试专门针对某个特定领域 m,即M。这样就完成了工作,但是我无法在实际程序中专门研究特定的幻像类型,因为它们已经被具体化了。
crockeea 2014年

我还提交了一份GHC错误报告ghc.haskell.org/trac/ghc/ticket/8668,但问题仍然存在。错误报告流程帮助我稍微澄清了一下问题,因此希望可以更轻松地弄清楚发生了什么。
crockeea 2014年

@monojohnny对不起,我相信您可以将其标记为此类。我想我要的是GHC做相当合理的事情,而它不会这样做。我不确定是否做错了,或者这是否与可能具有解决方法的编译器特质有关。我已经在一些关于黑客的特定库中看到了专门化的解决方法和规则,这些信息现在让我无所适从,所以我希望社区中比我本人拥有更多GHC经验的人可能会知道如何实现专门化。
crockeea 2014年

1
对于所发表的言论,我深表歉意-这不是我对该网站的最大贡献-您的帖子确实没有错(我猜是我缺乏理解,
这才

@monojohnny道歉已接受,但很遗憾现在无法锁定downvote ;-)
crockeea 2014年

Answers:


5

GHC还为SPECIALIZE类型类实例声明提供了一个选项。我使用的(扩展)代码尝试了此操作,方法Foo.hs如下:

instance (Num r, V.Vector v r, Factored m r) => Num (VT v m r) where 
    {-# SPECIALIZE instance ( Factored m Int => Num (VT U.Vector m Int)) #-}
    VT x + VT y = VT $ V.zipWith (+) x y

但是,此更改未实现所需的加速。确实实现了性能改进,是为具有相同功能定义的类型手动添加了一个专用实例VT U.Vector m Int,如下所示:

instance (Factored m Int) => Num (VT U.Vector m Int) where 
    VT x + VT y = VT $ V.zipWith (+) x y

这就需要增加OverlappingInstancesFlexibleInstancesLANGUAGE

有趣的是,在示例程序中,即使您删除了每一个SPECIALIZEINLINABLE编译指示,通过重叠实例获得的加速仍然保持。


绝对不是最优的,但这是实际上达到目标的第一个解决方案,所以我想现在就考虑一下……
crockeea 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.