-
Notifications
You must be signed in to change notification settings - Fork 9
Add general index benchmarks #599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,123 @@ | ||||||||||
| {-# LANGUAGE CPP #-} | ||||||||||
|
|
||||||||||
| module Bench.Database.LSMTree.Internal.Index (benchmarks) where | ||||||||||
|
|
||||||||||
| import Control.Category ((>>>)) | ||||||||||
| import Control.DeepSeq (rnf) | ||||||||||
| import Control.Monad.ST.Strict (runST) | ||||||||||
| import Criterion.Main (Benchmark, Benchmarkable, bench, bgroup, env, | ||||||||||
| whnf) | ||||||||||
| #if __GLASGOW_HASKELL__ < 910 | ||||||||||
| import Data.List (foldl') | ||||||||||
| #endif | ||||||||||
| import Database.LSMTree.Extras.Generators (getKeyForIndexCompact, | ||||||||||
| mkPages, toAppends) | ||||||||||
| -- also for @Arbitrary@ instantiation of @SerialisedKey@ | ||||||||||
| import Database.LSMTree.Extras.Index (Append, append) | ||||||||||
| import Database.LSMTree.Internal.Index (Index, | ||||||||||
| IndexType (Compact, Ordinary), newWithDefaults, search, | ||||||||||
| unsafeEnd) | ||||||||||
| import Database.LSMTree.Internal.Serialise | ||||||||||
| (SerialisedKey (SerialisedKey)) | ||||||||||
| import Test.QuickCheck (choose, vector) | ||||||||||
| import Test.QuickCheck.Gen (Gen (MkGen)) | ||||||||||
| import Test.QuickCheck.Random (mkQCGen) | ||||||||||
|
|
||||||||||
| -- * Benchmarks | ||||||||||
|
|
||||||||||
| benchmarks :: Benchmark | ||||||||||
| benchmarks = bgroup "Bench.Database.LSMTree.Internal.Index" $ | ||||||||||
| map (uncurry benchmarksForSingleType) $ | ||||||||||
| [("Compact", Compact), ("Ordinary", Ordinary)] | ||||||||||
| where | ||||||||||
|
|
||||||||||
| benchmarksForSingleType :: String -> IndexType -> Benchmark | ||||||||||
| benchmarksForSingleType indexTypeName indexType | ||||||||||
| = bgroup (indexTypeName ++ " index") $ | ||||||||||
| [ | ||||||||||
| -- Search | ||||||||||
| env (return $ searchIndex indexType 10000) $ \ index -> | ||||||||||
| env (return $ searchKeys 1000) $ \ keys -> | ||||||||||
| bench "Search" $ | ||||||||||
| searchBenchmarkable index keys, | ||||||||||
|
|
||||||||||
| -- Incremental construction | ||||||||||
| env (return $ incrementalConstructionAppends 10000) $ \ appends -> | ||||||||||
| bench "Incremental construction" $ | ||||||||||
| incrementalConstructionBenchmarkable indexType appends | ||||||||||
| ] | ||||||||||
|
|
||||||||||
| -- * Utilities | ||||||||||
|
|
||||||||||
| -- | Deterministically constructs a value using a QuickCheck generator. | ||||||||||
| generated :: Gen a -> a | ||||||||||
| generated (MkGen exec) = exec (mkQCGen 411) 30 | ||||||||||
|
|
||||||||||
| {-| | ||||||||||
| Constructs serialised keys that conform to the key size constraint of | ||||||||||
| compact indexes. | ||||||||||
| -} | ||||||||||
| keysForIndexCompact :: Int -- ^ Number of keys | ||||||||||
| -> [SerialisedKey] -- ^ Constructed keys | ||||||||||
| keysForIndexCompact = vector >>> | ||||||||||
| generated >>> | ||||||||||
| map (getKeyForIndexCompact >>> SerialisedKey) | ||||||||||
|
|
||||||||||
| {-| | ||||||||||
| Constructs append operations whose serialised keys conform to the key size | ||||||||||
| constraint of compact indexes. | ||||||||||
| -} | ||||||||||
| appendsForIndexCompact :: Int -- ^ Number of keys used in the construction | ||||||||||
| -> [Append] -- ^ Constructed append operations | ||||||||||
| appendsForIndexCompact = keysForIndexCompact >>> | ||||||||||
| mkPages 0.03 (choose (0, 16)) 0.01 >>> | ||||||||||
| generated >>> | ||||||||||
| toAppends | ||||||||||
| {- | ||||||||||
| The arguments used for 'mkPages' are the same as the ones used for | ||||||||||
| 'genPages' in the instantiation of 'Arbitrary' for 'LogicalPageSummaries' at | ||||||||||
| the time of writing. | ||||||||||
| -} | ||||||||||
|
|
||||||||||
| {-| | ||||||||||
| Constructs an index by applying append operations to an initially empty | ||||||||||
| index. | ||||||||||
| -} | ||||||||||
| indexFromAppends :: IndexType -> [Append] -> Index | ||||||||||
| indexFromAppends indexType appends = runST $ do | ||||||||||
| indexAcc <- newWithDefaults indexType | ||||||||||
| mapM_ (flip append indexAcc) appends | ||||||||||
| snd <$> unsafeEnd indexAcc | ||||||||||
|
|
||||||||||
| -- * Benchmark ingredients | ||||||||||
|
|
||||||||||
| -- ** Search | ||||||||||
|
|
||||||||||
| -- | Constructs an index to be searched. | ||||||||||
| searchIndex :: IndexType -- ^ Type of index to construct | ||||||||||
| -> Int -- ^ Number of keys used in the construction | ||||||||||
| -> Index -- ^ Constructed index | ||||||||||
| searchIndex indexType keyCount | ||||||||||
| = indexFromAppends indexType (appendsForIndexCompact keyCount) | ||||||||||
|
|
||||||||||
| -- | Constructs a list of keys to search for. | ||||||||||
| searchKeys :: Int -- ^ Number of searches | ||||||||||
| -> [SerialisedKey] -- ^ Constructed search keys | ||||||||||
| searchKeys = keysForIndexCompact | ||||||||||
|
|
||||||||||
| -- | The action to be performed by a search benchmark. | ||||||||||
| searchBenchmarkable :: Index -> [SerialisedKey] -> Benchmarkable | ||||||||||
| searchBenchmarkable index = whnf $ foldl' (\ _ key -> rnf (search key index)) () | ||||||||||
|
|
||||||||||
| -- ** Incremental construction | ||||||||||
|
|
||||||||||
| -- | Constructs append operations to be used in index construction. | ||||||||||
| incrementalConstructionAppends | ||||||||||
| :: Int -- ^ Number of keys used in the construction | ||||||||||
|
Comment on lines
+115
to
+116
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jeltsch did you forget to resolve this?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought that this wouldn’t be so important, given that it was labeled a “suggested” change and the pull request was already approved as it were. Generally, I think that having this sort of hanging indentation by not putting Well, I can make the change. Should I? |
||||||||||
| -> [Append] -- ^ Constructed append operations | ||||||||||
| incrementalConstructionAppends = appendsForIndexCompact | ||||||||||
|
|
||||||||||
| -- | The action to be performed by an incremental-construction benchmark. | ||||||||||
| incrementalConstructionBenchmarkable :: IndexType -> [Append] -> Benchmarkable | ||||||||||
| incrementalConstructionBenchmarkable indexType appends | ||||||||||
| = whnf (indexFromAppends indexType) appends | ||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally normally avoid using
QuickCheckgenerators because they are often in flux, and because they are primarily tailored towards testing, not benchmarking. It can be more future proof to write these functions withSystem.Randomand related functions. When we changeQuickCheckgenerators, we might accidentally change a benchmark as wellThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m also not completely satisfied with using QuickCheck generators for benchmarks. That said, by using
System.Randomdirectly, we lose the ability to use existing utilities, like we usemkPagesabove. I’d like to leave the above code as it is for now. It might be worthwhile, though, to generally revisit the uses of QuickCheck generators in our benchmarks.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not completely true. You should run the
mkPagesGenwith a seed, yes, but you can generate the keys withSystem.Random. See theIndex.CompactbenchmarksThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you’re advocating a mixed-approach with some data being generated by directly using
System.Randomand other by using QuickCheck?In the compact-index benchmark module, I can only see one use of
mkPages, the one inconstructionEnv. However, there the generator constructed bymkPagesis run viagenerate, which means that it uses a seed produced by the global random number generator, not a seed specified in the source file. That said, I could still use mygeneratedfunction for generators to work with fixed seeds.Should I change the general index benchmarks to use that mixed approach where just the page data is generated using QuickCheck?