Kısıtlı Uzmanlaşma


156

Sınıf kısıtlaması olan bir işlevi uzmanlaştırmak için GHC elde etmekte sorun yaşıyorum. Benim burada sorunun minimal örnek var: Foo.hs ve Main.hs . İki dosya derlenir (GHC 7.6.2, ghc -O3 Main) ve çalıştırılır.

NOT: Foo.hs gerçekten soyulmuş. Kısıtlamanın neden gerekli olduğunu görmek istiyorsanız, burada biraz daha kod görebilirsiniz . Kodu tek bir dosyaya koyarsam veya başka birçok küçük değişiklik yaparsam, GHC sadece çağrıyı sıralar plusFastCyc. Gerçek kodda bu gerçekleşmeyecektir, çünkü plusFastCycişaretlendiğinde bile GHC'nin satır içi olması için çok büyüktür INLINE. Mesele, satıriçi değil , çağrıyı uzmanlaştırmaktırplusFastCyc . plusFastCycgerçek kodda birçok yerde çağrılır, bu yüzden GHC'yi bunu yapmaya zorlayabilsem bile böyle büyük bir işlevi çoğaltmak istenmez.

İlgi kodudur plusFastCyciçinde Foo.hsburada çoğaltılamaz,:

{-# 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: Dosya, iki sürücüye sahip vtTest, ~ 3 saniye içinde çalışır, ve fcTestkullanılarak -o3 ile derlenmiş ~ 83 saniye içinde çalıştığı, foralld' uzmanlık.

Çekirdek gösterir için vtTesttest ilaveli kodu için özel olan Unboxedfazla vektörleri Intgenel vektör kod için kullanılır ise, vb s, fcTest. Hat 10 üzerinde, GHC bir uzman versiyonunu yazıyor görebilirsiniz plusFastCycBu kural hattı 270. (tetiklenmesi gereken inanıyoruz hat uzmanlık için kural hattı 225 üzerinde 167. jenerik sürümüne göre, main6aramalar iterate main8 yböylece, main8olduğu nerede plusFastCycuzmanlaşmalı.)

Amacım uzmanlaşmak fcTestkadar hızlı yapmak . Bunu yapmanın iki yolunu buldum:vtTestplusFastCyc

  1. Explicity çağrı inlinegelen GHC.Extsiçinde fcTest.
  2. Factored m IntÜzerindeki kısıtlamayı kaldırın plusFastCyc.

Seçenek 1 tatmin edici değildir, çünkü gerçek kod tabanında plusFastCycsık kullanılan bir işlem ve çok büyük bir işlevdir, bu nedenle her kullanımda satır içi olmamalıdır. Aksine, GHC'nin özel bir sürümünü çağırmalıdır plusFastCyc. Seçenek 2 gerçekten bir seçenek değil çünkü gerçek kod kısıtlaması gerekir.

Ben kullanarak (ve kullanmayan) çeşitli seçenekler denedim INLINE, INLINABLEve SPECIALIZE, ama hiçbir şey işe görünüyor. ( EDIT : plusFastCycBenim örnek küçük yapmak için çok fazla INLINEsıyırmış olabilir , bu nedenle işlevin satır içine neden olabilir. Bu benim gerçek kodda gerçekleşmez çünkü plusFastCycçok büyük.) Bu özel örnekte, ben değilim Herhangi bir match_co: needs more casesveya RULE: LHS too complicated to desugar(ve burada ) uyarı alıyorum, ancak match_coörneği en aza indirmeden önce birçok uyarı alıyordum . Muhtemelen, "problem" Factored m Intkuraldaki kısıtlamadır; bu kısıtlamada değişiklik yaparsam, bu fcTestkadar hızlı çalışır vtTest.

GHC'nin sevmediği bir şey mi yapıyorum? GHC neden uzmanlaşmıyor plusFastCycve bunu nasıl yapabilirim?

GÜNCELLEME

GHC 7.8.2'de sorun devam etmektedir, bu nedenle bu soru hala geçerlidir.


3
Sadece için uzmanlaşmış çalıştı özgü m yani M. Bu iş bitti, ama gerçek programdaki belirli fantom türleri için uzmanlaşamıyorum.
crockeea

Ayrıca bir GHC hata raporu ghc.haskell.org/trac/ghc/ticket/8668 gönderdim, ancak sorun hala açık. Hata raporu süreci soruyu biraz temizlememe yardımcı oldu, umarım neler olup bittiğini anlamak daha kolay olacaktır.
crockeea

@monojohnny Bunu duyduğuma üzüldüm, sanırım böyle işaretleyebilirsin. Sanırım GHC'den oldukça makul bir şey yapmasını istiyorum ve yapmayacak. Yanlış mı yapıyorum yoksa bu derleyici ile bir geçici çözüm olabilir bir idiosyncrasy olup olmadığından emin değilim. Şu anda kaçan hackage üzerinde belirli bir kütüphanede uzmanlık ve kurallar için geçici çözümler gördüm, bu yüzden toplulukta birisinin kendimi nasıl uzmanlaşacağını bildiğimden daha fazla GHC deneyimine sahip olmasını umuyorum.
crockeea

1
Yorumumun tonu için özür dilerim - bu siteye en iyi
katkım değil

@monojohnny Özür kabul etti, ancak downvote'un şimdi kilitli olması çok kötü ;-)
crockeea

Yanıtlar:


5

GHC ayrıca SPECIALIZEbir tür sınıf örneği bildirimi için bir seçenek sunar . Foo.hsAşağıdaki koyarak, (genişletilmiş) kodu ile denedim :

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

Ancak bu değişiklik istenen hızlanmayı başaramadı. Performans iyileştirmesini sağlayan, aşağıdaki gibi aynı işlev tanımlarına sahip tür için özel bir örneği el ile eklemektir 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

Bu ekleme gerektirir OverlappingInstancesve FlexibleInstancesde LANGUAGE.

İlginç bir şekilde, örnek programda, üst üste binen örnekle elde edilen hızlanma, her birini SPECIALIZEve INLINABLEpragmayı kaldırsanız bile kalır .


Kesinlikle optimal değil, ama aslında hedefe ulaşan ilk çözüm, bu yüzden sanırım şimdilik alacağım ...
crockeea
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.