diff --git a/Foundation/Array/Unboxed.hs b/Foundation/Array/Unboxed.hs index 66714b5e..ff80bfa1 100644 --- a/Foundation/Array/Unboxed.hs +++ b/Foundation/Array/Unboxed.hs @@ -531,25 +531,25 @@ null (UVecAddr _ l _) = l == Size 0 take :: PrimType ty => Int -> UArray ty -> UArray ty take nbElems v | nbElems <= 0 = empty - | n == vlen = v + | n >= vlen = v | otherwise = case v of UVecBA start _ pinst ba -> UVecBA start n pinst ba UVecAddr start _ fptr -> UVecAddr start n fptr where - n = min (Size nbElems) vlen + n = Size nbElems vlen = lengthSize v drop :: PrimType ty => Int -> UArray ty -> UArray ty drop nbElems v | nbElems <= 0 = v - | n == vlen = empty + | n >= vlen = empty | otherwise = case v of UVecBA start len pinst ba -> UVecBA (start `offsetPlusE` n) (len - n) pinst ba UVecAddr start len fptr -> UVecAddr (start `offsetPlusE` n) (len - n) fptr where - n = min (Size nbElems) vlen + n = Size nbElems vlen = lengthSize v splitAt :: PrimType ty => Int -> UArray ty -> (UArray ty, UArray ty) @@ -580,7 +580,7 @@ splitElem !ty r@(UVecBA start len pinst ba) loop !i | i < end && t /= ty = loop (i+Offset 1) | otherwise = i where !t = primBaIndex ba i -splitElem ty r@(UVecAddr start len fptr) +splitElem !ty r@(UVecAddr start len fptr) | k == end = (# r, empty #) | otherwise = (# UVecAddr start (offsetAsSize k) fptr @@ -809,10 +809,32 @@ filter :: PrimType ty => (ty -> Bool) -> UArray ty -> UArray ty filter predicate vec = vFromList $ Data.List.filter predicate $ vToList vec reverse :: PrimType ty => UArray ty -> UArray ty -reverse a = create len toEnd +reverse a + | len == Size 0 = empty + | otherwise = runST $ do + ma <- newNative len $ \mba -> + case a of + (UVecBA start _ _ ba) -> goNative endOfs mba ba start + (UVecAddr start _ fptr) -> withFinalPtr fptr $ \ptr -> goAddr endOfs mba ptr start + unsafeFreeze ma where - len = length a - toEnd i = unsafeIndex a (len - i - 1) + !len = lengthSize a + !endOfs = Offset 0 `offsetPlusE` len + + goNative :: PrimType ty => Offset ty -> MutableByteArray# s -> ByteArray# -> Offset ty -> ST s () + goNative !end !ma !ba !srcStart = loop (Offset 0) + where + !endI = sizeAsOffset ((srcStart + end) - Offset 1) + loop !i + | i == end = return () + | otherwise = primMbaWrite ma i (primBaIndex ba (sizeAsOffset (endI - i))) >> loop (i+Offset 1) + goAddr !end !ma !(Ptr ba) !srcStart = loop (Offset 0) + where + !endI = sizeAsOffset ((srcStart + end) - Offset 1) + loop !i + | i == end = return () + | otherwise = primMbaWrite ma i (primAddrIndex ba (sizeAsOffset (endI - i))) >> loop (i+Offset 1) +{-# SPECIALIZE [3] reverse :: UArray Word8 -> UArray Word8 #-} foldl :: PrimType ty => (a -> ty -> a) -> a -> UArray ty -> a foldl f initialAcc vec = loop 0 initialAcc diff --git a/README.md b/README.md index ec8c2dc8..a86d257d 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,10 @@ To run a specific or set of benchmarks : stack bench --flag foundation:bench-all --benchmark-arguments '-m prefix types/String/SplitAt' stack bench --flag foundation:bench-all --benchmark-arguments '-m glob types/String/SplitAt' +To register a set of benchmarks: + + stack bench --flag foundation:bench-all --benchmark-arguments "--csv $(git describe).csv" + Design ====== diff --git a/benchs/BenchUtil/RefData.hs b/benchs/BenchUtil/RefData.hs index c094c586..eb9c4610 100644 --- a/benchs/BenchUtil/RefData.hs +++ b/benchs/BenchUtil/RefData.hs @@ -1,19 +1,26 @@ module BenchUtil.RefData - ( rdLoremIpsum1 + ( + -- string + rdLoremIpsum1 , rdLoremIpsum5 , rdFoundationEn , rdFoundationZh , rdFoundationJap , rdFoundationHun + -- byte array + , rdBytes20 + , rdBytes200 + , rdBytes2000 ) where -import Prelude (Char) +import Prelude (Char, cycle, take, ($)) +import Data.Word (Word8) rdLoremIpsum1 :: [Char] rdLoremIpsum1 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ornare dui vitae porta varius. In quis diam sed felis elementum ultricies non sit amet lorem. Nullam ut erat varius lectus scelerisque iaculis sed eu leo. Vivamus gravida interdum elit suscipit tempus. Quisque at mauris ac sapien consequat feugiat. In varius interdum rhoncus. Etiam hendrerit pharetra consectetur. Pellentesque laoreet, nisi quis feugiat rhoncus, nisi ipsum tincidunt nulla, vel fermentum mauris nisl sed felis. Sed ac convallis nibh. Donec rutrum finibus odio et rhoncus. Suspendisse pulvinar ex ac fermentum fermentum. Nam dui dui, lobortis sit amet sapien sed, gravida sagittis magna. Vestibulum nec egestas dui, non efficitur lectus. Fusce vitae mattis sem, nec dignissim nibh. Sed ac tincidunt metus." rdLoremIpsum5 :: [Char] -rdLoremIpsum5 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ornare dui vitae porta varius. In quis diam sed felis elementum ultricies non sit amet lorem. Nullam ut erat varius lectus scelerisque iaculis sed eu leo. Vivamus gravida interdum elit suscipit tempus. Quisque at mauris ac sapien consequat feugiat. In varius interdum rhoncus. Etiam hendrerit pharetra consectetur. Pellentesque laoreet, nisi quis feugiat rhoncus, nisi ipsum tincidunt nulla, vel fermentum mauris nisl sed felis. Sed ac convallis nibh. Donec rutrum finibus odio et rhoncus. Suspendisse pulvinar ex ac fermentum fermentum. Nam dui dui, lobortis sit amet sapien sed, gravida sagittis magna. Vestibulum nec egestas dui, non efficitur lectus. Fusce vitae mattis sem, nec dignissim nibh. Sed ac tincidunt metus. Vestibulum ac bibendum ex. In vulputate pellentesque elementum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas elit libero, vehicula eget hendrerit non, convallis vel metus. Maecenas faucibus nulla id quam vestibulum, eget commodo tellus interdum. Mauris eu odio id lacus gravida sollicitudin. Aenean vel velit enim. Phasellus vitae urna nisl. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc volutpat convallis elementum. Curabitur suscipit congue ligula non maximus. Fusce tristique lacinia sem sed condimentum. Sed non eleifend mi, fringilla congue tortor. Nunc rhoncus sit amet nisl ac tempor. Fusce sed consectetur purus, et aliquam sem. Vestibulum finibus lectus et vehicula euismod. Aliquam sed neque mattis, sollicitudin enim sed, vestibulum est. Quisque varius pharetra risus id tempor. In hac habitasse platea dictumst. Donec cursus nisi sed magna bibendum aliquet. Mauris a elit id erat imperdiet consequat. Phasellus at condimentum ipsum. Pellentesque vehicula pulvinar ipsum et porta. Nullam quis quam mauris. Sed scelerisque porta nibh eu tempor. Morbi sollicitudin fringilla sollicitudin. Cras nec velit quis velit sollicitudin pellentesque. Phasellus quis ullamcorper nisi. Curabitur fringilla sed turpis sit amet pharetra. Cras euismod eget massa eu posuere. Suspendisse id aliquam enim. Nullam sollicitudin aliquet elementum. Nulla sit amet ligula vitae lorem finibus laoreet sed ac velit. Nulla facilisi. Aenean vel pretium lectus. Nunc augue lorem, viverra et felis vel, vestibulum feugiat nisl. Vestibulum imperdiet laoreet posuere. Maecenas vestibulum consequat felis eu aliquam. Nullam ac efficitur ante, eget egestas mauris. Cras id tincidunt nisi. Cras tincidunt molestie lorem et bibendum. Donec commodo porttitor faucibus. Aenean aliquam suscipit iaculis. Cras eu purus sit amet elit rhoncus laoreet. Vestibulum fringilla nulla ut neque vestibulum porttitor. Pellentesque vitae risus elit. Quisque et sapien eu diam tincidunt luctus ac quis nunc. Proin nec nisl eget diam faucibus tempus id sed quam. Ut scelerisque enim lacus, at mollis diam sagittis et. Nam lobortis convallis maximus. Donec maximus tortor id consequat venenatis." +rdLoremIpsum5 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ornare dui vitae porta varius. In quis diam sed felis elementum ultricies non sit amet lorem. Nullam ut erat varius lectus scelerisque iaculis sed eu leo. Vivamus gravida interdum elit suscipit tempus. Quisque at mauris ac sapien consequat feugiat. In varius interdum rhoncus. Etiam hendrerit pharetra consectetur. Pellentesque laoreet, nisi quis feugiat rhoncus, nisi ipsum tincidunt nulla, vel fermentum mauris nisl sed felis. Sed ac convallis nibh. Donec rutrum finibus odio et rhoncus. Suspendisse pulvinar ex ac fermentum fermentum. Nam dui dui, lobortis sit amet sapien sed, gravida sagittis magna. Vestibulum nec egestas dui, non efficitur lectus. Fusce vitae mattis sem, nec dignissim nibh. Sed ac tincidunt metus. Vestibulum ac bibendum ex. In vulputate pellentesque elementum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas elit libero, vehicula eget hendrerit non, convallis vel metus. Maecenas faucibus nulla id quam vestibulum, eget commodo tellus interdum. Mauris eu odio id lacus gravida sollicitudin. Aenean vel velit enim. Phasellus vitae urna nisl. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc volutpat convallis elementum. Curabitur suscipit congue ligula non maximus. Fusce tristique lacinia sem sed condimentum. Sed non eleifend mi, fringilla congue tortor. Nunc rhoncus sit amet nisl ac tempor. Fusce sed consectetur purus, et aliquam sem. Vestibulum finibus lectus et vehicula euismod. Aliquam sed neque mattis, sollicitudin enim sed, vestibulum est. Quisque varius pharetra risus id tempor. In hac habitasse platea dictumst. Donec cursus nisi sed magna bibendum aliquet. Mauris a elit id erat imperdiet consequat. Phasellus at condimentum ipsum. Pellentesque vehicula pulvinar ipsum et porta. Nullam quis quam mauris. Sed scelerisque porta nibh eu tempor. Morbi sollicitudin fringilla sollicitudin. Cras nec velit quis velit sollicitudin pellentesque. Phasellus quis ullamcorper nisi. Curabitur fringilla sed turpis sit amet pharetra. Cras euismod eget massa eu posuere. Suspendisse id aliquam enim. Nullam sollicitudin aliquet elementum. Nulla sit amet ligula vitae lorem finibus laoreet sed ac velit. Nulla facilisi. Aenean vel pretium lectus. Nunc augue lorem, viverra et felis vel, vestibulum feugiat nisl. Vestibulum imperdiet laoreet posuere. Maecenas vestibulum consequat felis eu aliquam. Nullam ac efficitur ante, eget egestas mauris. Cras id tincidunt nisi. Cras tincidunt molestie lorem et bibendum. Donec commodo porttitor faucibus. Aenean aliquam suscipit iaculis. Cras eu purus sit amet elit rhoncus laoreet. Vestibulum fringilla nulla ut neque vestibulum porttitor. Pellentesque vitae risus elit. Quisque et sapien eu diam tincidunt luctus ac quis nunc. Proin nec nisl eget diam faucibus tempus id sed quam. Ut scelerisque enim lacus, at mollis diam sagittis et. Nam lobortis convallis maximus. Donec maximus tortor id consequat venenatis." rdFoundationEn :: [Char] rdFoundationEn = "Set in the year 0 F.E. (\"Foundation Era\"), The Psychohistorians opens on Trantor, the capital of the 12,000-year-old Galactic Empire. Though the empire appears stable and powerful, it is slowly decaying in ways that parallel the decline of the Western Roman Empire. Hari Seldon, a mathematician and psychologist, has developed psychohistory, a new field of science and psychology that equates all possibilities in large societies to mathematics, allowing for the prediction of future events." @@ -26,3 +33,12 @@ rdFoundationHun = "A történet G.K. 12 067-ben (A.K. 1) játszódik. A fiatal rdFoundationJap :: [Char] rdFoundationJap = "数学者ハリ・セルダンは、膨大な集団の行動を予測する心理歴史学を作りあげ発展させることで、銀河帝国が近いうちに崩壊することを予言する[1]。セルダンは、帝国崩壊後に3万年続くはずの暗黒時代を、あらゆる知識を保存することで千年に縮めようとし、知識の集大成となる銀河百科事典 (Encyclopedia Galactica) を編纂するグループ「ファウンデーション」をつくったが、帝国崩壊を公言し平和を乱したという罪で裁判にかけられ、グループは銀河系辺縁部にある資源の乏しい無人惑星ターミナスへ追放されることになった。しかし、この追放劇すらもセルダンの計画に予定されていた事柄であった。病で死期をさとっていたセルダンは、己の仕事が終わったことを確信する。" + +rdBytes20 ::[Word8] +rdBytes20 = take 20 $ cycle [1..255] + +rdBytes200 :: [Word8] +rdBytes200 = take 200 $ cycle [1..255] + +rdBytes2000 :: [Word8] +rdBytes2000 = take 2000 $ cycle [1..255] diff --git a/benchs/Fake/ByteString.hs b/benchs/Fake/ByteString.hs new file mode 100644 index 00000000..d707341b --- /dev/null +++ b/benchs/Fake/ByteString.hs @@ -0,0 +1,22 @@ +module Fake.ByteString + ( ByteString + , pack + , length + , splitAt + , take + , break + , reverse + , filter + ) where + +import Prelude (undefined) + +data ByteString = ByteString + +pack _ = ByteString +length = undefined +splitAt _ _ = (undefined, undefined) +take = undefined +break _ _ = (undefined, undefined) +reverse = undefined +filter _ = undefined diff --git a/benchs/Fake/Text.hs b/benchs/Fake/Text.hs new file mode 100644 index 00000000..90eabaf9 --- /dev/null +++ b/benchs/Fake/Text.hs @@ -0,0 +1,22 @@ +module Fake.Text + ( Text + , pack + , length + , splitAt + , take + , any + , filter + , reverse + ) where + +import Prelude (undefined) + +data Text = Text + +pack _ = Text +length = undefined +splitAt _ _ = (undefined, undefined) +take = undefined +filter _ = undefined +reverse = undefined +any = undefined diff --git a/benchs/Main.hs b/benchs/Main.hs index eff6112a..4f74e3d7 100644 --- a/benchs/Main.hs +++ b/benchs/Main.hs @@ -11,22 +11,11 @@ import BenchUtil.Common import BenchUtil.RefData #ifdef BENCH_ALL +import qualified Data.ByteString as ByteString import qualified Data.Text as Text -type TextText = Text.Text - -textPack = Text.pack -textLength = Text.length -textSplitAt = Text.splitAt -textTake = Text.take -textAny = Text.any #else -data TextText = Text - -textPack _ = Text -textLength = undefined -textSplitAt _ _ = (undefined, undefined) -textTake = undefined -textAny = undefined +import qualified Fake.ByteString as ByteString +import qualified Fake.Text as Text #endif -------------------------------------------------------------------------- @@ -37,10 +26,12 @@ benchsString = bgroup "String" , benchTake , benchSplitAt , benchBuildable + , benchReverse + , benchFilter ] where diffTextString :: (String -> a) - -> (TextText -> b) + -> (Text.Text -> b) -> [Char] -> [Benchmark] diffTextString foundationBench textBench dat = @@ -51,54 +42,99 @@ benchsString = bgroup "String" ] where s = fromList dat - t = textPack dat + t = Text.pack dat + + allDat = [ ("ascii", rdFoundationEn) + , ("mascii", rdFoundationHun) + , ("uni1" ,rdFoundationJap) + , ("uni2" ,rdFoundationZh) + ] + allDatSuffix s = fmap (first (\x -> x <> "-" <> s)) allDat benchLength = bgroup "Length" $ - fmap (\(n, dat) -> bgroup n $ diffTextString length textLength dat) - [ ("ascii", rdFoundationEn) - , ("mascii", rdFoundationHun) - , ("uni1" ,rdFoundationJap) - , ("uni2" ,rdFoundationZh) - ] + fmap (\(n, dat) -> bgroup n $ diffTextString length Text.length dat) + allDat benchElem = bgroup "Elem" $ - fmap (\(n, dat) -> bgroup n $ diffTextString (elem '.') (textAny (== '.')) dat) - [ ("ascii" , rdFoundationEn) - , ("mascii", rdFoundationHun) - , ("uni1" , rdFoundationJap) - , ("uni2" , rdFoundationZh) - ] - benchTake = bgroup "Take" $ - mconcat $ fmap (\p -> - fmap (\(n, dat) -> bgroup n $ diffTextString (take p) (textTake p) dat) - [ ("ascii-" <> show p, rdFoundationEn) - , ("mascii-" <> show p, rdFoundationHun) - , ("uni1-" <> show p,rdFoundationJap) - , ("uni2-" <> show p,rdFoundationZh) - ]) [ 10, 100, 800 ] - benchSplitAt = bgroup "SplitAt" $ - mconcat $ fmap (\p -> - fmap (\(n, dat) -> bgroup n $ diffTextString (fst . splitAt p) (fst . textSplitAt p) dat) - [ ("ascii-" <> show p, rdFoundationEn) - , ("mascii-" <> show p, rdFoundationHun) - , ("uni1-" <> show p,rdFoundationJap) - , ("uni2-" <> show p,rdFoundationZh) - ]) [ 10, 100, 800 ] + fmap (\(n, dat) -> bgroup n $ diffTextString (elem '.') (Text.any (== '.')) dat) + allDat + benchTake = bgroup "Take" $ mconcat $ fmap (\p -> + fmap (\(n, dat) -> bgroup n $ diffTextString (take p) (Text.take p) dat) + $ allDatSuffix (show p) + ) [ 10, 100, 800 ] + benchSplitAt = bgroup "SplitAt" $ mconcat $ fmap (\p -> + fmap (\(n, dat) -> bgroup n $ diffTextString (fst . splitAt p) (fst . Text.splitAt p) dat) + $ allDatSuffix (show p) + ) [ 10, 100, 800 ] benchBuildable = bgroup "Buildable" $ fmap (\(n, dat) -> bench n $ toString (\es -> runST $ build 128 $ Prelude.mapM_ append es) dat) - [ ("ascii" , rdFoundationEn) - , ("mascii", rdFoundationHun) - , ("uni1" , rdFoundationJap) - , ("uni2" , rdFoundationZh) - ] + allDat + + benchReverse = bgroup "Reverse" $ + fmap (\(n, dat) -> bgroup n $ diffTextString reverse Text.reverse dat) + allDat + + benchFilter = bgroup "Filter" $ + fmap (\(n, dat) -> bgroup n $ diffTextString (filter (> 'b')) (Text.filter (> 'b')) dat) + allDat toString :: ([Char] -> String) -> [Char] -> Benchmarkable toString = whnf -------------------------------------------------------------------------- +benchsByteArray = bgroup "ByteArray" + [ benchLength + , benchTake + , benchBreakElem + , benchReverse + , benchFilter + --, benchSplitAt + ] + where + diffByteString :: (UArray Word8 -> a) + -> (ByteString.ByteString -> b) + -> [Word8] + -> [Benchmark] + diffByteString foundationBench textBench dat = + [ bench "UArray_W8" $ whnf foundationBench s +#ifdef BENCH_ALL + , bench "ByteString" $ whnf textBench t +#endif + ] + where + s = fromList dat + t = ByteString.pack dat + + allDat = + [ ("bs20", rdBytes20) + , ("bs200", rdBytes200) + , ("bs2000", rdBytes2000) + ] + allDatSuffix s = fmap (first (\x -> x <> "-" <> s)) allDat + + benchLength = bgroup "Length" $ + fmap (\(n, dat) -> bgroup n $ diffByteString length ByteString.length dat) allDat + + benchTake = bgroup "Take" $ mconcat $ fmap (\p -> + fmap (\(n, dat) -> bgroup n $ diffByteString (take p) (ByteString.take p) dat) + $ allDatSuffix (show p) + ) [ 0, 10, 100 ] + + benchBreakElem = bgroup "BreakElem" $ mconcat $ fmap (\p -> + fmap (\(n, dat) -> bgroup n $ diffByteString (fst . breakElem p) (fst . ByteString.break (== p)) dat) + $ allDatSuffix (show p) + ) [ 19, 199, 0 ] + + benchReverse = bgroup "Reverse" $ + fmap (\(n, dat) -> bgroup n $ diffByteString reverse ByteString.reverse dat) allDat + + benchFilter = bgroup "Filter" $ + fmap (\(n, dat) -> bgroup n $ diffByteString (filter (> 100)) (ByteString.filter (> 100)) dat) allDat +-------------------------------------------------------------------------- benchsTypes = bgroup "types" [ benchsString + , benchsByteArray ] main = defaultMain