@@ -10,6 +10,7 @@ import Criterion
1010import Data.Csv
1111import Data.Proxy
1212import Data.Typeable
13+ import Generic.Either
1314import Generic.U2
1415import Generic.U4
1516import Generic.U8
@@ -19,94 +20,204 @@ import Generic.U32
1920
2021genericFieldBench :: Benchmark
2122genericFieldBench = bgroup " genericField"
22- [ bgroup " parseField: ok"
23- [ mkParseSuccessBench (Proxy @ U2 ) (Proxy @ U2Generic ) (Proxy @ U2GenericStripPrefix )
24- , mkParseSuccessBench (Proxy @ U4 ) (Proxy @ U4Generic ) (Proxy @ U4GenericStripPrefix )
25- , mkParseSuccessBench (Proxy @ U8 ) (Proxy @ U8Generic ) (Proxy @ U8GenericStripPrefix )
26- , mkParseSuccessBench (Proxy @ U16 ) (Proxy @ U16Generic ) (Proxy @ U16GenericStripPrefix )
27- , mkParseSuccessBench (Proxy @ U32 ) (Proxy @ U32Generic ) (Proxy @ U32GenericStripPrefix )
23+ [ bgroup " parseField:ok"
24+ [ mkParseSuccessBench (genRange @ U2 )
25+ , mkParseSuccessBench (genRange @ U2Generic )
26+ , mkParseSuccessBench (genRange @ U2GenericStripPrefix )
27+ , mkParseSuccessBench (genRange @ U4 )
28+ , mkParseSuccessBench (genRange @ U4Generic )
29+ , mkParseSuccessBench (genRange @ U4GenericStripPrefix )
30+ , mkParseSuccessBench (genRange @ U8 )
31+ , mkParseSuccessBench (genRange @ U8Generic )
32+ , mkParseSuccessBench (genRange @ U8GenericStripPrefix )
33+ , mkParseSuccessBench (genRange @ U16 )
34+ , mkParseSuccessBench (genRange @ U16Generic )
35+ , mkParseSuccessBench (genRange @ U16GenericStripPrefix )
36+ , mkParseSuccessBench (genRange @ U32 )
37+ , mkParseSuccessBench (genRange @ U32Generic )
38+ , mkParseSuccessBench (genRange @ U32GenericStripPrefix )
39+ , mkParseSuccessBench manualEither0
40+ , mkParseSuccessBench genericEither0
41+ , mkParseSuccessBench manualEither1
42+ , mkParseSuccessBench genericEither1
43+ , mkParseSuccessBench manualEither2
44+ , mkParseSuccessBench genericEither2
45+ , mkParseSuccessBench manualEither3
46+ , mkParseSuccessBench genericEither3
2847 ]
29- , bgroup " parseField: fail"
30- [ mkParseFailBench (Proxy @ U2 ) (Proxy @ U2Generic ) (Proxy @ U2GenericStripPrefix )
31- , mkParseFailBench (Proxy @ U4 ) (Proxy @ U4Generic ) (Proxy @ U4GenericStripPrefix )
32- , mkParseFailBench (Proxy @ U8 ) (Proxy @ U8Generic ) (Proxy @ U8GenericStripPrefix )
33- , mkParseFailBench (Proxy @ U16 ) (Proxy @ U16Generic ) (Proxy @ U16GenericStripPrefix )
34- , mkParseFailBench (Proxy @ U32 ) (Proxy @ U32Generic ) (Proxy @ U32GenericStripPrefix )
48+ , bgroup " parseField:fail"
49+ [ mkParseFailBench (Proxy @ U2 )
50+ , mkParseFailBench (Proxy @ U2Generic )
51+ , mkParseFailBench (Proxy @ U2GenericStripPrefix )
52+ , mkParseFailBench (Proxy @ U4 )
53+ , mkParseFailBench (Proxy @ U4Generic )
54+ , mkParseFailBench (Proxy @ U4GenericStripPrefix )
55+ , mkParseFailBench (Proxy @ U8 )
56+ , mkParseFailBench (Proxy @ U8Generic )
57+ , mkParseFailBench (Proxy @ U8GenericStripPrefix )
58+ , mkParseFailBench (Proxy @ U16 )
59+ , mkParseFailBench (Proxy @ U16Generic )
60+ , mkParseFailBench (Proxy @ U16GenericStripPrefix )
61+ , mkParseFailBench (Proxy @ U32 )
62+ , mkParseFailBench (Proxy @ U32Generic )
63+ , mkParseFailBench (Proxy @ U32GenericStripPrefix )
64+ , mkParseFailBench (Proxy @ ManualEither0 )
65+ , mkParseFailBench (Proxy @ GenericEither0 )
66+ , mkParseFailBench (Proxy @ ManualEither1 )
67+ , mkParseFailBench (Proxy @ GenericEither1 )
68+ , mkParseFailBench (Proxy @ ManualEither2 )
69+ , mkParseFailBench (Proxy @ GenericEither2 )
70+ , mkParseFailBench (Proxy @ ManualEither3 )
71+ , mkParseFailBench (Proxy @ GenericEither3 )
3572 ]
3673 , bgroup " toField"
37- [ mkToFieldBench (Proxy @ U2 ) (Proxy @ U2Generic ) (Proxy @ U2GenericStripPrefix )
38- , mkToFieldBench (Proxy @ U4 ) (Proxy @ U4Generic ) (Proxy @ U4GenericStripPrefix )
39- , mkToFieldBench (Proxy @ U8 ) (Proxy @ U8Generic ) (Proxy @ U8GenericStripPrefix )
40- , mkToFieldBench (Proxy @ U16 ) (Proxy @ U16Generic ) (Proxy @ U16GenericStripPrefix )
41- , mkToFieldBench (Proxy @ U32 ) (Proxy @ U32Generic ) (Proxy @ U32GenericStripPrefix )
74+ [ mkToFieldBench (genRange @ U2 )
75+ , mkToFieldBench (genRange @ U2Generic )
76+ , mkToFieldBench (genRange @ U2GenericStripPrefix )
77+ , mkToFieldBench (genRange @ U4 )
78+ , mkToFieldBench (genRange @ U4Generic )
79+ , mkToFieldBench (genRange @ U4GenericStripPrefix )
80+ , mkToFieldBench (genRange @ U8 )
81+ , mkToFieldBench (genRange @ U8Generic )
82+ , mkToFieldBench (genRange @ U8GenericStripPrefix )
83+ , mkToFieldBench (genRange @ U16 )
84+ , mkToFieldBench (genRange @ U16Generic )
85+ , mkToFieldBench (genRange @ U16GenericStripPrefix )
86+ , mkToFieldBench (genRange @ U32 )
87+ , mkToFieldBench (genRange @ U32Generic )
88+ , mkToFieldBench (genRange @ U32GenericStripPrefix )
89+ , mkToFieldBench manualEither0
90+ , mkToFieldBench genericEither0
91+ , mkToFieldBench manualEither1
92+ , mkToFieldBench genericEither1
93+ , mkToFieldBench manualEither2
94+ , mkToFieldBench genericEither2
95+ , mkToFieldBench manualEither3
96+ , mkToFieldBench genericEither3
4297 ]
4398 ]
4499
45- type IsBench a = (Bounded a , Enum a , FromField a , ToField a , NFData a )
46-
47- mkParseSuccessBench
48- :: (IsBench a , Typeable a , IsBench generic , IsBench genericWithPrefix )
49- => Proxy a
50- -> Proxy generic
51- -> Proxy genericWithPrefix
52- -> Benchmark
53- mkParseSuccessBench px pxGen pxGenPfx = bgroup (show $ typeRep px)
54- [ mkB " manual" px
55- , mkB " generic" pxGen
56- , mkB " generic with prefix" pxGenPfx
57- ]
58- where
59- {-
60- NB: this all is about sum representations.
61- Manual instance tries to parse constructors from left to right,
62- so parsing the string matching the first constructor is the best case,
63- while parsing the last matcher is the worst case.
64- Generic representation is, however, not that flat (one can check that by
65- exploring 'Rep' of U32) and is more like a balanced binary tree with root
66- being somewhere around U32_16 constructor (rough estimation).
67- To level this discrepency and compare parsing efficiency more accurately
68- we parse the whole range @[minBound..maxBound]@ of possible values for a type.
69- This corresponds to the situation where data values are uniformly distributed.
70- -}
71- mkB
72- :: (Bounded a , Enum a , FromField a , ToField a , NFData a )
73- => String -> Proxy a -> Benchmark
74- mkB name p = env (pure $ map toField $ genEnum p) $ bench name . nf (go p)
75- go :: (FromField a ) => Proxy a -> [Field ] -> [a ]
76- go p = map $ ((\ (Right x) -> x `asProxyTypeOf` p) . parse)
77-
78- mkParseFailBench
79- :: (IsBench a , Typeable a , IsBench generic , IsBench genericWithPrefix )
80- => Proxy a
81- -> Proxy generic
82- -> Proxy genericWithPrefix
83- -> Benchmark
84- mkParseFailBench px pxg pxgp = bgroup (show $ typeRep px)
85- [ bench " manual" $ whnf (\ s -> parse s `asProxyEither` px) mempty
86- , bench " generic" $ whnf (\ s -> parse s `asProxyEither` pxg) mempty
87- , bench " generic with prefix" $ whnf (\ s -> parse s `asProxyEither` pxgp) mempty
88- ]
100+ type IsBench a = (FromField a , ToField a , NFData a , Typeable a )
89101
90- asProxyEither :: Either String a -> Proxy a -> Either String a
91- asProxyEither = const
92-
93- mkToFieldBench
94- :: (IsBench a , Typeable a , IsBench generic , IsBench genericWithPrefix )
95- => Proxy a
96- -> Proxy generic
97- -> Proxy genericWithPrefix
98- -> Benchmark
99- mkToFieldBench px pxg pxgp = bgroup (show $ typeRep px)
100- [ mkB " manual" px
101- , mkB " generic" pxg
102- , mkB " generic with prefix" pxgp
103- ]
102+ {-
103+ Manual instance tries to parse constructors from left to right,
104+ so parsing the string matching the first constructor is the best case,
105+ while parsing the last matcher is the worst case.
106+ Generic representation is, however, not that flat (one can check that by
107+ exploring 'Rep' of U32) and is more like a balanced binary tree with root
108+ being somewhere around U32_16 constructor (rough estimation).
109+ To level this discrepency and compare parsing efficiency more accurately
110+ we parse some range (@[minBound..maxBound]@ for enum) of possible values for a type.
111+ This corresponds to the situation where data values are uniformly distributed.
112+ -}
113+ mkParseSuccessBench :: (IsBench a ) => [a ] -> Benchmark
114+ mkParseSuccessBench xs = env (pure $ map toField xs) $
115+ bench (show $ typeRep xs) . nf (map $ (\ (Right x) -> x `asProxyTypeOf` xs) . parse)
116+
117+ mkParseFailBench :: (IsBench a ) => Proxy a -> Benchmark
118+ mkParseFailBench px = bench (show $ typeRep px) $
119+ nf (\ s -> parse s `asProxyEither` px) mempty
104120 where
105- mkB :: (Bounded a , Enum a , ToField a ) => String -> Proxy a -> Benchmark
106- mkB name = bench name . nf (map toField) . genEnum
121+ asProxyEither :: Either String a -> Proxy a -> Either String a
122+ asProxyEither x _ = x
123+
124+ mkToFieldBench :: (IsBench a ) => [a ] -> Benchmark
125+ mkToFieldBench xs = env (pure xs) $ bench (show $ typeRep xs) . nf (map toField)
107126
108127parse :: (FromField a ) => Field -> Either String a
109128parse = runParser . parseField
110129
111- genEnum :: (Bounded a , Enum a ) => Proxy a -> [a ]
112- genEnum _ = [minBound .. maxBound ]
130+ genRange :: (Bounded a , Enum a ) => [a ]
131+ genRange = take 32 $ cycle [minBound .. maxBound ]
132+
133+ manualEither0 :: [ManualEither0 ]
134+ manualEither0 = take 32 $ cycle
135+ [ LManual 1
136+ , RManual ' !'
137+ ]
138+
139+ genericEither0 :: [GenericEither0 ]
140+ genericEither0 = take 32 $ cycle
141+ [ LGeneric 1
142+ , RGeneric ' !'
143+ ]
144+
145+ manualEither1 :: [ManualEither1 ]
146+ manualEither1 = take 32 $ cycle
147+ [ LManual $ LManual 1
148+ , LManual $ RManual ' !'
149+ , RManual $ LManual 1
150+ , RManual $ RManual ' !'
151+ ]
152+
153+ genericEither1 :: [GenericEither1 ]
154+ genericEither1 = take 32 $ cycle
155+ [ LGeneric $ LGeneric 1
156+ , LGeneric $ RGeneric ' !'
157+ , RGeneric $ LGeneric 1
158+ , RGeneric $ RGeneric ' !'
159+ ]
160+
161+ manualEither2 :: [ManualEither2 ]
162+ manualEither2 = take 32 $ cycle
163+ [ LManual $ LManual $ LManual 1
164+ , LManual $ LManual $ RManual ' !'
165+ , LManual $ RManual $ LManual 1
166+ , LManual $ RManual $ RManual ' !'
167+ , RManual $ LManual $ LManual 1
168+ , RManual $ LManual $ RManual ' !'
169+ , RManual $ RManual $ LManual 1
170+ , RManual $ RManual $ RManual ' !'
171+ ]
172+
173+ genericEither2 :: [GenericEither2 ]
174+ genericEither2 = take 32 $ cycle
175+ [ LGeneric $ LGeneric $ LGeneric 1
176+ , LGeneric $ LGeneric $ RGeneric ' !'
177+ , LGeneric $ RGeneric $ LGeneric 1
178+ , LGeneric $ RGeneric $ RGeneric ' !'
179+ , RGeneric $ LGeneric $ LGeneric 1
180+ , RGeneric $ LGeneric $ RGeneric ' !'
181+ , RGeneric $ RGeneric $ LGeneric 1
182+ , RGeneric $ RGeneric $ RGeneric ' !'
183+ ]
184+
185+ manualEither3 :: [ManualEither3 ]
186+ manualEither3 = take 32 $ cycle
187+ [ LManual $ LManual $ LManual $ LManual 1
188+ , LManual $ LManual $ LManual $ RManual ' !'
189+ , LManual $ LManual $ RManual $ LManual 1
190+ , LManual $ LManual $ RManual $ RManual ' !'
191+ , LManual $ RManual $ LManual $ LManual 1
192+ , LManual $ RManual $ LManual $ RManual ' !'
193+ , LManual $ RManual $ RManual $ LManual 1
194+ , LManual $ RManual $ RManual $ RManual ' !'
195+ , RManual $ LManual $ LManual $ LManual 1
196+ , RManual $ LManual $ LManual $ RManual ' !'
197+ , RManual $ LManual $ RManual $ LManual 1
198+ , RManual $ LManual $ RManual $ RManual ' !'
199+ , RManual $ RManual $ LManual $ LManual 1
200+ , RManual $ RManual $ LManual $ RManual ' !'
201+ , RManual $ RManual $ RManual $ LManual 1
202+ , RManual $ RManual $ RManual $ RManual ' !'
203+ ]
204+
205+ genericEither3 :: [GenericEither3 ]
206+ genericEither3 = take 32 $ cycle
207+ [ LGeneric $ LGeneric $ LGeneric $ LGeneric 1
208+ , LGeneric $ LGeneric $ LGeneric $ RGeneric ' !'
209+ , LGeneric $ LGeneric $ RGeneric $ LGeneric 1
210+ , LGeneric $ LGeneric $ RGeneric $ RGeneric ' !'
211+ , LGeneric $ RGeneric $ LGeneric $ LGeneric 1
212+ , LGeneric $ RGeneric $ LGeneric $ RGeneric ' !'
213+ , LGeneric $ RGeneric $ RGeneric $ LGeneric 1
214+ , LGeneric $ RGeneric $ RGeneric $ RGeneric ' !'
215+ , RGeneric $ LGeneric $ LGeneric $ LGeneric 1
216+ , RGeneric $ LGeneric $ LGeneric $ RGeneric ' !'
217+ , RGeneric $ LGeneric $ RGeneric $ LGeneric 1
218+ , RGeneric $ LGeneric $ RGeneric $ RGeneric ' !'
219+ , RGeneric $ RGeneric $ LGeneric $ LGeneric 1
220+ , RGeneric $ RGeneric $ LGeneric $ RGeneric ' !'
221+ , RGeneric $ RGeneric $ RGeneric $ LGeneric 1
222+ , RGeneric $ RGeneric $ RGeneric $ RGeneric ' !'
223+ ]
0 commit comments