This breaks any existing keys database!
IKey serializes more efficiently than SKey, although this limits the
use of its Read/Show instances.
This makes the keys database use less disk space, and so should be a win.
Updated benchmark:
benchmarking keys database/getAssociatedFiles from 1000 (hit)
time                 64.04 μs   (63.95 μs .. 64.13 μs)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 64.02 μs   (63.96 μs .. 64.08 μs)
std dev              218.2 ns   (172.5 ns .. 299.3 ns)
benchmarking keys database/getAssociatedFiles from 1000 (miss)
time                 52.53 μs   (52.18 μs .. 53.21 μs)
                     0.999 R²   (0.998 R² .. 1.000 R²)
mean                 52.31 μs   (52.18 μs .. 52.91 μs)
std dev              734.6 ns   (206.2 ns .. 1.623 μs)
benchmarking keys database/getAssociatedKey from 1000 (hit)
time                 64.60 μs   (64.46 μs .. 64.77 μs)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 64.74 μs   (64.57 μs .. 65.20 μs)
std dev              900.2 ns   (389.7 ns .. 1.733 μs)
benchmarking keys database/getAssociatedKey from 1000 (miss)
time                 52.46 μs   (52.29 μs .. 52.68 μs)
                     1.000 R²   (0.999 R² .. 1.000 R²)
mean                 52.63 μs   (52.35 μs .. 53.37 μs)
std dev              1.362 μs   (562.7 ns .. 2.608 μs)
variance introduced by outliers: 24% (moderately inflated)
benchmarking keys database/addAssociatedFile to 1000 (old)
time                 487.3 μs   (484.7 μs .. 490.1 μs)
                     1.000 R²   (0.999 R² .. 1.000 R²)
mean                 490.9 μs   (487.8 μs .. 496.5 μs)
std dev              13.95 μs   (6.841 μs .. 22.03 μs)
variance introduced by outliers: 20% (moderately inflated)
benchmarking keys database/addAssociatedFile to 1000 (new)
time                 6.633 ms   (5.741 ms .. 7.751 ms)
                     0.905 R²   (0.850 R² .. 0.965 R²)
mean                 8.252 ms   (7.803 ms .. 8.602 ms)
std dev              1.126 ms   (900.3 μs .. 1.430 ms)
variance introduced by outliers: 72% (severely inflated)
benchmarking keys database/getAssociatedFiles from 10000 (hit)
time                 65.36 μs   (64.71 μs .. 66.37 μs)
                     0.998 R²   (0.995 R² .. 1.000 R²)
mean                 65.28 μs   (64.72 μs .. 66.45 μs)
std dev              2.576 μs   (920.8 ns .. 4.122 μs)
variance introduced by outliers: 42% (moderately inflated)
benchmarking keys database/getAssociatedFiles from 10000 (miss)
time                 52.34 μs   (52.25 μs .. 52.45 μs)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 52.49 μs   (52.42 μs .. 52.59 μs)
std dev              255.4 ns   (205.8 ns .. 312.9 ns)
benchmarking keys database/getAssociatedKey from 10000 (hit)
time                 64.76 μs   (64.67 μs .. 64.84 μs)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 64.67 μs   (64.62 μs .. 64.72 μs)
std dev              177.3 ns   (148.1 ns .. 217.1 ns)
benchmarking keys database/getAssociatedKey from 10000 (miss)
time                 52.75 μs   (52.66 μs .. 52.82 μs)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 52.69 μs   (52.63 μs .. 52.75 μs)
std dev              210.6 ns   (173.7 ns .. 265.9 ns)
benchmarking keys database/addAssociatedFile to 10000 (old)
time                 489.7 μs   (488.7 μs .. 490.7 μs)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 490.4 μs   (489.6 μs .. 492.2 μs)
std dev              3.990 μs   (2.435 μs .. 7.604 μs)
benchmarking keys database/addAssociatedFile to 10000 (new)
time                 9.994 ms   (9.186 ms .. 10.74 ms)
                     0.959 R²   (0.928 R² .. 0.979 R²)
