Спеціалізація з обмеженнями


156

У мене виникають проблеми з отриманням GHC для спеціалізації функції з обмеженням класу. У мене є мінімальний приклад моєї проблеми тут: Foo.hs і Main.hs . Два файли компілюються (GHC 7.6.2, ghc -O3 Main) і запускаються.

ПРИМІТКА: Foo.hs дійсно позбавлений. Якщо ви хочете зрозуміти, для чого потрібне обмеження, ви можете побачити трохи більше коду тут . Якщо я поміщую код в один файл або вношу багато інших незначних змін, GHC просто вказує дзвінок на plusFastCyc. Це не відбудеться в реальному коді, оскільки plusFastCycвін занадто великий для вбудованого GHC, навіть коли він позначений INLINE. Суть у тому, щоб спеціалізувати виклик plusFastCyc, а не вбудовувати його. plusFastCycу багатьох місцях називається реальним кодом, тому дублювання такої великої функції було б небажаним, навіть якщо я можу змусити GHC це зробити.

Код становить інтерес plusFastCycв 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який працює за ~ 83 секунд при компілюванні з -O3 за допомогою forallспеціалізації 'd.

В ядрі показує , що для vtTestтесту, код поповнення спеціалізуючись на Unboxedвектори над Intс, і т.д., в той час як загальний вектором код використовується для fcTest. У рядку 10, ви можете побачити , що GHC чи написати спеціалізовану версію plusFastCyc, по порівнянні із загальною версією на лінії 167. Правило для спеціалізації по лінії 225. Я вважаю , це правило повинно стріляти по лінії 270. ( main6дзвінки iterate main8 y, так main8це де plusFastCycслід спеціалізуватися.)

Моя мета - зробити fcTestтак швидко, як vtTestспеціалізуватися plusFastCyc. Я знайшов два способи зробити це:

  1. У явній формі виклику inlineз GHC.Extsв fcTest.
  2. Видаліть Factored m Intобмеження plusFastCyc.

Варіант 1 незадовільний, оскільки в дійсній базі коду plusFastCycє часто використовувана операція і дуже велика функція, тому її не слід вказувати при кожному використанні. Швидше за все, GHC має викликати спеціалізовану версію plusFastCyc. Варіант 2 насправді не є варіантом, тому що мені потрібно обмеження в реальному коді.

Я пробував різні варіанти використання (і не використовувати) INLINE, INLINABLEі SPECIALIZE, але нічого не схоже на роботу. ( EDIT : я, можливо, позбавив себе занадто багато, plusFastCycщоб зробити мій приклад малим, тому це INLINEможе призвести до того, що функція буде вписана. Це не відбувається в моєму реальному коді, оскільки plusFastCycтакий великий.) У цьому конкретному прикладі я не отримувати будь-які match_co: needs more casesабо RULE: LHS too complicated to desugarтут ) попередження, хоча я отримував багато match_coпопереджень, перш ніж мінімізувати приклад. Імовірно, "проблема" є Factored m Intобмеженням у праві; якщо я вношу зміни до цього обмеження, fcTestпрацює так само швидко vtTest.

Мені щось робити GHC просто не подобається? Чому GHC не спеціалізується plusFastCyc, і як це зробити?

ОНОВЛЕННЯ

Проблема зберігається в GHC 7.8.2, тому це питання все ще є актуальним.


3
Я просто спробував спеціалізуватися на конкретній m , а саме M. З цим було виконано завдання, але я не можу спеціалізуватися на конкретних фантомних типах у реальній програмі, оскільки вони переробляються.
крокей

Я також подав звіт про помилки GHC ghc.haskell.org/trac/ghc/ticket/8668, але проблема все ще залишається відкритою. Процес повідомлення про помилки допоміг мені трохи прибрати питання, тому, сподіваюся, буде легше розібратися, що відбувається.
crockeea

@monojohnny Вибачте, почувши це, я вважаю, що ви можете позначити це як таке. Я думаю, що я прошу GHC зробити щось досить розумне, і це не зробить. Я не впевнений, чи роблю це неправильно, чи це ідіосинкразія з компілятором, яка може мати вирішення. Я бачив шляхові шляхи спеціалізації та правил у певній бібліотеці щодо викрадення, яка мені зараз уникає, тому я сподіваюся, що хтось із громади, що має більше досвіду GHC, ніж я, можливо, знаю, як досягти спеціалізації.
crockeea

1
Я прошу вибачення за тон свого коментаря - це не мій найкращий внесок на цей сайт - з вашою публікацією насправді немає нічого поганого (я думаю, саме моє нерозуміння було джерелом мого роздратування!)
monojohnny

@monojohnny Вибачення прийнято, але це дуже погано, що downvote заблокований зараз ;-)
crockeea

Відповіді:


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

Для цього потрібно додати OverlappingInstancesі FlexibleInstancesв LANGUAGE.

Цікаво, що у прикладі програми прискорення, отримане із екземпляром, що перекривається, залишається навіть у тому випадку, якщо ви видалите всі SPECIALIZEта INLINABLEпрагми.


Однозначно не оптимально, але це перше рішення, яке реально досягає мети, тому, мабуть, я зараз
прийму
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.