Ancora lavorando sulla mia implementazione SHA1 in Haskell. Ora ho un'implementazione di lavoro e questo è il ciclo interno:Ottimizzazione dei loop interni Haskell
iterateBlock' :: Int -> [Word32] -> Word32 -> Word32 -> Word32 -> Word32 -> Word32 -> [Word32]
iterateBlock' 80 ws a b c d e = [a, b, c, d, e]
iterateBlock' t (w:ws) a b c d e = iterateBlock' (t+1) ws a' b' c' d' e'
where
a' = rotate a 5 + f t b c d + e + w + k t
b' = a
c' = rotate b 30
d' = c
e' = d
Il profiler mi dice che questa funzione prende 1/3 del tempo di esecuzione della mia applicazione. Non riesco a pensare ad altro modo di ottimizzarlo ulteriormente se non di inserire le variabili temporanee, ma credo che -O2 lo farà comunque per me.
Qualcuno può vedere un'ottimizzazione significativa che può essere ulteriormente applicata?
FYI le chiamate kef sono riportate di seguito. Sono così semplici che non penso ci sia un modo per ottimizzare questi altri. A meno che il modulo DataBits sia lento?
f :: Int -> Word32 -> Word32 -> Word32 -> Word32
f t b c d
| t <= 19 = (b .&. c) .|. ((complement b) .&. d)
| t <= 39 = b `xor` c `xor` d
| t <= 59 = (b .&. c) .|. (b .&. d) .|. (c .&. d)
| otherwise = b `xor` c `xor` d
k :: Int -> Word32
k t
| t <= 19 = 0x5A827999
| t <= 39 = 0x6ED9EBA1
| t <= 59 = 0x8F1BBCDC
| otherwise = 0xCA62C1D6
Senza provare, sto indovinando un sacco di questo problema è mantenere i dati del blocco in un elenco (troppo punto/traffico di memoria). Cercherò di passare a un vettore unboxed di 'Word32' e srotolare manualmente il ciclo. In breve, provalo con una struttura rigida/decompressa contenente 'a',' b', 'c',' d' e 'e'; allora avresti solo bisogno di una variabile passata (e avresti la certezza di mettere un modello bang su di esso, giusto?). –
Vorrei anche provare a sostituire tutti i '(<=)' con una ricerca tabella, anche se non sono sicuro che sarà di grande aiuto. –
Un'altra cosa: spesso è una buona idea scrivere funzioni aritmetiche rigide in C e chiamarla usando l'FFI. Se si fa attenzione a non introdurre effetti collaterali, il runtime può utilizzare una chiamata rapida in C che offre buone prestazioni. – fuz