mean                 9.906 ms   (9.343 ms .. 10.40 ms)
std dev              1.384 ms   (1.051 ms .. 2.100 ms)
variance introduced by outliers: 69% (severely inflated)
		
	
			
		
			
				
	
	
		
			123 lines
		
	
	
	
		
			3.7 KiB
			
		
	
	
	
		
			Haskell
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
	
		
			3.7 KiB
			
		
	
	
	
		
			Haskell
		
	
	
	
	
	
{- git-annex benchmark
 | 
						|
 -
 | 
						|
 - Copyright 2016 Joey Hess <id@joeyh.name>
 | 
						|
 -
 | 
						|
 - Licensed under the GNU GPL version 3 or higher.
 | 
						|
 -}
 | 
						|
 | 
						|
{-# OPTIONS_GHC -fno-warn-orphans #-}
 | 
						|
 | 
						|
module Command.Benchmark where
 | 
						|
 | 
						|
import Command
 | 
						|
import Database.Types
 | 
						|
import qualified Database.Keys.SQL as SQL
 | 
						|
import qualified Database.Queue as H
 | 
						|
import Utility.Tmp
 | 
						|
import Git.FilePath
 | 
						|
 | 
						|
import Criterion.Main
 | 
						|
import Criterion.Internal (runAndAnalyse)
 | 
						|
import Criterion.Monad
 | 
						|
import Control.Monad.IO.Class (liftIO)
 | 
						|
import Control.Monad
 | 
						|
import Control.DeepSeq
 | 
						|
import System.FilePath
 | 
						|
import System.Random
 | 
						|
 | 
						|
cmd :: Command
 | 
						|
cmd = noRepo (withParams benchmark) $
 | 
						|
	dontCheck repoExists $
 | 
						|
		command "benchmark" SectionTesting
 | 
						|
			"run benchmarks"
 | 
						|
			paramNothing
 | 
						|
			(withParams (liftIO . benchmark))
 | 
						|
 | 
						|
benchmark :: CmdParams -> IO ()
 | 
						|
benchmark _ = withTmpDirIn "." "benchmark" $ \tmpdir -> do
 | 
						|
	-- benchmark different sizes of databases
 | 
						|
	dbs <- mapM (benchDb tmpdir)
 | 
						|
		[ 1000
 | 
						|
		, 10000
 | 
						|
		-- , 100000
 | 
						|
		]
 | 
						|
	runCriterion $
 | 
						|
		bgroup "keys database" $ flip concatMap dbs $ \db ->
 | 
						|
			[ getAssociatedFilesHitBench db
 | 
						|
			, getAssociatedFilesMissBench db
 | 
						|
			, getAssociatedKeyHitBench db
 | 
						|
			, getAssociatedKeyMissBench db
 | 
						|
			, addAssociatedFileOldBench db
 | 
						|
			, addAssociatedFileNewBench db
 | 
						|
			]
 | 
						|
 | 
						|
getAssociatedFilesHitBench :: BenchDb -> Benchmark
 | 
						|
getAssociatedFilesHitBench ( BenchDb h num) = bench ("getAssociatedFiles from " ++ show num ++ " (hit)") $ nfIO $ do
 | 
						|
	n <- getStdRandom (randomR (1,num))
 | 
						|
	SQL.getAssociatedFiles (keyN n) (SQL.ReadHandle h)
 | 
						|
 | 
						|
getAssociatedFilesMissBench :: BenchDb -> Benchmark
 | 
						|
getAssociatedFilesMissBench ( BenchDb h num) = bench ("getAssociatedFiles from " ++ show num ++ " (miss)") $ nfIO $
 | 
						|
	SQL.getAssociatedFiles keyMiss (SQL.ReadHandle h)
 | 
						|
 | 
						|
getAssociatedKeyHitBench :: BenchDb -> Benchmark
 | 
						|
getAssociatedKeyHitBench (BenchDb h num) = bench ("getAssociatedKey from " ++ show num ++ " (hit)") $ nfIO $ do
 | 
						|
	n <- getStdRandom (randomR (1,num))
 | 
						|
	SQL.getAssociatedKey (fileN n) (SQL.ReadHandle h)
 | 
						|
 | 
						|
getAssociatedKeyMissBench :: BenchDb -> Benchmark
 | 
						|
getAssociatedKeyMissBench (BenchDb h num) = bench ("getAssociatedKey from " ++ show num ++ " (miss)") $ nfIO $
 | 
						|
	SQL.getAssociatedKey fileMiss (SQL.ReadHandle h)
 | 
						|
 | 
						|
addAssociatedFileOldBench :: BenchDb -> Benchmark
 | 
						|
addAssociatedFileOldBench ( BenchDb h num) = bench ("addAssociatedFile to " ++ show num ++ " (old)") $ nfIO $ do
 | 
						|
	n <- getStdRandom (randomR (1,num))
 | 
						|
	SQL.addAssociatedFile (keyN n) (fileN n) (SQL.WriteHandle h)
 | 
						|
	H.flushDbQueue h
 | 
						|
 | 
						|
addAssociatedFileNewBench :: BenchDb -> Benchmark
 | 
						|
addAssociatedFileNewBench ( BenchDb h num) = bench ("addAssociatedFile to " ++ show num ++ " (new)") $ nfIO $ do
 | 
						|
	n <- getStdRandom (randomR (1,num))
 | 
						|
	SQL.addAssociatedFile (keyN n) (fileN (n+1)) (SQL.WriteHandle h)
 | 
						|
	H.flushDbQueue h
 | 
						|
 | 
						|
populateAssociatedFiles :: H.DbQueue -> Int -> IO ()
 | 
						|
populateAssociatedFiles h num = do
 | 
						|
	forM_ [1..num] $ \n ->
 | 
						|
		SQL.addAssociatedFile (keyN n) (fileN n) (SQL.WriteHandle h)
 | 
						|
	H.flushDbQueue h
 | 
						|
 | 
						|
keyN :: Int -> IKey
 | 
						|
keyN n = IKey ("key" ++ show n)
 | 
						|
 | 
						|
fileN :: Int -> TopFilePath
 | 
						|
fileN n = asTopFilePath ("file" ++ show n)
 | 
						|
 | 
						|
keyMiss :: IKey
 | 
						|
keyMiss = keyN 0 -- 0 is never stored
 | 
						|
 | 
						|
fileMiss :: TopFilePath
 | 
						|
fileMiss = fileN 0 -- 0 is never stored
 | 
						|
 | 
						|
data BenchDb = BenchDb H.DbQueue Int
 | 
						|
 | 
						|
benchDb :: FilePath -> Int -> IO BenchDb
 | 
						|
benchDb tmpdir num = do
 | 
						|
	putStrLn $ "setting up database with " ++ show num
 | 
						|
	H.initDb f SQL.createTables
 | 
						|
	h <- H.openDbQueue f SQL.containedTable
 | 
						|
	populateAssociatedFiles h num
 | 
						|
	return (BenchDb h num)
 | 
						|
  where
 | 
						|
	f = tmpdir </> "db" ++ show num
 | 
						|
 | 
						|
instance NFData TopFilePath where
 | 
						|
	rnf = rnf . getTopFilePath
 | 
						|
 | 
						|
instance NFData IKey where
 | 
						|
	rnf (IKey s) = rnf s
 | 
						|
	
 | 
						|
-- can't use Criterion's defaultMain here because it looks at
 | 
						|
-- command-line parameters
 | 
						|
runCriterion :: Benchmark -> IO ()
 | 
						|
runCriterion = withConfig defaultConfig . runAndAnalyse (const True)
 |