2
2
3
3
module Bench.Database.LSMTree.Internal.Lookup (benchmarks ) where
4
4
5
- import Control.Exception (assert )
5
+ import Control.Exception (assert , evaluate )
6
6
import Control.Monad
7
- import Control.Monad.ST.Strict (stToIO )
8
7
import Criterion.Main (Benchmark , bench , bgroup , env , envWithCleanup ,
9
- perRunEnv , perRunEnvWithCleanup , whnf , whnfAppIO )
10
- import Data.Arena (ArenaManager , closeArena , newArena ,
11
- newArenaManager , withArena )
8
+ perRunEnvWithCleanup , whnf , whnfAppIO )
12
9
import Data.Bifunctor (Bifunctor (.. ))
13
10
import qualified Data.List as List
14
11
import Data.Map.Strict (Map )
@@ -21,7 +18,10 @@ import Database.LSMTree.Extras.Random (frequency,
21
18
import Database.LSMTree.Extras.UTxO
22
19
import Database.LSMTree.Internal.Entry (Entry (.. ), NumEntries (.. ))
23
20
import Database.LSMTree.Internal.Lookup (bloomQueriesDefault ,
24
- indexSearches , intraPageLookups , lookupsIO , prepLookups )
21
+ cleanupPreparedLookups , indexSearches , intraPageLookups ,
22
+ lookupsIO , unmanagedAllocatePagesForIndexSearches ,
23
+ unmanagedPreparedLookups , withPreparedLookups )
24
+ import Database.LSMTree.Internal.PageAlloc
25
25
import Database.LSMTree.Internal.Paths (RunFsPaths (.. ))
26
26
import Database.LSMTree.Internal.Run (Run )
27
27
import qualified Database.LSMTree.Internal.Run as Run
@@ -77,7 +77,7 @@ benchmarks = bgroup "Bench.Database.LSMTree.Internal.Lookup" [
77
77
78
78
benchLookups :: Config -> Benchmark
79
79
benchLookups conf@ Config {name} =
80
- withEnv $ \ ~ (_dir, arenaManager , _hasFS, hasBlockIO, rs, ks) ->
80
+ withEnv $ \ ~ (_dir, pagealloc , _hasFS, hasBlockIO, rs, ks) ->
81
81
env ( pure ( V. map Run. runFilter rs
82
82
, V. map Run. runIndex rs
83
83
, V. map Run. runKOpsFile rs
@@ -90,24 +90,33 @@ benchLookups conf@Config{name} =
90
90
whnf (\ ks' -> bloomQueriesDefault blooms ks') ks
91
91
-- The compact index is only searched for (true and false) positive
92
92
-- lookup keys. We use whnf here because the result is
93
- , env (pure $ bloomQueriesDefault blooms ks) $ \ rkixs ->
94
- bench " Compact index search" $
95
- whnfAppIO (\ ks' -> withArena arenaManager $ \ arena -> stToIO $ indexSearches arena indexes kopsFiles ks' rkixs) ks
93
+ , env (do let ! rkixs = bloomQueriesDefault blooms ks
94
+ pages <- unmanagedAllocatePagesForIndexSearches pagealloc rkixs
95
+ return (rkixs, pages))
96
+ (\ ~ (rkixs, pages) ->
97
+ bench " Compact index search" $
98
+ whnf (\ ks' -> indexSearches indexes kopsFiles
99
+ ks' pages rkixs) ks)
96
100
-- prepLookups combines bloom filter querying and index searching.
97
101
-- The implementation forces the results to WHNF, so we use
98
102
-- whnfAppIO here instead of nfAppIO.
99
103
, bench " Lookup preparation in memory" $
100
- whnfAppIO (\ ks' -> withArena arenaManager $ \ arena -> stToIO $ prepLookups arena blooms indexes kopsFiles ks') ks
104
+ whnfAppIO (\ ks' -> withPreparedLookups
105
+ pagealloc blooms indexes
106
+ kopsFiles ks' $ \ rkixs ioops ->
107
+ void $ evaluate rkixs >> evaluate ioops
108
+ ) ks
101
109
-- Submit the IOOps we get from prepLookups to HasBlockIO. We use
102
110
-- perRunEnv because IOOps contain mutable buffers, so we want fresh
103
111
-- ones for each run of the benchmark. We manually evaluate the
104
112
-- result to WHNF since it is unboxed vector.
105
113
, bench " Submit IOOps" $
106
114
-- TODO: here arena is destroyed too soon
107
115
-- but it should be fine for non-debug code
108
- perRunEnv (withArena arenaManager $ \ arena -> stToIO $ prepLookups arena blooms indexes kopsFiles ks) $ \ ~ (_rkixs, ioops) -> do
109
- ! _ioress <- FS. submitIO hasBlockIO ioops
110
- pure ()
116
+ perRunEnvWithCleanup
117
+ (unmanagedPreparedLookups pagealloc blooms indexes kopsFiles ks)
118
+ (cleanupPreparedLookups pagealloc)
119
+ (\ ~ (_, ioops, _) -> void $ evaluate =<< FS. submitIO hasBlockIO ioops)
111
120
-- When IO result have been collected, intra-page lookups searches
112
121
-- through the raw bytes (representing a disk page) for the lookup
113
122
-- key. Again, we use perRunEnv here because IOOps contain mutable
@@ -117,20 +126,21 @@ benchLookups conf@Config{name} =
117
126
-- only compute WHNF.
118
127
, bench " Perform intra-page lookups" $
119
128
perRunEnvWithCleanup
120
- ( newArena arenaManager >>= \ arena ->
121
- stToIO (prepLookups arena blooms indexes kopsFiles ks) >>= \ (rkixs, ioops) ->
122
- FS. submitIO hasBlockIO ioops >>= \ ioress ->
123
- pure (rkixs, ioops, ioress, arena)
124
- )
125
- (\ (_, _, _, arena) -> closeArena arenaManager arena) $ \ ~ (rkixs, ioops, ioress, _) -> do
126
- ! _ <- intraPageLookups resolveV rs ks rkixs ioops ioress
127
- pure ()
129
+ (do (rkixs, ioops, pages) <-
130
+ unmanagedPreparedLookups pagealloc blooms
131
+ indexes kopsFiles ks
132
+ ioress <- FS. submitIO hasBlockIO ioops
133
+ return ((rkixs, ioops, pages), ioress))
134
+ (cleanupPreparedLookups pagealloc . fst )
135
+ (\ ~ ((rkixs, ioops, _pages), ioress) ->
136
+ void $ evaluate =<< intraPageLookups resolveV rs ks
137
+ rkixs ioops ioress)
128
138
-- The whole shebang: lookup preparation, doing the IO, and then
129
139
-- performing intra-page-lookups. Again, we evaluate the result to
130
140
-- WHNF because it is the same result that intraPageLookups produces
131
141
-- (see above).
132
142
, bench " Lookups in IO" $
133
- whnfAppIO (\ ks' -> lookupsIO hasBlockIO arenaManager resolveV rs blooms indexes kopsFiles ks') ks
143
+ whnfAppIO (\ ks' -> lookupsIO hasBlockIO pagealloc resolveV rs blooms indexes kopsFiles ks') ks
134
144
]
135
145
where
136
146
withEnv = envWithCleanup
@@ -162,14 +172,14 @@ data Config = Config {
162
172
lookupsInBatchesEnv ::
163
173
Config
164
174
-> IO ( FilePath -- ^ Temporary directory
165
- , ArenaManager RealWorld
175
+ , PageAlloc RealWorld
166
176
, FS. HasFS IO FS. HandleIO
167
177
, FS. HasBlockIO IO FS. HandleIO
168
178
, V. Vector (Run (FS. Handle FS. HandleIO ))
169
179
, V. Vector SerialisedKey
170
180
)
171
181
lookupsInBatchesEnv Config {.. } = do
172
- arenaManager <- newArenaManager
182
+ pagealloc <- newPageAlloc
173
183
sysTmpDir <- getCanonicalTemporaryDirectory
174
184
benchTmpDir <- createTempDirectory sysTmpDir " lookupsInBatchesEnv"
175
185
(storedKeys, lookupKeys) <- lookupsEnv (mkStdGen 17 ) nentries npos nneg
@@ -184,7 +194,7 @@ lookupsInBatchesEnv Config {..} = do
184
194
assert (npagesReal * 42 <= nentriesReal) $ pure ()
185
195
assert (npagesReal * 43 >= nentriesReal) $ pure ()
186
196
pure ( benchTmpDir
187
- , arenaManager
197
+ , pagealloc
188
198
, hasFS
189
199
, hasBlockIO
190
200
, V. singleton r
@@ -193,14 +203,14 @@ lookupsInBatchesEnv Config {..} = do
193
203
194
204
lookupsInBatchesCleanup ::
195
205
( FilePath -- ^ Temporary directory
196
- , ArenaManager RealWorld
206
+ , PageAlloc RealWorld
197
207
, FS. HasFS IO FS. HandleIO
198
208
, FS. HasBlockIO IO FS. HandleIO
199
209
, V. Vector (Run (FS. Handle FS. HandleIO ))
200
210
, V. Vector SerialisedKey
201
211
)
202
212
-> IO ()
203
- lookupsInBatchesCleanup (tmpDir, _arenaManager , hasFS, hasBlockIO, rs, _) = do
213
+ lookupsInBatchesCleanup (tmpDir, _pagealloc , hasFS, hasBlockIO, rs, _) = do
204
214
FS. close hasBlockIO
205
215
forM_ rs $ Run. removeReference hasFS
206
216
removeDirectoryRecursive tmpDir
0 commit comments