Skip to content

Conversation

@aldexis
Copy link
Contributor

@aldexis aldexis commented Dec 8, 2025

Before this PR

We don't have a great way to measure conjure serde performance.

After this PR

==COMMIT_MSG==
Add JMH benchmarks for conjure map deserialization
==COMMIT_MSG==

This measures

  • The time it takes to deserialize
  • The memory that gets allocated for deserialization
  • The memory that is retained after by the deserialized object

Running this locally (and removing pieces that aren't that useful), I get the below results. Summarized:

  • In the one-item map case, the custom singleton map handling allocates a bit more memory (~1% more), but retains a lot less (~47%)
  • For empty maps, the custom handling allocates a bit less and retains a ton less (just the object wrapper)
  • For all cases, the guava option allocates ~20% less and retains ~10% less memory
Benchmark                                                             (json)        (mapImpl)  Mode  Cnt        Score         Error   Units
ConjureBenchmarks.testAllocatingBenchmark                             NO_MAP           NORMAL  avgt    5      184.651 ±      29.672   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm          NO_MAP           NORMAL  avgt    5      968.004 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm     NO_MAP           NORMAL  avgt    5      112.092 ±       0.068    B/op

ConjureBenchmarks.testAllocatingBenchmark                             NO_MAP        SINGLETON  avgt    5      159.875 ±       7.069   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm          NO_MAP        SINGLETON  avgt    5      936.003 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm     NO_MAP        SINGLETON  avgt    5       16.027 ±       0.101    B/op

ConjureBenchmarks.testAllocatingBenchmark                             NO_MAP  GUAVA_IMMUTABLE  avgt    5      176.506 ±     183.164   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm          NO_MAP  GUAVA_IMMUTABLE  avgt    5      872.003 ±       0.004    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm     NO_MAP  GUAVA_IMMUTABLE  avgt    5       16.032 ±       0.045    B/op

ConjureBenchmarks.testAllocatingBenchmark                              EMPTY           NORMAL  avgt    5      257.319 ±      56.192   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm           EMPTY           NORMAL  avgt    5     1208.005 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm      EMPTY           NORMAL  avgt    5      112.128 ±       0.310    B/op

ConjureBenchmarks.testAllocatingBenchmark                              EMPTY        SINGLETON  avgt    5      220.516 ±       5.144   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm           EMPTY        SINGLETON  avgt    5     1176.004 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm      EMPTY        SINGLETON  avgt    5       16.016 ±       0.106    B/op

ConjureBenchmarks.testAllocatingBenchmark                              EMPTY  GUAVA_IMMUTABLE  avgt    5      211.399 ±       8.693   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm           EMPTY  GUAVA_IMMUTABLE  avgt    5      984.004 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm      EMPTY  GUAVA_IMMUTABLE  avgt    5       16.047 ±       0.079    B/op

ConjureBenchmarks.testAllocatingBenchmark                          SINGLETON           NORMAL  avgt    5      405.794 ±      26.292   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm       SINGLETON           NORMAL  avgt    5     1528.008 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm  SINGLETON           NORMAL  avgt    5      272.118 ±       0.205    B/op

ConjureBenchmarks.testAllocatingBenchmark                          SINGLETON        SINGLETON  avgt    5      357.805 ±      36.661   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm       SINGLETON        SINGLETON  avgt    5     1552.007 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm  SINGLETON        SINGLETON  avgt    5      144.092 ±       0.159    B/op

ConjureBenchmarks.testAllocatingBenchmark                          SINGLETON  GUAVA_IMMUTABLE  avgt    5      320.432 ±      33.864   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm       SINGLETON  GUAVA_IMMUTABLE  avgt    5     1200.006 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm  SINGLETON  GUAVA_IMMUTABLE  avgt    5      160.142 ±       0.289    B/op

ConjureBenchmarks.testAllocatingBenchmark                              THREE           NORMAL  avgt    5      574.595 ±      18.514   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm           THREE           NORMAL  avgt    5     1920.011 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm      THREE           NORMAL  avgt    5      552.286 ±       0.216    B/op

ConjureBenchmarks.testAllocatingBenchmark                              THREE        SINGLETON  avgt    5      580.841 ±      51.899   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm           THREE        SINGLETON  avgt    5     1920.011 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm      THREE        SINGLETON  avgt    5      552.261 ±       0.402    B/op

ConjureBenchmarks.testAllocatingBenchmark                              THREE  GUAVA_IMMUTABLE  avgt    5      506.948 ±      58.892   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm           THREE  GUAVA_IMMUTABLE  avgt    5     1528.010 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm      THREE  GUAVA_IMMUTABLE  avgt    5      480.155 ±       0.354    B/op

ConjureBenchmarks.testAllocatingBenchmark                                SIX           NORMAL  avgt    5      863.696 ±      62.455   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm             SIX           NORMAL  avgt    5     2512.017 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm        SIX           NORMAL  avgt    5      976.401 ±       1.085    B/op

ConjureBenchmarks.testAllocatingBenchmark                                SIX        SINGLETON  avgt    5      889.678 ±     158.380   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm             SIX        SINGLETON  avgt    5     2512.017 ±       0.003    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm        SIX        SINGLETON  avgt    5      976.380 ±       1.032    B/op

ConjureBenchmarks.testAllocatingBenchmark                                SIX  GUAVA_IMMUTABLE  avgt    5      758.321 ±      39.006   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm             SIX  GUAVA_IMMUTABLE  avgt    5     2008.015 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm        SIX  GUAVA_IMMUTABLE  avgt    5      864.340 ±       0.478    B/op

ConjureBenchmarks.testAllocatingBenchmark                                TEN           NORMAL  avgt    5     1278.512 ±      61.835   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm             TEN           NORMAL  avgt    5     3312.025 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm        TEN           NORMAL  avgt    5     1553.018 ±       1.519    B/op

ConjureBenchmarks.testAllocatingBenchmark                                TEN        SINGLETON  avgt    5     1280.454 ±     147.395   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm             TEN        SINGLETON  avgt    5     3312.025 ±       0.001    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm        TEN        SINGLETON  avgt    5     1552.555 ±       0.988    B/op

ConjureBenchmarks.testAllocatingBenchmark                                TEN  GUAVA_IMMUTABLE  avgt    5     1128.815 ±     149.054   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm             TEN  GUAVA_IMMUTABLE  avgt    5     2712.022 ±       0.003    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm        TEN  GUAVA_IMMUTABLE  avgt    5     1392.462 ±       1.501    B/op

ConjureBenchmarks.testAllocatingBenchmark                            HUNDRED           NORMAL  avgt    5    11248.318 ±     640.032   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm         HUNDRED           NORMAL  avgt    5    23720.220 ±       0.011    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm    HUNDRED           NORMAL  avgt    5    14757.744 ±       5.804    B/op

ConjureBenchmarks.testAllocatingBenchmark                            HUNDRED        SINGLETON  avgt    5    11391.878 ±     553.685   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm         HUNDRED        SINGLETON  avgt    5    23720.222 ±       0.012    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm    HUNDRED        SINGLETON  avgt    5    14758.101 ±       6.503    B/op

ConjureBenchmarks.testAllocatingBenchmark                            HUNDRED  GUAVA_IMMUTABLE  avgt    5     9613.995 ±     650.940   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm         HUNDRED  GUAVA_IMMUTABLE  avgt    5    18616.185 ±       0.016    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm    HUNDRED  GUAVA_IMMUTABLE  avgt    5    13003.866 ±       9.984    B/op

ConjureBenchmarks.testAllocatingBenchmark                           THOUSAND           NORMAL  avgt    5   112590.970 ±   13575.673   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm        THOUSAND           NORMAL  avgt    5   210554.177 ±       0.343    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm   THOUSAND           NORMAL  avgt    5   144405.510 ±      84.187    B/op

ConjureBenchmarks.testAllocatingBenchmark                           THOUSAND        SINGLETON  avgt    5   111950.084 ±    7945.716   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm        THOUSAND        SINGLETON  avgt    5   210554.703 ±       4.775    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm   THOUSAND        SINGLETON  avgt    5   144400.054 ±      63.475    B/op

ConjureBenchmarks.testAllocatingBenchmark                           THOUSAND  GUAVA_IMMUTABLE  avgt    5    91829.734 ±    8998.321   ns/op
ConjureBenchmarks.testAllocatingBenchmark:gc.alloc.rate.norm        THOUSAND  GUAVA_IMMUTABLE  avgt    5   163961.788 ±       0.186    B/op
ConjureBenchmarks.testAllocatingBenchmark:mem.retained.total.norm   THOUSAND  GUAVA_IMMUTABLE  avgt    5   128243.556 ±      64.769    B/op

@changelog-app
Copy link

changelog-app bot commented Dec 8, 2025

Generate changelog in changelog/@unreleased

Type (Select exactly one)

  • Feature (Adding new functionality)
  • Improvement (Improving existing functionality)
  • Fix (Fixing an issue with existing functionality)
  • Break (Creating a new major version by breaking public APIs)
  • Deprecation (Removing functionality in a non-breaking way)
  • Migration (Automatically moving data/functionality to a new system)

Description

Add JMH benchmarks for conjure map deserialization

Check the box to generate changelog(s)

  • Generate changelog entry

Comment on lines -51 to +52
runtime = 25
runtime = 21
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why, but I can't seem to run in IntelliJ with runtime = 25

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants