Aeson 2 Object Coercion (Part 2)
I did not plan on spending any more time on optimizing aeson and ginger after writing the Aeson 2 Object Coercion blog entry, but I ended up doing a few more experiments.
First, I realized that my rawJSONToGVal
change also
traverses objects twice, transforming keys and values separately.
Curious to see the performance impact, I moved the helper
function of the Map Text
instance to the top level so that
it can be used by rawJSONToGVal
as well. Note that I added
an INLINE
pragma to ensure that it is (still?) inlined even
though it is used in two locations.
instance ToGVal m v => ToGVal m (Map Text v) where
= mapToGVal (Map.map toGVal xs)
toGVal xs
mapToGVal :: Map Text (GVal m) -> GVal m
=
mapToGVal xs
def= mconcat . Prelude.map asHtml . Map.elems $ xs
{ asHtml = mconcat . Prelude.map asText . Map.elems $ xs
, asText = mconcat . Prelude.map asBytes . Map.elems $ xs
, asBytes = not . Map.null $ xs
, asBoolean = False
, isNull = Just (`Map.lookup` xs)
, asLookup = Just $ Map.toAscList xs
, asDictItems
}{-# INLINE mapToGVal #-}
I changed rawJSONToGVal
to transform the keys and values
in a single pass.
#if MIN_VERSION_aeson(2,0,0)
JSON.Object o) = mapToGVal . Map.fromList . List.map (bimap AK.toText toGVal) $ AKM.toList o
rawJSONToGVal (#else
JSON.Object o) = toGVal o
rawJSONToGVal (#endif
This change does indeed improve the performance.
toGVal (ms) |
|
---|---|
Aeson 2 Map |
10.80 |
Aeson 2 HashMap |
10.81 |
Next, I created a second version of unsafeAesonToGVal
(code)
that avoids calling toGVal
at all. This is done by copying
instance implementations into separate functions, with slight
modifications. This allowed me to avoid multiple traversals as well as
do some aggressive inlining, but the code is even more unsightly than
the first version. This version even marginally outperforms the Aeson 1
baseline in this test case.
toGVal |
unsafeAesonToGVal 1 |
unsafeAesonToGVal 2 |
|
---|---|---|---|
Aeson 1 | 10.94 | 11.01 | 11.19 |
Aeson 2 Map |
10.95 | 10.79 | 10.78 |
Aeson 2 HashMap |
10.90 | 10.84 | 10.76 |