2015-03-23 17 views
9

Mam kod, który wykonuje pewne parsowanie plików zgodnie z określonymi regułami. Całe parsowanie odbywa się w monadzie, która jest stosem ReaderT/STTrans/ErrorT.Generalizując monadę, wydajność spada prawie o 50%.

type RunningRule s a = ReaderT (STRef s LocalVarMap) (STT s (ErrorT String Identity)) a 

Ponieważ byłoby przydatne do uruchomienia niektórych IO w kodzie (np zapytań do zewnętrznych baz danych), myślałem, że chciałbym generalizować parsowania, tak aby mógł on działać zarówno w systemie ewidencji ludności lub IO bazowej monady, w zależności od funkcjonalność, której pragnę. Zmieniło to podpis:

type RunningRule s m a = ReaderT (STRef s LocalVarMap) (STT s (ErrorT String m)) a 

Po zmianie odpowiednie podpisy typu (i korzystania z niektórych rozszerzeń, aby ominąć typów) Pobiegłem go ponownie w monady Identity i było ~ 50% wolniej. Chociaż zasadniczo nic się nie zmieniło, jest znacznie wolniej. Czy to normalne zachowanie? Czy jest jakiś prosty sposób, aby uczynić to szybszym? (np. łączenie stosu ErrorT i ReaderT (i prawdopodobnie STT) w jeden transformator monad?)

Aby dodać próbkę kodu - jest to rzecz, która na podstawie przeanalizowanego wejścia (podanego w języku C) konstruuje parser. Kod wygląda następująco:

+1

Czy kompilowałeś z optymalizacją i profilowałeś ją z kryterium? Jakie kroki profilowania podjęto, aby znaleźć to spowolnienie? – bheklilr

+1

Skompilowany z optymalizacjami, włączonym profilowaniem i uruchomionym z + RTS -p, porównywał wyjścia - wynik sugerował głównie nic (poza tym prawdopodobnie ma coś wspólnego z monadami). Użyłem ogólnego "czasu", aby sprawdzić wydajność, na moich danych testowych zajęło to 2 sekundy z "zakodowaną tożsamością" i 3 sekundy, gdy pozwolono ustawić monadę tożsamości jako "parametr". – ondra

+0

"i używanie niektórych rozszerzeń do obejścia typów" <- może oznaczać, że coś się zmieniło. Rozszerzony przykład kodu może pomóc szybciej znaleźć wyjaśnienie. –

Odpowiedz

12

To nie jest takie niezwykłe, nie. Powinieneś spróbować użyć pragma SPECIALIZE, aby specjalizować się w Identity, a może także IO. Użyj -ddump-simpl i uważaj na ostrzeżenia o lewych stronach reguły, które są zbyt skomplikowane. Gdy specjalizacja nie odbywa się tak, jak powinna, GHC kończy się przekazywaniem słowników typu "typeclass" w czasie wykonywania. Jest to z natury nieco nieefektywne, ale co ważniejsze, uniemożliwia GHC wprowadzanie metod klasy w celu dalszego uproszczenia.

+0

Próbowałem dodać, wydaje się, że działało w tym sensie, że ddump-simpl wydaje się pokazywać, że jest rzeczywiście wyspecjalizowany (musiał również dodać INLINABLE). Miało znikomy wpływ na wydajność. Chodzi o to, że buduję wiele wyrażeń lambda działających w tej monadzie, może oni nie specjalizują się? – ondra

+1

Myślę, że powinniśmy faktycznie porównać oryginalny kod do uogólnionego. – dfeuer

+0

@ondra, zamierzałem wysłać ci wiadomość na ten ostatni komentarz. – dfeuer

Powiązane problemy