ฉันต้องการโปรไฟล์ความเร็วของเครื่องกำเนิดสุ่ม Haskell และกรณีทดสอบของฉันคือการสร้างตัวเลขสุ่มที่มีความแม่นยำสองเท่า 1000,000 ช่วงจากศูนย์ถึงหนึ่งและคำนวณผลรวม นี่คือรหัสของฉัน:
import System.Random
import System.Environment
import Control.Monad.State
import Data.Time.Clock
type Seed = Int
intDayTime :: IO Int
intDayTime = getCurrentTime >>= return.(floor.utctDayTime :: UTCTime->Int)
n = 1000000 :: Int
main :: IO ()
main = do
calc <- getArgs >>= return . (read ::(String->Int)).head
seed <- intDayTime
let calcit :: Int->Double
calcit 1 = calc1 n seed
calcit 2 = calc2 n (mkStdGen seed)
calcit _ = error "error calculating"
in print $ calcit calc
calc1 ::Int->Seed->Double
calc1 n initSeed =
let next :: Seed->(Double,Seed) -- my simple random number generator, just for test
myRandGen :: State Seed Double
calc :: Int->Int->Seed->Double->Double
next seed = let x = (1103515245 * seed + 12345) `mod` 1073741824 in (((fromIntegral x)/1073741824),x)
myRandGen = state next
calc _ 0 _ r = r
calc n c s r = calc n (c-1) ns (r + nv)
where (nv,ns) = runState myRandGen s
in calc n n initSeed 0
calc2 ::Int->StdGen->Double
calc2 n initSeed =
let myRandGen :: State StdGen Double
calc :: Int->Int->StdGen->Double->Double
next :: StdGen->(Double,StdGen)
next gen = randomR (0,1) gen
myRandGen = state next
calc _ 0 _ r = r
calc n c s r = calc n (c-1) ns (r + nv)
where (nv,ns) = runState myRandGen s
in calc n n initSeed 0
และฉันก็รวบรวมโค้ดด้วย
ghc profRandGen.hs -O3 -prof -fprof-auto -rtsopts
วิ่งด้วย
./profRandGen.exe 1 +RTS -o # for calc1
./profRandGen.exe 2 +RTS -o # for calc2
และข้อมูลโปรไฟล์สำหรับ calc1 คือ
total time = 0.10 secs (105 ticks @ 1000 us, 1 processor)
total alloc = 128,121,344 bytes (excludes profiling overheads)
ข้อมูลโปรไฟล์สำหรับ calc1 คือ
total time = 1.48 secs (1479 ticks @ 1000 us, 1 processor)
total alloc = 2,008,077,560 bytes (excludes profiling overheads)
ฉันเข้าใจได้ว่าตัวสร้างแบบสุ่มใน System.Random
จะช้าลง แต่ทำไมมันถึงช้าลงมากและทำไมมันถึงจัดสรรหน่วยความจำมากขึ้น
ฉันใช้ การเรียกซ้ำแบบหาง ในโค้ดของฉันและคอมไพล์ด้วยตัวเลือก -O2 -fforce-recomp
เหตุใดฉันจึงไม่ได้รับการใช้งานหน่วยความจำอย่างต่อเนื่อง
มีอะไรผิดปกติในรหัสของฉันหรือเปล่า? ตัวอย่างเช่น เป็นเพราะการประเมินแบบขี้เกียจที่การเรียกซ้ำส่วนท้ายไม่ได้รับการปรับให้เหมาะสมและมีการจัดสรรหน่วยความจำจำนวนมากหรือไม่ หากเป็นเช่นนั้น โปรแกรมนี้จะได้รับการเพิ่มประสิทธิภาพเพิ่มเติมได้อย่างไร
-fforce-recomp
- person MaiaVictor   schedule 31.01.2015-O2
การเรียกหางจะถูกปรับให้เหมาะสม ดังนั้นฉันเดาว่าฉันอาจได้รับการใช้งานหน่วยความจำอย่างต่อเนื่อง... - person Alaya   schedule 31.01.2015means
ตัวอย่างใน Real World Haskell ที่นี่ เวอร์ชันแบบเรียกซ้ำแบบหางและแบบสะสมอย่างเคร่งครัดจะทำงานในพื้นที่คงที่ - person MasterMastic   schedule 31.01.2015