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
toGVal xs = mapToGVal (Map.map toGVal xs)
mapToGVal :: Map Text (GVal m) -> GVal m
mapToGVal xs =
def
{ asHtml = mconcat . Prelude.map asHtml . Map.elems $ xs
, asText = mconcat . Prelude.map asText . Map.elems $ xs
, asBytes = mconcat . Prelude.map asBytes . Map.elems $ xs
, asBoolean = not . Map.null $ xs
, isNull = False
, asLookup = Just (`Map.lookup` xs)
, asDictItems = Just $ Map.toAscList xs
}
{-# INLINE mapToGVal #-}I changed rawJSONToGVal to transform the keys and values
in a single pass.
#if MIN_VERSION_aeson(2,0,0)
rawJSONToGVal (JSON.Object o) = mapToGVal . Map.fromList . List.map (bimap AK.toText toGVal) $ AKM.toList o
#else
rawJSONToGVal (JSON.Object o) = toGVal o
#endifThis 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 |