Ich habe Probleme, GHC dazu zu bringen, eine Funktion mit einer Klassenbeschränkung zu spezialisieren. Ich habe ein minimales Beispiel für mein Problem hier: Foo.hs und Main.hs . Die beiden Dateien werden kompiliert (GHC 7.6.2 ghc -O3 Main
) und ausgeführt.
HINWEIS:
Foo.hs
ist wirklich reduziert. Wenn Sie sehen möchten, warum die Einschränkung benötigt wird, können Sie hier etwas mehr Code sehen . Wenn ich den Code in eine einzelne Datei einfüge oder viele andere kleinere Änderungen vornehme, leitet GHC den Aufruf einfach an plusFastCyc
. Dies wird im realen Code nicht passieren, da plusFastCyc
GHC zu groß ist, um inline zu sein, selbst wenn es markiert ist INLINE
. Es geht darum , den Anruf zu spezialisieren plusFastCyc
und nicht zu inline. plusFastCyc
wird an vielen Stellen im realen Code aufgerufen, so dass das Duplizieren einer so großen Funktion nicht wünschenswert wäre, selbst wenn ich GHC dazu zwingen könnte.
Der Code von Interesse ist der plusFastCyc
in Foo.hs
, hier wiedergegebene:
{-# 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
Die Main.hs
Datei hat zwei Treiber: vtTest
die in ~ 3 Sekunden ausgeführt werden und fcTest
die in ~ 83 Sekunden ausgeführt werden, wenn sie mit -O3 unter Verwendung der forall
Spezialisierung 'd kompiliert werden .
Der Kern zeigt, dass für den vtTest
Test der Additionscode auf Unboxed
Vektoren über Int
s usw. spezialisiert ist, während für generischen Vektorcode verwendet wird fcTest
. In Zeile 10 können Sie sehen , dass GHC eine spezielle Version von schreibt plusFastCyc
, im Vergleich zu der generischen Version auf Linie 167. Die Regel für die Spezialisierung auf der Leitung 225. ich diese Regel glaube , auf der Linie 270. (Feuer soll main6
Anrufe iterate main8 y
, so main8
ist wo plusFastCyc
sollte spezialisiert werden.)
Mein Ziel ist es, fcTest
so schnell wie möglich zu vtTest
spezialisieren plusFastCyc
. Ich habe zwei Möglichkeiten gefunden, dies zu tun:
- Explicity Call
inline
vonGHC.Exts
infcTest
. - Entfernen Sie die
Factored m Int
Einschränkung aufplusFastCyc
.
Option 1 ist unbefriedigend, da es sich bei der eigentlichen Codebasis plusFastCyc
um eine häufig verwendete Operation und eine sehr große Funktion handelt, sodass sie nicht bei jeder Verwendung eingefügt werden sollte. Vielmehr sollte GHC eine spezielle Version von aufrufen plusFastCyc
. Option 2 ist nicht wirklich eine Option, da ich die Einschränkung im realen Code benötige.
Ich habe eine Vielzahl von Optionen versucht , mit (und nicht mit ) INLINE
, INLINABLE
und SPECIALIZE
, aber nichts scheint zu funktionieren. ( BEARBEITEN : Ich habe möglicherweise zu viel entfernt plusFastCyc
, um mein Beispiel klein zu machen, sodass INLINE
die Funktion möglicherweise inline ist. Dies geschieht in meinem realen Code nicht, weil er plusFastCyc
so groß ist.) In diesem speziellen Beispiel bin ich es nicht Erhalten von match_co: needs more cases
oder RULE: LHS too complicated to desugar
(und hier ) Warnungen, obwohl ich viele match_co
Warnungen erhalten habe, bevor ich das Beispiel minimiert habe. Vermutlich ist das "Problem" die Factored m Int
Einschränkung in der Regel; Wenn ich Änderungen an dieser Einschränkung vornehme, fcTest
läuft sie so schnell wie vtTest
.
Mache ich etwas, das GHC einfach nicht mag? Warum wird GHC das nicht spezialisieren plusFastCyc
und wie kann ich es machen?
AKTUALISIEREN
Das Problem besteht weiterhin in GHC 7.8.2, daher ist diese Frage immer noch relevant.
m
, nämlichM
. Dies hat die Arbeit erledigt, aber ich kann mich nicht auf bestimmte Phantomtypen im realen Programm spezialisieren, da diese bestätigt werden.Antworten:
GHC bietet auch eine Option für
SPECIALIZE
eine Instanzdeklaration der Typklasse. Ich habe dies mit dem (erweiterten) Code vonFoo.hs
versucht, indem ich Folgendes eingegeben habe:Diese Änderung erreichte jedoch nicht die gewünschte Beschleunigung. Durch diese Leistungsverbesserung wurde manuell eine spezielle Instanz für den Typ
VT U.Vector m Int
mit denselben Funktionsdefinitionen wie folgt hinzugefügt :Dies erfordert das Hinzufügen
OverlappingInstances
undFlexibleInstances
inLANGUAGE
.Interessanterweise bleibt im Beispielprogramm die mit der überlappenden Instanz erzielte Beschleunigung erhalten, auch wenn Sie alle
SPECIALIZE
undINLINABLE
Pragma entfernen .quelle