2014-01-12 2 views
154

GHC에서 클래스 제약 조건으로 함수를 특수화하는 데 문제가 있습니다. 여기에 내 문제의 최소한의 예가 있습니다 : Foo.hsMain.hs. 두 파일을 컴파일하고 (GHC 7.6.2, ghc -O3 Main) 실행하십시오.제약 조건의 특수화

참고 : Foo.hs은 실제로 삭제되었습니다. 제약 조건이 필요한 이유를 알고 싶다면 here 코드를 조금 더 볼 수 있습니다. 단일 파일에 코드를 삽입하거나 다른 많은 사소한 변경을하면 GHC는 plusFastCyc에 대한 호출을 간단히 설명합니다. plusFastCyc은 GHC가 인라인하기에는 너무 커서 심지어 INLINE으로 표시된 경우에도 실제 코드에서는 발생하지 않습니다. 요점은 plusFastCyc에 대한 호출을 전문으로하지 인라인하지 않습니다. plusFastCyc은 실제 코드의 여러 위치에서 호출되므로 GHC에 강제로 적용 할 수있는 경우에도 그러한 큰 함수를 복제하는 것은 바람직하지 않습니다.

관심의 코드는 여기 재현, Foo.hs에서 plusFastCyc입니다 :

{-# 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 파일은 두 드라이버가 있습니다 ~ 83초 경우에 실행되는 2 ~ 3 초 실행 vtTest, 및 fcTest을, forall 'd 전문화를 사용하여 -O3로 컴파일됩니다.

다음은 vtTest 시험, 추가 코드가 Unboxed 벡터에 전문되는 core showsInt 이상들, 등, 일반적인 벡터 코드는 fcTest에 사용된다. 라인 10에서 GHC가 라인 167의 일반 버전과 비교하여 plusFastCyc의 특수 버전을 작성하고 있음을 알 수 있습니다. 전문화 규칙은 225 행에 있습니다.이 규칙은 270 행에서 실행되어야합니다. (main6iterate main8 y를 호출, 그래서 plusFastCyc는 전문해야하는 위치 main8입니다.)

내 목표는 plusFastCyc을 전문으로 빨리 vtTestfcTest을 확인하는 것입니다. fcTest에서 GHC.Exts에서

  1. 명시 적으로 호출 inline :이 두 가지 방법을 발견했습니다.
  2. plusFastCycFactored m Int 제약 조건을 제거하십시오.

옵션 1은 실제 코드베이스 plusFastCyc 매우 큰 기능은 자주 사용하는 작업을하고 있기 때문에 불충분하므로 이는 모든 용도에서 인라인 안된다. 오히려 GHC는 plusFastCyc의 특수 버전을 호출해야합니다. 옵션 2는 실제 코드에서 제약 조건을 필요로하기 때문에 실제로 옵션이 아닙니다.

나는 (사용하지 않고) INLINE, INLINABLESPECIALIZE을 사용하여 다양한 옵션을 시도했지만 아무 것도 작동하지 않는 것 같습니다. (EDIT : 예제를 작게 만들기 위해 plusFastCyc을 너무 많이 사용하지 않았기 때문에 INLINE은 함수가 인라인 될 수 있습니다. plusFastCyc이 너무 커서 실제 코드에서는 그렇지 않습니다.)이 예제에서는 예제를 최소화하기 전에 많은 match_co 경고가 발생했지만 어떤 match_co: needs more cases 또는 RULE: LHS too complicated to desugar (및 here) 경고도 표시되지 않습니다. 아마도 "문제"는 규칙의 Factored m Int 제약 조건입니다. 해당 제약 조건을 변경하면 fcTestvtTest만큼 빠르게 실행됩니다.

GHC에서 뭔가를하고 있습니까? GHC가 plusFastCyc을 전문으로하지 않는 이유는 무엇입니까? 어떻게 만들 수 있습니까?

UPDATE

문제는 GHC 7.8.2에서 계속 때문에이 질문은 여전히 ​​관련이있다.

+3

방금 ​​* 특정 * m을 전문으로 해 보았습니다. 즉 M입니다. 이 작업은 끝났지 만, 실제 프로그램에서 구체화 된 특정 팬텀 유형을 전문으로 할 수는 없습니다. – crockeea

+0

또한 GHC 버그 보고서 https://ghc.haskell.org/trac/ghc/ticket/8668도 제출했지만 문제는 여전히 열려 있습니다. 버그보고 프로세스를 통해 질문을 정리하는 데 도움이되었으므로 문제가 무엇인지 파악하는 것이 더 쉬워졌습니다. – crockeea

+0

@monojohnny 죄송합니다. 신고 해 주셔서 감사합니다. 저는 GHC에 공정하게 합당한 일을하도록 요구하고 있습니다. 그렇게하지 않을 것입니다. 나는 잘못하고 있는지, 또는 이것이 임시 해결책이 될지도 모르는 컴파일러와의 특이한면이 확실하지 않다. 나는 지금 특정 분야의 도서관에서 전문화와 규칙에 대한 대안을 보았습니다. 그래서 나 자신보다 더 많은 GHC 경험을 가진 커뮤니티의 누군가가 전문 분야를 성취하는 방법을 알고있을 수도 있습니다. – crockeea

답변

4

또한 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 

이 변화하지만, 원하는 속도 향상을 달성하지 않았다.

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

LANGUAGEOverlappingInstancesFlexibleInstances를 추가해야합니다 다음과 같이 무슨 성능 향상을 달성 한 것은, 같은 함수 정의와 유형 VT U.Vector m Int에 대한 전문 인스턴스를 추가 수동으로했다.

흥미롭게도 예제 프로그램에서 중복 된 인스턴스로 얻은 속도 향상은 모든 SPECIALIZEINLINABLE 플러그를 제거해도 남아 있습니다.

+0

확실히 최적은 아니지만 실제로 목표를 달성 한 첫 번째 솔루션이므로 지금 당장 가져갈 것입니다. – crockeea

관련 문제