Ho il seguente codice Haskell, che implementa una versione semplice dell'utilità della riga di comando "cat" unix. Test delle prestazioni con "time" su un file da 400MB, è circa 3 volte più lento. (lo script esatto che sto usando per testarlo è sotto il codice).Prestazioni Haskell che implementano il programma "cat" di Unix con Data.ByteString
Le mie domande sono:
- È questo un test valido di prestazioni?
- Come posso rendere questo programma più veloce?
- Come identificare i colli di bottiglia delle prestazioni nei programmi Haskell in generale?
Riguardo alle domande 2 e 3: Ho usato GHC -prof, quindi eseguito con + RTS -p, ma sto trovando l'output un po 'non informativo qui.
Source (Main.hs)
module Main where
import System.IO
import System.Environment
import Data.ByteString as BS
import Control.Monad
-- Copied from cat source code
bufsize = 1024*128
go handle buf = do
hPut stdout buf
eof <- hIsEOF handle
unless eof $ do
buf <- hGetSome handle bufsize
go handle buf
main = do
file <- fmap Prelude.head getArgs
handle <- openFile file ReadMode
buf <- hGetSome handle bufsize
hSetBuffering stdin $ BlockBuffering (Just bufsize)
hSetBuffering stdout $ BlockBuffering (Just bufsize)
go handle buf
sceneggiatura Timing (run.sh):
#!/usr/bin/env bash
# Generate 10M lines of silly test data
yes aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | head -n 10000000 > huge
# Compile with optimisation
ghc -O2 Main.hs
# Run haskell
echo "timing Haskell"
time ./Main huge > /dev/null
echo ""
echo ""
# Run cat
echo "timing 'cat'"
time cat huge > /dev/null
I miei risultati:
timing Haskell
real 0m0.980s
user 0m0.296s
sys 0m0.684s
timing 'cat'
real 0m0.304s
user 0m0.001s
sys 0m0.302s
Il rapporto profilatura quando si compila con -Prof e in esecuzione con + RTS -p è qui sotto:
Sat Dec 13 21:26 2014 Time and Allocation Profiling Report (Final)
Main +RTS -p -RTS huge
total time = 0.92 secs (922 ticks @ 1000 us, 1 processor)
total alloc = 7,258,596,176 bytes (excludes profiling overheads)
COST CENTRE MODULE %time %alloc
MAIN MAIN 100.0 100.0
individual inherited
COST CENTRE MODULE no. entries %time %alloc %time %alloc
MAIN MAIN 46 0 100.0 100.0 100.0 100.0
CAF GHC.Conc.Signal 84 0 0.0 0.0 0.0 0.0
CAF GHC.IO.FD 82 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Handle.FD 81 0 0.0 0.0 0.0 0.0
CAF System.Posix.Internals 76 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Encoding 70 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Encoding.Iconv 69 0 0.0 0.0 0.0 0.0
E 'bello vedere che si è aggiunto anche -O2 ottimizzazione. Puoi anche pubblicare il link al rapporto profilato qui. – Sibi
Sibi: L'ho aggiunto, ma sfortunatamente sembra un po 'opaco. L'unica cosa che sembra strana è forse che il numero di "allocazione totale" sia molto grande - quando mi aspetterei che una memoria buffer temporanea venga sovrascritta come ottimizzazione (non sono sicuro che sia possibile). – statusfailed
Invece di 'hGetSome' usa' hGetNonBlocking', aumenta le prestazioni sostanzialmente – Sibi