Skip to content

Commit 21c6a0c

Browse files
committed
speed up shrinkRawBytes
Before: Test.Database.LSMTree.Generators RawBytes Shrinking satisfies invariant: OK (0.01s) +++ OK, passed 100 tests (1% no shrinks). number of shrinks (99 in total): 64% 100 <= n < 1000 30% 10 <= n < 100 6% 1 <= n < 10 lists of key/op pairs Shrinking satisfies invariant: OK (4.51s) +++ OK, passed 100 tests (4% no shrinks). number of shrinks (96 in total): 45% 1000 <= n < 10000 44% 10000 <= n < 100000 10% 100 <= n < 1000 1% 10 <= n < 100 After: Test.Database.LSMTree.Generators RawBytes Shrinking satisfies invariant: OK +++ OK, passed 100 tests (4% no shrinks). number of shrinks (96 in total): 52% 10 <= n < 100 45% 100 <= n < 1000 3% 1 <= n < 10 lists of key/op pairs Shrinking satisfies invariant: OK (1.57s) +++ OK, passed 100 tests (6% no shrinks). number of shrinks (94 in total): 56% 1000 <= n < 10000 21% 100 <= n < 1000 19% 10000 <= n < 100000 3% 10 <= n < 100
1 parent c20c8d8 commit 21c6a0c

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

src-extras/Database/LSMTree/Extras/Generators.hs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,16 @@ module Database.LSMTree.Extras.Generators (
3737
, isKeyForIndexCompact
3838
, KeyForIndexCompact (..)
3939
, BiasedKeyForIndexCompact (..)
40+
-- * helpers
41+
, shrinkVec
4042
) where
4143

4244
import Control.DeepSeq (NFData)
4345
import Control.Exception (assert)
4446
import Data.Coerce (coerce)
4547
import Data.Containers.ListUtils (nubOrd)
4648
import Data.Function ((&))
47-
import Data.List (sort)
49+
import Data.List (nub, sort)
4850
import qualified Data.Primitive.ByteArray as BA
4951
import qualified Data.Vector.Primitive as VP
5052
import Data.Word
@@ -57,7 +59,8 @@ import Database.LSMTree.Internal.BlobRef (BlobSpan (..))
5759
import Database.LSMTree.Internal.Entry (Entry (..), NumEntries (..))
5860
import qualified Database.LSMTree.Internal.Merge as Merge
5961
import Database.LSMTree.Internal.Page (PageNo (..))
60-
import Database.LSMTree.Internal.RawBytes as RB
62+
import Database.LSMTree.Internal.RawBytes (RawBytes (RawBytes))
63+
import qualified Database.LSMTree.Internal.RawBytes as RB
6164
import Database.LSMTree.Internal.Serialise
6265
import qualified Database.LSMTree.Internal.Serialise.Class as S.Class
6366
import Database.LSMTree.Internal.Unsliced (Unsliced, fromUnslicedKey,
@@ -454,8 +457,33 @@ packRawBytesPinnedOrUnpinned True = \ws ->
454457
return mba
455458

456459
shrinkRawBytes :: RawBytes -> [RawBytes]
457-
shrinkRawBytes (RawBytes pvec) = [ RawBytes (VP.fromList ws)
458-
| ws <- QC.shrink (VP.toList pvec) ]
460+
shrinkRawBytes (RawBytes pvec) =
461+
[ RawBytes pvec'
462+
| pvec' <- shrinkVec shrinkByte pvec
463+
]
464+
where
465+
-- no need to try harder shrinking individual bytes
466+
shrinkByte b = nub (takeWhile (< b) [0, b `div` 2])
467+
468+
-- | Based on QuickCheck's 'shrinkList' (behaves identically, see tests).
469+
shrinkVec :: VP.Prim a => (a -> [a]) -> VP.Vector a -> [VP.Vector a]
470+
shrinkVec shr vec =
471+
concat [ removeBlockOf k | k <- takeWhile (> 0) (iterate (`div` 2) len) ]
472+
++ shrinkOne
473+
where
474+
len = VP.length vec
475+
476+
shrinkOne =
477+
[ vec VP.// [(i, x')]
478+
| i <- [0 .. len-1]
479+
, let x = vec VP.! i
480+
, x' <- shr x
481+
]
482+
483+
removeBlockOf k =
484+
[ VP.take i vec VP.++ VP.drop (i + k) vec
485+
| i <- [0, k .. len - k]
486+
]
459487

460488
genSlice :: RawBytes -> Gen RawBytes
461489
genSlice (RawBytes pvec) = do
@@ -465,10 +493,14 @@ genSlice (RawBytes pvec) = do
465493

466494
shrinkSlice :: RawBytes -> [RawBytes]
467495
shrinkSlice (RawBytes pvec) =
468-
[ RawBytes (VP.slice m n pvec)
469-
| n <- QC.shrink (VP.length pvec)
470-
, m <- QC.shrink (VP.length pvec - n)
496+
[ RawBytes (VP.take len' pvec)
497+
| len' <- QC.shrink len
498+
] ++
499+
[ RawBytes (VP.drop (len - len') pvec)
500+
| len' <- QC.shrink len
471501
]
502+
where
503+
len = VP.length pvec
472504

473505
deriving newtype instance Arbitrary SerialisedKey
474506

test/Test/Database/LSMTree/Generators.hs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import Database.LSMTree.Internal.Serialise
2525
import qualified Test.QuickCheck as QC
2626
import Test.QuickCheck (Property)
2727
import Test.Tasty (TestTree, localOption, testGroup)
28-
import Test.Tasty.QuickCheck (QuickCheckMaxSize (..), testProperty)
28+
import Test.Tasty.QuickCheck (QuickCheckMaxSize (..), testProperty,
29+
(===))
2930
import Test.Util.Arbitrary
3031

3132
tests :: TestTree
@@ -62,6 +63,10 @@ tests = testGroup "Test.Database.LSMTree.Generators" [
6263
, testGroup "lists of key/op pairs" $
6364
prop_arbitraryAndShrinkPreserveInvariant labelTestKOps $
6465
deepseqInvariant
66+
, testGroup "helpers"
67+
[ testProperty "prop_shrinkVec" $ \vec ->
68+
shrinkVec (QC.shrink @Int) vec === map VP.fromList (QC.shrink (VP.toList vec))
69+
]
6570
]
6671

6772
prop_packRawBytesPinnedOrUnpinned :: Bool -> [Word8] -> Bool

0 commit comments

Comments
 (0)