CBOR/MessagePack readers: leave one-element arrays to the general path
enter_cbor_array and enter_msgpack_array called the out-of-line scalar run for every non-empty array. When the array's element is an object or an array, as on every level of [[...]] or the single ring of a GeoJSON polygon, the call reads nothing; it made 1,000 arrays nested in each other cost 4 % more instructions (GCC 13) and up to 8 % more time (Apple clang) than without the run. #5975 had fixed that with an inline pre-check, which was later dropped after measuring canada only. The run is now entered only for arrays of two or more elements: the same comparison as before, so no other row changes. Arrays of one scalar, which the run read faster, now take the general path; they are rare in documents (one in citm_catalog, none in twitter or canada). The new benchmark FromBinaryShape/singles measures them, next to FromBinaryShape/nested. Instructions per repetition, new/old, GCC 13 callgrind: nested arrays 0.973 (CBOR) and 0.971 (MessagePack), arrays of one scalar 1.037 and 1.021, every other row within 0.15 %. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
5 files changed
+96
-6
No files matched your search
@@ -1856,14 +1856,18 @@ class binary_reader
|
||||
|
||||
Only the start of an array is tried, which covers arrays of numbers
|
||||
(e.g. coordinates) but costs arrays of other values only one call, not one
|
||||
per element.
|
||||
per element. An array of one element is not tried at all: that element is
|
||||
mostly an object or an array (`[[...]]`, the single ring of a GeoJSON
|
||||
polygon), for which the call would find no scalar, while a single scalar,
|
||||
which the run would read faster, is rare. The benchmarks
|
||||
`FromBinaryShape/nested` and `FromBinaryShape/singles` show both sides.
|
||||
|
||||
@param[in] len the number of elements
|
||||
@return whether the SAX parser accepted the array and the values read
|
||||
*/
|
||||
bool enter_cbor_array(const std::size_t len)
|
||||
{
|
||||
return enter_array(len) && (len == 0 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
return enter_array(len) && (len <= 1 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
}
|
||||
|
||||
/// input that is not contiguous: every value is read by parse_cbor_value
|
||||
@@ -2764,12 +2768,16 @@ class binary_reader
|
||||
/*!
|
||||
@brief open a MessagePack array and read the scalars it begins with (see
|
||||
@ref parse_msgpack_scalar_run)
|
||||
|
||||
An array of one element is not tried, for the reason given at
|
||||
@ref enter_cbor_array.
|
||||
|
||||
@param[in] len the number of elements
|
||||
@return whether the SAX parser accepted the array and the values read
|
||||
*/
|
||||
bool enter_msgpack_array(const std::size_t len)
|
||||
{
|
||||
return enter_array(len) && (len == 0 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
return enter_array(len) && (len <= 1 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||
}
|
||||
|
||||
/// input that is not contiguous: every value is read by parse_msgpack_value
|
||||
|
||||
Reference in new issue
Block a user