on master help sign in
benchmarks
commit6ab4cd59609faa595e0e96fb0d3048fb7180d9e0 authorMark Wotton <mwotton@gmail.com> dateWed 30 Dec 2020, 13:03 (6 years ago) parent75ec6d3
5 files changed+143
benchmarks/README.md+30 benchmarks/genFile.sh+13 benchmarks/prelude+80 benchmarks/runTiming.sh+10 benchmarks/runTimingNoisy.sh+10
benchmarks/README.mdnew file+30
@@ -0,0 +1,30 @@
1+# Benchmarks
2+
3+I've noticed compilation can be a little slow on realistic apps so I set up a test.
4+
5+## components
6+
7+1. codegen
8+
9+ given an integer input n, create an api with n endpoints. they should take a reasonably
10+ complicated input and return a reasonably complicated output
11+
12+2. runner
13+
14+ build dependencies
15+ for i from 1 to 100
16+ generate api with i endpoints
17+ compile it, but timed
18+ print (i,time)
19+
20+3. plot to see linearity/quadraticity?
21+
22+## possible gotchas
23+
24+- we usually compile these in different modules rather than together: if we don't get slow
25+ compilation in one file, try out multiple files.
26+
27+## notes
28+
29+- flat profile if you don't have the call to `fuzz`
30+- no difference between deriving via Atom vs Compound, so not a Generics thing.
benchmarks/genFile.shnew file+13
@@ -0,0 +1,13 @@
1+n=$1
2+
3+cat prelude
4+echo -n "type Api = \"route1\" :> ReqBody '[JSON] Input :> Post '[JSON] Output"
5+for i in $(seq 2 $n); do
6+ echo " :<|> \"route${i}\" :> ReqBody '[JSON] Input :> Post '[JSON] Output"
7+done
8+
9+echo -n "server = handler "
10+
11+for i in $(seq 2 $n); do
12+ echo -n ":<|> handler "
13+done
benchmarks/preludenew file+80
@@ -0,0 +1,80 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE DataKinds #-}
4+{-# LANGUAGE TypeApplications #-}
5+{-# LANGUAGE DerivingVia #-}
6+{-# LANGUAGE StandaloneDeriving #-}
7+{-# LANGUAGE DeriveGeneric #-}
8+
9+
10+import Roboservant
11+import Servant
12+import Data.Hashable
13+import GHC.Generics
14+import Data.Aeson
15+
16+data Input = Input1 { foo :: String }
17+ | Input2 { bar :: Int }
18+ deriving (Generic, Eq)
19+
20+instance FromJSON Input
21+instance ToJSON Input
22+
23+
24+deriving via (Compound Input) instance Breakdown Input
25+deriving via (Compound Input) instance BuildFrom Input
26+
27+
28+-- deriving via (Atom Input) instance Breakdown Input
29+-- deriving via (Atom Input) instance BuildFrom Input
30+
31+instance Hashable Input
32+
33+
34+data Output = Output1 { ofoo :: String }
35+ | Output2 { obar :: Int }
36+ deriving (Generic, Eq)
37+
38+instance FromJSON Output
39+instance ToJSON Output
40+
41+instance Hashable Output
42+
43+deriving via (Compound Output) instance Breakdown Output
44+deriving via (Compound Output) instance BuildFrom Output
45+
46+-- deriving via (Atom Output) instance Breakdown Output
47+-- deriving via (Atom Output) instance BuildFrom Output
48+
49+
50+handler :: Input -> Handler Output
51+handler = pure . \case
52+ Input1 foo -> Output1 foo
53+ Input2 bar -> Output2 bar
54+
55+main =
56+ -- 28s at 80 reps
57+ -- fuzz @Api server defaultConfig (pure ())
58+ pure ()
59+
60+-- 18.5s at 80 reps
61+-- reifiedApi = toReifiedApi flattened endpoints
62+
63+flattened = flattenServer @Api server
64+
65+endpoints = Proxy @(Endpoints Api)
66+
67+defaultConfig :: Config
68+defaultConfig = Config {
69+ -- you can pass extra values in using the seed argument. This can be useful
70+ -- for things that might not be produceable within the api, like auth tokens.
71+ seed = [hashedDyn "blah"]
72+ , maxRuntime = 0.5
73+ -- if we get to 1000 interactions with the api, call it quits.
74+ , maxReps = 1000
75+ -- if you're using this inside quickcheck or hedgehog, you might want to set this
76+ -- from their seed to make sure it stays deterministic
77+ , rngSeed = 0
78+ -- 0 to 100: fail tests if we hit less than this percentage of endpoints.
79+ , coverageThreshold = 0
80+ }
benchmarks/runTiming.shnew file+10
@@ -0,0 +1,10 @@
1+lo=$1
2+hi=$2
3+
4+for i in $(seq $lo 5 $hi); do
5+ ./genFile.sh $i > main.hs;
6+ echo "sievedn: $i,";
7+ /usr/bin/time -f "%e" stack ghc main.hs 2>&1;
8+# /usr/bin/time -f "%e" stack ghc -- -fomit-interface-pragmas main.hs 2>&1;
9+
10+done | grep -v Compiling | grep -v Linking | awk '/,$/ { printf("%s", $0); next } 1' | sed 's/sievedn: //'
benchmarks/runTimingNoisy.shnew file+10
@@ -0,0 +1,10 @@
1+lo=$1
2+hi=$2
3+
4+for i in $(seq $lo 5 $hi); do
5+ ./genFile.sh $i > main.hs;
6+ echo "sievedn: $i,";
7+ /usr/bin/time -f "%e" stack ghc main.hs 2>&1;
8+# /usr/bin/time -f "%e" stack ghc -- -fomit-interface-pragmas main.hs 2>&1;
9+
10+done