development

제약이있는 전문화

big-blog 2020. 6. 8. 07:57
반응형

제약이있는 전문화


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

참고 : Foo.hs 실제로 제거되었습니다. 제약 조건이 필요한 이유를 보려면 여기에서 더 많은 코드를 볼 수 있습니다 . 코드를 단일 파일에 넣거나 다른 많은 사소한 변경을 수행하면 GHC는 단순히 호출을 인라인합니다 plusFastCyc. 실제 코드에서는 표시되지 않은 경우 plusFastCyc에도 GHC가 인라인 하기 에 너무 커서이 문제 발생하지 않습니다 INLINE. 요점은 인라인이 아닌에 대한 호출 특수화 하는 plusFastCyc것입니다. plusFastCyc실제 코드의 많은 곳에서 호출되므로 GHC가 강제로 수행 할 수 있다고해도 그러한 큰 기능을 복제하는 것은 바람직하지 않습니다.

관심의 코드입니다 plusFastCycFoo.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, 2 ~ 3 초 실행하고 fcTest사용 -O3으로 컴파일시 ~ 83초에서 실행되는, forall'D 전문화.

핵심 쇼 에 대한 vtTest테스트, 추가 코드가 전문화되고있는 Unboxed이상 벡터 Int일반적인 벡터 코드가 사용되는 동안, 등의, fcTest. 라인 (10)에, 당신은 GHC이의 전문 버전 쓰기 않는 것을 볼 수 있습니다 plusFastCyc나는이 규칙이 라인 (270) (에 발사한다고 생각 라인 전문화에 대한 규칙은 라인 225에 167의 일반 버전에 비해 main6통화 iterate main8 y그래서 main8입니다 plusFastCyc전문화해야 할 )

내 목표는 전문화 하여 fcTest최대한 빨리 만드는 것 vtTest입니다 plusFastCyc. 이 작업을 수행하는 두 가지 방법을 찾았습니다.

  1. 명시 적으로 호출 inline에서 GHC.Exts에서 fcTest.
  2. Factored m Int제약 조건을 제거하십시오 plusFastCyc.

실제 코드 기반 plusFastCyc에서 자주 사용되는 작업이고 매우 큰 기능 이기 때문에 옵션 1은 만족스럽지 않으므로 매번 사용할 때마다 인라인되지 않아야합니다. 대신 GHC는의 특수 버전을 호출해야합니다 plusFastCyc. 실제 코드에는 제약 조건이 필요하기 때문에 옵션 2는 실제로 옵션이 아닙니다.

내가 사용하는 (그리고 사용하지 않는) 다양한 옵션을 시도했습니다 INLINE, INLINABLE그리고 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에서도 문제가 지속되므로이 질문은 여전히 ​​관련이 있습니다.


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

OverlappingInstances그리고 FlexibleInstances추가가 필요합니다 LANGUAGE.

Interestingly, in the example program, the speedup obtained with the overlapping instance remains even if you remove every SPECIALIZE and INLINABLE pragma.

참고URL : https://stackoverflow.com/questions/21071706/specialization-with-constraints

반응형