가변 배열을 사용하여 변경 가능하고 순수한 목록을 사용하는 중간 집을 얻을 수 있습니다. 재귀 적 정의의 이점을 얻지 만, 그 이유 때문에 목록보다 덜하지만 게으름과 복싱의 가격을 지불합니다. 강제 I가 -O2
로 컴파일 된 코드
module Main where
import Data.Bits
import Data.List
import Data.Word
import qualified Data.Vector as LV
import Data.Array.ST
import Data.Array.Unboxed
import qualified Data.Array as A
import Data.Array.Base
import Criterion.Main
gen :: Word32 -> Word32 -> Word32 -> Word32 -> Word32
gen a b c d = rotate (a `xor` b `xor` c `xor` d) 1
gss blkw = LV.toList v
where v = LV.fromList $ blkw ++ rest
rest = map (\i -> gen (LV.unsafeIndex v (i + 13))
(LV.unsafeIndex v (i + 8))
(LV.unsafeIndex v (i + 2))
(LV.unsafeIndex v i)
)
[0..79 - 14]
gss' blkw = A.elems v
where v = A.listArray (0,79) $ blkw ++ rest
rest = map (\i -> gen (unsafeAt v (i + 13))
(unsafeAt v (i + 8))
(unsafeAt v (i + 2))
(unsafeAt v i)
)
[0..79 - 14]
generateSchedule :: [Word32] -> [Word32]
generateSchedule blkw = take 80 ws
where
ws = blkw ++ zipWith4 gen (drop 13 ws) (drop 8 ws) (drop 2 ws) ws
gs :: [Word32] -> [Word32]
gs ws = elems (generateSched ws)
generateSched :: [Word32] -> UArray Int Word32
generateSched ws0 = runSTUArray $ do
arr <- unsafeNewArray_ (0,79)
let fromList i [] = fill i 0
fromList i (w:ws) = do
unsafeWrite arr i w
fromList (i+1) ws
fill i j
| i == 80 = return arr
| otherwise = do
d <- unsafeRead arr j
c <- unsafeRead arr (j+2)
b <- unsafeRead arr (j+8)
a <- unsafeRead arr (j+13)
unsafeWrite arr i (gen a b c d)
fill (i+1) (j+1)
fromList 0 ws0
args = [0..13]
main = defaultMain [
bench "list" $ whnf (sum . generateSchedule) args
,bench "vector" $ whnf (sum . gss) args
,bench "array" $ whnf (sum . gss') args
,bench "uarray" $ whnf (sum . gs) args
]
및 -funfolding-use-threshold=256
다음 코드는 두 개의 지연 어레이 용액 (표준 배열을 사용하고, 벡터)뿐만 아니라 원래 목록 코드 및 상기 다니엘 가변 uarray 코드를 테스트 기준을 사용 많은 인라인. ,
benchmarking list
mean: 8.021718 us, lb 7.720636 us, ub 8.605683 us, ci 0.950
std dev: 2.083916 us, lb 1.237193 us, ub 3.309458 us, ci 0.950
benchmarking vector
mean: 6.829923 us, lb 6.725189 us, ub 7.226799 us, ci 0.950
std dev: 882.3681 ns, lb 76.20755 ns, ub 2.026598 us, ci 0.950
benchmarking array
mean: 6.212669 us, lb 5.995038 us, ub 6.635405 us, ci 0.950
std dev: 1.518521 us, lb 946.8826 ns, ub 2.409086 us, ci 0.950
benchmarking uarray
mean: 2.380519 us, lb 2.147896 us, ub 2.715305 us, ci 0.950
std dev: 1.411092 us, lb 1.083180 us, ub 1.862854 us, ci 0.950
는 너무 기본적인 프로파일을 실행 :
판단 기준 벤치 마크는 벡터 솔루션이 약간 더 나은 것을 증명하고 언 박싱 변경 가능한 솔루션이 여전히 압도적으로 승리 배열 솔루션 약간 더 나은 아직,하지만 게으른/박스형 배열 솔루션이 목록 솔루션보다 약간 좋았지 만, 박스 처리되지 않은 배열 방식보다 훨씬 심각하다는 것을 알게되었습니다.
나는 아직도 당신이 목록을 완전히 버릴 필요가 있다고 생각합니다. 중개인이 아닌 데이터를 ByteString으로 입력하고 Data.Vector.Storable 또는 일부를 사용하십시오. 입력이 단어 목록 일 때 최적화에 많은 부분을 알지 못합니다. 'partcb'를 완전히 풀면이'generateSchedule' 함수 ('partab')도 필요 없습니다. 그것은 언 롤링에서 명시 적 (인라인)이됩니다. 또한 목표에 대해 충분히 궁금해하고 있습니다. 교육입니까, 프로덕션 코드로 구현을 사용하고 싶습니까? # 2 인 경우 'cryptohash'를 피할 이유가 있습니까? –
교육. 나는 내가 방금 C 언어로 작성했으면 좋겠다는 최적화 트릭에 의지하지 않고 속도면에서 비슷한 깨끗하고 관용적 인 하스켈을 작성할 수 있는지 알고 싶다. SHA1의 경우, 그렇게 느껴지기 시작합니다. 또한 [Data.Digest.Pure.SHA] (http://hackage.haskell.org/packages/archive/SHA/1.5.0.0/doc/html/src/Data-Digest-Pure-SHA)의 출처를 살펴 보았습니다. .html). C 구현 속도의 2-3 배 이내입니다. 그러나 내가 쓰고 싶은 코드 종류는 아닙니다. – Ana
FYI 전체 최신 코드 [여기] (https://gist.github.com/5a7c61e057c94f35b87b). – Ana