Skip to content

C

C serialization is fragmented: each library owns its own object model (DOM trees, streams, generated structs).

Benchmark runner

  • c/ (repository root)
  • Logs: logs/c/YYYY-MM-DD-HHMMSS.csv
  • Build: CMake, C11 (+ C++17 for Google libprotobuf)
  • Deps: c/scripts/fetch-and-build-deps.sh; Google protobuf: cpp/scripts/setup-protobuf-sysroot.sh
  • Registration: c/src/register_serializers.c
  • Domain shape: map-style codecs use a single visitor in c/src/v2_codec.c (v2_write_fixture / v2_read_fixture). Wrappers implement library ops only—they do not hard-code V2 field graphs.

Serializers

Name Category Timed path (what the row measures)
cJSON, yyjson, jansson, parson, json-c JSON Library DOM build + print / parse via visitor ops
custom-binary Binary Suite length-prefixed V2 baseline (bin_write_fixture / bin_read_fixture)
flatcc, avro-c Schema Real flatcc builder / avro-c iface write-read wrapping V2 payload bytes
libbson Binary bson_append_* / bson_iter_* via visitor ops
mpack, msgpack-c Binary Fixed-buffer map pack + tree/object unpack via visitor ops
nanopb, protobuf-c, protobuf-wire Schema Shared in-tree proto3 wire for V2 (fixture_pb_v2.h, same field tags as schemas/v2/protobuf/benchmark_v2.proto). Log names stay separate for historical comparison; not full nanopb stream codegen, protoc-gen-c descriptors, or Google upb.
protobuf Schema Google libprotobuf SerializeToArray / ParseFromArray on generated benchmark_v2.proto messages
tinycbor, cbor-encode (libcbor), qcbor, zcbor Binary/schema Native CBOR map encode via visitor ops; decode via tinycbor map walker (standard CBOR interop) where noted
ubj Binary In-tree UBJSON markers around suite V2 binary payload (bin_*)

Pins: c/third_party/VERSIONS.md.

Caveats

  • Visitor (map codecs): JSON / MessagePack / CBOR / BSON serializers only implement library primitives; field layout lives in v2_codec.c.
  • Protobuf family honesty: the official Google row is protobuf (libprotobuf + sysroot). nanopb / protobuf-c / protobuf-wire currently time the shared fixture_pb_v2 wire codec (domain encode/decode), not each library’s full generated-message stack. Do not read those three as “full library codegen benchmarks.”
  • Payload-wrapped: ubj, flatcc, and avro-c keep kind + binary payload (or builder vector) without full multi-type schema codegen.
  • Symbol prefixing: parson and tinycbor are linked with renamed symbols so they co-exist with jansson and libcbor.
  • A serializer is registered only when its library is linked (CMake configure log serializer: … REAL).

Stream honesty

Stream mode uses an in-memory FILE* (fmemopen) wrapper around full encode/decode buffers — StreamMode=adapted for every stream row. It is not a per-library incremental stream API. See Modes — stream honesty.