Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why is MessagePack slower than JSON in jackson-databind? #841

Open
john-boxcar opened this issue Sep 25, 2024 · 8 comments
Open

Why is MessagePack slower than JSON in jackson-databind? #841

john-boxcar opened this issue Sep 25, 2024 · 8 comments
Assignees

Comments

@john-boxcar
Copy link

john-boxcar commented Sep 25, 2024

I wrote this crude benchmark to compare the performance of JSON and MessagePack. Consistently, JSON is faster during serialization, faster on deserialization, and MessagePack produces smaller payloads. Based on what I've read, I was expecting MessagePack to be faster during both serialization and deserialization in addition to producing smaller payloads. Are my expecations unrealistic or is there room for improvement here? On my machine, I'm getting this output:

==================================== OUTPUT ====================================
JSON serialized 1,000,000 times in 893ms
JSON size 360
MessagePack serialized 1,000,000 times in 1497ms
MessagePack size 304
JSON deserialized 1,000,000 times in 1496ms
MessagePack deserialized 1,000,000 times in 1777ms

=================================== SUMMARY ====================================
JSON serialization is %40.35 faster than MessagePack serialization
JSON deserialization is %15.81 faster than MessagePack deserialization
MessagePack is %15.56 smaller than JSON

Here are my dependency versions:

+- org.msgpack:jackson-dataformat-msgpack:jar:0.9.8:compile
|  |  +- com.google.http-client:google-http-client-jackson2:jar:1.44.1:compile
+- com.fasterxml.jackson.core:jackson-databind:jar:2.17.1:compile
|  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.17.1:compile
|  \- com.fasterxml.jackson.core:jackson-core:jar:2.17.1:compile
+- com.fasterxml.jackson.datatype:jackson-datatype-guava:jar:2.17.1:compile
+- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.17.1:compile
|  +- org.msgpack:jackson-dataformat-msgpack:jar:0.9.8:compile
|  |  |  +- com.google.http-client:google-http-client-jackson2:jar:1.44.1:compile
|  +- com.fasterxml.jackson.core:jackson-databind:jar:2.17.1:compile
|  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.17.1:compile
|  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.17.1:compile
|  +- com.fasterxml.jackson.datatype:jackson-datatype-guava:jar:2.17.1:compile
|  +- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.17.1:compile

Here is the code:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.msgpack.jackson.dataformat.MessagePackMapper;

import java.io.IOException;
import java.text.NumberFormat;
import java.util.List;
import java.util.Locale;

public class MessagePackMain {
    private static final String SAMPLE_JSON = """
        {
            "glossary": {
                "title": "example glossary",
                "GlossDiv": {
                    "title": "S",
                    "GlossList": {
                        "GlossEntry": {
                            "ID": "SGML",
                            "SortAs": "SGML",
                            "GlossTerm": "Standard Generalized Markup Language",
                            "Acronym": "SGML",
                            "Abbrev": "ISO 8879:1986",
                            "GlossDef": {
                                "para": "A meta-markup language, used to create markup languages such as DocBook.",
                                "GlossSeeAlso": ["GML", "XML"]
                            },
                            "GlossSee": "markup"
                        }
                    }
                }
            }
        }
    """;

    public static void main(String[] args) throws IOException {
        ObjectMapper jsonMapper = new ObjectMapper();
        ObjectMapper messagePackMapper = new MessagePackMapper();
        int iterations = 1_000_000;

        Item item = new ObjectMapper().readValue(SAMPLE_JSON, Item.class);

        System.out.println("==================================== OUTPUT ====================================");

        long startTime = System.currentTimeMillis();
        byte[] jsonOutput = null;
        byte[] messagePackOutput = null;

        for (int i =0; i < iterations; i++) {
            byte[] bytes = jsonMapper.writeValueAsBytes(item);
            if (jsonOutput == null) {
                jsonOutput = bytes;
            }
        }

        long endTime = System.currentTimeMillis();
        long jSerializeElapsedTime = endTime - startTime;
        System.out.println("JSON serialized " + NumberFormat.getNumberInstance(Locale.US).format(iterations) + " times in " + jSerializeElapsedTime + "ms");
        System.out.println("JSON size " + jsonOutput.length);

        startTime = System.currentTimeMillis();

        for (int i =0; i < iterations; i++) {
            byte[] bytes = messagePackMapper.writeValueAsBytes(item);
            if (messagePackOutput == null) {
                messagePackOutput = bytes;
            }
        }

        endTime = System.currentTimeMillis();
        long mSerializeElapsedTime = endTime - startTime;
        System.out.println("MessagePack serialized " + NumberFormat.getNumberInstance(Locale.US).format(iterations) + " times in " + mSerializeElapsedTime + "ms");
        System.out.println("MessagePack size " + messagePackOutput.length);

        String newJson = new String(jsonOutput);
        startTime = System.currentTimeMillis();

        for (int i =0; i < iterations; i++) {
            jsonMapper.readValue(newJson, Item.class);
        }

        endTime = System.currentTimeMillis();
        long jDeserializeElapsedTime = endTime - startTime;
        System.out.println("JSON deserialized " + NumberFormat.getNumberInstance(Locale.US).format(iterations) + " times in " + jDeserializeElapsedTime + "ms");

        startTime = System.currentTimeMillis();

        for (int i =0; i < iterations; i++) {
            messagePackMapper.readValue(messagePackOutput, Item.class);
        }

        endTime = System.currentTimeMillis();
        long mDeserializeElapsedTime = endTime - startTime;
        System.out.println("MessagePack deserialized " + NumberFormat.getNumberInstance(Locale.US).format(iterations) + " times in " + mDeserializeElapsedTime + "ms");

        System.out.println("\n=================================== SUMMARY ====================================");

        if (jSerializeElapsedTime > mSerializeElapsedTime) {
            System.out.printf("MessagePack serialization is %%%.02f faster than JSON serialization\n", ((1.0 - (float) mSerializeElapsedTime / (float) jSerializeElapsedTime))*100.0);
        } else {
            System.out.printf("JSON serialization is %%%.02f faster than MessagePack serialization\n", ((1.0 - (float) jSerializeElapsedTime / (float) mSerializeElapsedTime))*100.0);
        }

        if (jDeserializeElapsedTime > mDeserializeElapsedTime) {
            System.out.printf("MessagePack deserialization is %%%.02f faster than JSON deserialization\n", ((1.0 - (float) mDeserializeElapsedTime / (float) jDeserializeElapsedTime))*100.0);
        } else {
            System.out.printf("JSON deserialization is %%%.02f faster than MessagePack deserialization\n", ((1.0 - (float) jDeserializeElapsedTime / (float) mDeserializeElapsedTime))*100.0);
        }

        if (jsonOutput.length > messagePackOutput.length) {
            System.out.printf("MessagePack is %%%.02f smaller than JSON\n", ((1.0 - (float) messagePackOutput.length / (float)jsonOutput.length))*100.0);
        } else {
            System.out.printf("JSON is %%%.02f smaller than MessagePack\n", ((1.0 - (float) jsonOutput.length / (float)messagePackOutput.length))*100.0);
        }
    }

    private static class Item {
        private Glossary glossary;

        public Glossary getGlossary() {
            return glossary;
        }

        public void setGlossary(Glossary glossary) {
            this.glossary = glossary;
        }
    }
    
    private static class GlossaryDef {
        private String para;
        
        @JsonProperty("GlossSeeAlso")
        private List<String> seeAlso;

        public String getPara() {
            return para;
        }

        public void setPara(String para) {
            this.para = para;
        }

        public List<String> getSeeAlso() {
            return seeAlso;
        }

        public void setSeeAlso(List<String> seeAlso) {
            this.seeAlso = seeAlso;
        }
    }
    
    private static class GlossaryEntry {
        @JsonProperty("ID")
        private String id;
        
        @JsonProperty("SortAs")
        private String sortAs;
        
        @JsonProperty("GlossTerm")
        private String glossTerm;
        
        @JsonProperty("Acronym")
        private String acronym;
        
        @JsonProperty("Abbrev")
        private String abbrev;
        
        @JsonProperty("GlossDef")
        private GlossaryDef glossaryDef;
        
        @JsonProperty("GlossSee")
        private String glossSee;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getSortAs() {
            return sortAs;
        }

        public void setSortAs(String sortAs) {
            this.sortAs = sortAs;
        }

        public String getGlossTerm() {
            return glossTerm;
        }

        public void setGlossTerm(String glossTerm) {
            this.glossTerm = glossTerm;
        }

        public String getAcronym() {
            return acronym;
        }

        public void setAcronym(String acronym) {
            this.acronym = acronym;
        }

        public String getAbbrev() {
            return abbrev;
        }

        public void setAbbrev(String abbrev) {
            this.abbrev = abbrev;
        }

        public GlossaryDef getGlossaryDef() {
            return glossaryDef;
        }

        public void setGlossaryDef(GlossaryDef glossaryDef) {
            this.glossaryDef = glossaryDef;
        }

        public String getGlossSee() {
            return glossSee;
        }

        public void setGlossSee(String glossSee) {
            this.glossSee = glossSee;
        }
    }
    
    private static class GlossaryList {
        @JsonProperty("GlossEntry")
        private GlossaryEntry glossaryEntry;

        public GlossaryEntry getGlossaryEntry() {
            return glossaryEntry;
        }

        public void setGlossaryEntry(GlossaryEntry glossaryEntry) {
            this.glossaryEntry = glossaryEntry;
        }
    }
    
    private static class GlossaryDiv {
        private String title;
        
        @JsonProperty("GlossList")
        private GlossaryList glossaryList;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public GlossaryList getGlossaryList() {
            return glossaryList;
        }

        public void setGlossaryList(GlossaryList glossaryList) {
            this.glossaryList = glossaryList;
        }
    }
    
    private static class Glossary {
        private String title;
        
        @JsonProperty("GlossDiv")
        private GlossaryDiv glossaryDiv;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public GlossaryDiv getGlossaryDiv() {
            return glossaryDiv;
        }

        public void setGlossaryDiv(GlossaryDiv glossaryDiv) {
            this.glossaryDiv = glossaryDiv;
        }
    }
}
@cowtowncoder
Copy link

I have seen similarly less-than-optimal performance with tests on https://github.com/FasterXML/jackson-benchmarks -- I think there is room for improvement for jackson-dataformat-msgpack if anyone has time and interest.

@komamitsu komamitsu self-assigned this Sep 26, 2024
@xerial
Copy link
Member

xerial commented Sep 26, 2024

We haven't focused on the performance of msgpack-jackson. There should be much room for improvement.

@komamitsu
Copy link
Member

komamitsu commented Sep 28, 2024

@john-boxcar Thanks for the heads-up! Based on our benchmark tests, the performance didn't seem too bad https://github.com/msgpack/msgpack-java/actions/runs/11042744800/job/30675681860#step:5:510, so I didn't notice the performance issue that you encountered with your test code. I'll take a look into it when I have time later.

@cowtowncoder Thank for the comment. Let me ask a quick question.

I noticed BeanPropertyWriter.serializeAsField() is consuming about half of the execution time in this profile:
profile-of-msgpack-ser

However, this profile result doesn't show any further stack trace details. I'm wondering if the implementation of jackson-dataformat-msgpack could contribute to the duration of BeanPropertyWriter.serializeAsField(). What do you think?

@cowtowncoder
Copy link

I am not 100% sure but I suspect serializeAsField() timing just encapsulates call it makes to actual serialization. I don't remember it doing anything very complicated on its own. And not something that would be format-specific (locating dependant serializers, for example, would have same overhead regardless of format-specific JsonGenerator subtype.

But for sure that is on stack trace to most serialization activity so that in itself is not surprising. Just does not give much information.

Why timing details are not included; maybe due to JIT inlining? But that seems odd as it's likely some nesting, and should be calling JsonSerializers which in turn then call JsonGenerator.writeXxx() (sub-classes) methods. So inlining all of that seems unlikely.

@komamitsu
Copy link
Member

@cowtowncoder Thanks for the reply! The information that serializeAsField() wouldn't be format-specific is really helpful for me. As for the hidden stack trace, yeah that's strange. I'll look into it a bit more.

@komamitsu
Copy link
Member

I improved the performance of jackson-dataformat-msgpack to some extent in #866 without modifying msgpack-core. Based on the benchmark using https://github.com/FasterXML/jackson-benchmarks, the serialization performance improved by 60% in Java 8 and 4% in Java 21, and the deserialization performance improved by 39% in Java 8 and 21% in Java 21. But the performance of JSON serialization and deserialization is basically still better.

I think one of the performance challenges is that MessagePack's Map and Array need to store the number of child entries in the header. This requires the serializer to know the number of subsequent entries before moving forward since jackson-databind framework doesn't provide the number of child entries in advance.

I don't have any plan for further performance improvement at this moment, as the main purpose of jackson-dataformat-msgpack is to integrate jackson-databind and msgpack-core libraries.

@cowtowncoder
As far as I know, com.fasterxml.jackson.core.JsonGenerator#writeStartObject(java.lang.Object, int) exists, but the method doesn't seem to be called in typical jackson-databind use cases. Let me know if you have a plan to activate it for jackson-databind, so that jackson-dataformat-msgpack would take a more straightforward approach.

FYI: This is the detail of the benchmark:

$ uname -a
Linux onion 6.9.3-76060903-generic #202405300957~1732141768~22.04~f2697e1 SMP PREEMPT_DYNAMIC Wed N x86_64 x86_64 x86_64 GNU/Linux

$ lscpu 
Architecture:             x86_64
  CPU op-mode(s):         32-bit, 64-bit
  Address sizes:          48 bits physical, 48 bits virtual
  Byte Order:             Little Endian
CPU(s):                   16
  On-line CPU(s) list:    0-15
Vendor ID:                AuthenticAMD
  Model name:             AMD Ryzen 9 5900HS with Radeon Graphics
    CPU family:           25
    Model:                80
    Thread(s) per core:   2
    Core(s) per socket:   8
    Socket(s):            1
    Stepping:             0
    CPU max MHz:          4680.0000
    CPU min MHz:          400.0000
    BogoMIPS:             6588.27
    Flags:                fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcn
                          t aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid c
                          qm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local user_shstk clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold av
                          ic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm debug_swap

$ free -h
               total        used        free      shared  buff/cache   available
Mem:            30Gi        12Gi       6.7Gi       333Mi        11Gi        15Gi
Swap:           19Gi          0B        19Gi

# Original (0.9.8)

$ jenv global 1.8 && java -Xmx256m -jar target/perf.jar ".*StdWriteVan.*PojoMedia.*" -wi 3 -w 1 -i 3 -r 1 -f 3 -t 1

Benchmark                                                   Mode  Cnt        Score       Error  Units
c.f.j.p.avro.AvroStdWriteVanilla.writePojoMediaItem        thrpt    9   489294.500 ±  4924.498  ops/s
c.f.j.p.bson.BSONStdWriteVanilla.writePojoMediaItem        thrpt    9   681374.119 ±  8760.644  ops/s
c.f.j.p.cbor.CBORStdWriteVanilla.writePojoMediaItem        thrpt    9  1697897.098 ± 61424.954  ops/s
c.f.j.p.csv.CsvStdWriteVanilla.writePojoMediaItem          thrpt    9  1105202.397 ± 25253.241  ops/s
c.f.j.p.ion.IonStdWriteVanilla.writePojoMediaItem          thrpt    9   533993.139 ± 19634.359  ops/s
c.f.j.p.json.JacksonJrStdWriteVanilla.writePojoMediaItem   thrpt    9  1501644.460 ± 57205.124  ops/s
c.f.j.p.json.JsonStdWriteVanilla.writePojoMediaItem        thrpt    9  1389623.325 ± 55563.787  ops/s
c.f.j.p.msgpack.MsgpackStdWriteVanilla.writePojoMediaItem  thrpt    9   407974.511 ±  6631.502  ops/s
c.f.j.p.props.PropsStdWriteVanilla.writePojoMediaItem      thrpt    9   404364.503 ±  8700.286  ops/s
c.f.j.p.protob.ProtobStdWriteVanilla.writePojoMediaItem    thrpt    9  1792950.687 ± 35790.732  ops/s
c.f.j.p.smile.SmileStdWriteVanilla.writePojoMediaItem      thrpt    9  1557336.040 ± 25948.417  ops/s
c.f.j.p.toml.TOMLStdWriteVanilla.writePojoMediaItem        thrpt    9   696477.417 ± 13197.279  ops/s
c.f.j.p.xml.XMLStdWriteVanilla.writePojoMediaItem          thrpt    9   628871.650 ± 11299.180  ops/s
c.f.j.p.yaml.YAMLStdWriteVanilla.writePojoMediaItem        thrpt    9   121216.044 ±  1968.682  ops/s

$ jenv global 1.8 && java -Xmx256m -jar target/perf.jar ".*StdReadVan.*PojoMedia.*" -wi 3 -w 1 -i 3 -r 1 -f 3 -t 1

Benchmark                                                 Mode  Cnt       Score       Error  Units
c.f.j.p.avro.AvroStdReadVanilla.readPojoMediaItem        thrpt    9  942882.086 ±  7936.068  ops/s
c.f.j.p.bson.BSONStdReadVanilla.readPojoMediaItem        thrpt    9  325765.930 ±  9430.468  ops/s
c.f.j.p.cbor.CBORStdReadVanilla.readPojoMediaItem        thrpt    9  763711.004 ± 37159.610  ops/s
c.f.j.p.csv.CsvStdReadVanilla.readPojoMediaItem          thrpt    9  548974.931 ±  8903.669  ops/s
c.f.j.p.ion.IonStdReadVanilla.readPojoMediaItem          thrpt    9  175297.535 ±  4229.962  ops/s
c.f.j.p.json.JacksonJrStdReadVanilla.readPojoMediaItem   thrpt    9  763989.637 ± 16085.107  ops/s
c.f.j.p.json.JsonStdReadVanilla.readPojoMediaItem        thrpt    9  743932.224 ±  8340.437  ops/s
c.f.j.p.msgpack.MsgpackStdReadVanilla.readPojoMediaItem  thrpt    9  424294.124 ±  5798.284  ops/s
c.f.j.p.props.PropsStdReadVanilla.readPojoMediaItem      thrpt    9  141666.034 ±  3170.434  ops/s
c.f.j.p.protob.ProtobStdReadVanilla.readPojoMediaItem    thrpt    9  895467.969 ± 31109.949  ops/s
c.f.j.p.smile.SmileStdReadVanilla.readPojoMediaItem      thrpt    9  962004.705 ±  4778.528  ops/s
c.f.j.p.toml.TOMLStdReadVanilla.readPojoMediaItem        thrpt    9  162379.068 ±  1333.447  ops/s
c.f.j.p.xml.XMLStdReadVanilla.readPojoMediaItem          thrpt    9  341984.361 ± 22479.115  ops/s
c.f.j.p.yaml.YAMLStdReadVanilla.readPojoMediaItem        thrpt    9   53542.854 ±   298.744  ops/s

$ jenv global 21.0 && java -Xmx256m -jar target/perf.jar ".*StdWriteVan.*PojoMedia.*" -wi 3 -w 1 -i 3 -r 1 -f 3 -t 1

Benchmark                                                   Mode  Cnt        Score       Error  Units
c.f.j.p.avro.AvroStdWriteVanilla.writePojoMediaItem        thrpt    9   604146.609 ± 12046.498  ops/s
c.f.j.p.bson.BSONStdWriteVanilla.writePojoMediaItem        thrpt    9   511417.334 ±  5997.995  ops/s
c.f.j.p.cbor.CBORStdWriteVanilla.writePojoMediaItem        thrpt    9  1394309.459 ± 31171.624  ops/s
c.f.j.p.csv.CsvStdWriteVanilla.writePojoMediaItem          thrpt    9  1023008.232 ± 22729.656  ops/s
c.f.j.p.ion.IonStdWriteVanilla.writePojoMediaItem          thrpt    9   441537.835 ± 34920.793  ops/s
c.f.j.p.json.JacksonJrStdWriteVanilla.writePojoMediaItem   thrpt    9  1333207.671 ± 35654.686  ops/s
c.f.j.p.json.JsonStdWriteVanilla.writePojoMediaItem        thrpt    9  1166001.914 ± 40842.917  ops/s
c.f.j.p.msgpack.MsgpackStdWriteVanilla.writePojoMediaItem  thrpt    9   782189.492 ± 11111.575  ops/s
c.f.j.p.props.PropsStdWriteVanilla.writePojoMediaItem      thrpt    9   625417.873 ± 13297.877  ops/s
c.f.j.p.protob.ProtobStdWriteVanilla.writePojoMediaItem    thrpt    9  1263701.715 ± 17541.267  ops/s
c.f.j.p.smile.SmileStdWriteVanilla.writePojoMediaItem      thrpt    9  1287249.122 ± 20395.253  ops/s
c.f.j.p.toml.TOMLStdWriteVanilla.writePojoMediaItem        thrpt    9   621114.456 ±  9801.864  ops/s
c.f.j.p.xml.XMLStdWriteVanilla.writePojoMediaItem          thrpt    9   535547.324 ± 20899.912  ops/s
c.f.j.p.yaml.YAMLStdWriteVanilla.writePojoMediaItem        thrpt    9   100167.793 ±  5390.545  ops/s

$ jenv global 21.0 && java -Xmx256m -jar target/perf.jar ".*StdReadVan.*PojoMedia.*" -wi 3 -w 1 -i 3 -r 1 -f 3 -t 1

Benchmark                                                 Mode  Cnt       Score       Error  Units
c.f.j.p.avro.AvroStdReadVanilla.readPojoMediaItem        thrpt    9  872757.955 ± 11472.128  ops/s
c.f.j.p.bson.BSONStdReadVanilla.readPojoMediaItem        thrpt    9  355271.843 ±  7764.761  ops/s
c.f.j.p.cbor.CBORStdReadVanilla.readPojoMediaItem        thrpt    9  728326.233 ± 27703.471  ops/s
c.f.j.p.csv.CsvStdReadVanilla.readPojoMediaItem          thrpt    9  515646.544 ± 23481.202  ops/s
c.f.j.p.ion.IonStdReadVanilla.readPojoMediaItem          thrpt    9  178573.660 ±  4258.389  ops/s
c.f.j.p.json.JacksonJrStdReadVanilla.readPojoMediaItem   thrpt    9  711433.436 ±  4086.300  ops/s
c.f.j.p.json.JsonStdReadVanilla.readPojoMediaItem        thrpt    9  669091.267 ± 34308.260  ops/s
c.f.j.p.msgpack.MsgpackStdReadVanilla.readPojoMediaItem  thrpt    9  512168.824 ± 10254.230  ops/s
c.f.j.p.props.PropsStdReadVanilla.readPojoMediaItem      thrpt    9  134767.718 ±  3292.295  ops/s
c.f.j.p.protob.ProtobStdReadVanilla.readPojoMediaItem    thrpt    9  845397.669 ± 18762.979  ops/s
c.f.j.p.smile.SmileStdReadVanilla.readPojoMediaItem      thrpt    9  927000.840 ± 32923.455  ops/s
c.f.j.p.toml.TOMLStdReadVanilla.readPojoMediaItem        thrpt    9  185067.273 ±  3969.967  ops/s
c.f.j.p.xml.XMLStdReadVanilla.readPojoMediaItem          thrpt    9  321863.934 ±  9639.973  ops/s
c.f.j.p.yaml.YAMLStdReadVanilla.readPojoMediaItem        thrpt    9   48877.170 ±   221.066  ops/s

# Optimized

$ jenv global 1.8 && java -Xmx256m -jar target/perf.jar ".*StdWriteVan.*PojoMedia.*" -wi 3 -w 1 -i 3 -r 1 -f 3 -t 1

Benchmark                                                   Mode  Cnt        Score       Error  Units
c.f.j.p.avro.AvroStdWriteVanilla.writePojoMediaItem        thrpt    9   484189.173 ± 18290.273  ops/s
c.f.j.p.bson.BSONStdWriteVanilla.writePojoMediaItem        thrpt    9   671714.185 ± 12962.207  ops/s
c.f.j.p.cbor.CBORStdWriteVanilla.writePojoMediaItem        thrpt    9  1640309.520 ± 43878.117  ops/s
c.f.j.p.csv.CsvStdWriteVanilla.writePojoMediaItem          thrpt    9  1114543.921 ± 18094.287  ops/s
c.f.j.p.ion.IonStdWriteVanilla.writePojoMediaItem          thrpt    9   541683.734 ± 30579.006  ops/s
c.f.j.p.json.JacksonJrStdWriteVanilla.writePojoMediaItem   thrpt    9  1525445.080 ± 52410.043  ops/s
c.f.j.p.json.JsonStdWriteVanilla.writePojoMediaItem        thrpt    9  1379044.699 ± 28883.095  ops/s
c.f.j.p.msgpack.MsgpackStdWriteVanilla.writePojoMediaItem  thrpt    9   654176.058 ±  2607.457  ops/s
c.f.j.p.props.PropsStdWriteVanilla.writePojoMediaItem      thrpt    9   402786.317 ±  3751.668  ops/s
c.f.j.p.protob.ProtobStdWriteVanilla.writePojoMediaItem    thrpt    9  1827131.160 ± 85225.419  ops/s
c.f.j.p.smile.SmileStdWriteVanilla.writePojoMediaItem      thrpt    9  1561782.089 ± 37587.722  ops/s
c.f.j.p.toml.TOMLStdWriteVanilla.writePojoMediaItem        thrpt    9   701562.140 ±  4652.099  ops/s
c.f.j.p.xml.XMLStdWriteVanilla.writePojoMediaItem          thrpt    9   626551.249 ±  8724.151  ops/s
c.f.j.p.yaml.YAMLStdWriteVanilla.writePojoMediaItem        thrpt    9   121450.182 ±  1957.381  ops/s

$ jenv global 1.8 && java -Xmx256m -jar target/perf.jar ".*StdReadVan.*PojoMedia.*" -wi 3 -w 1 -i 3 -r 1 -f 3 -t 1

Benchmark                                                 Mode  Cnt       Score       Error  Units
c.f.j.p.avro.AvroStdReadVanilla.readPojoMediaItem        thrpt    9  938416.088 ± 18279.461  ops/s
c.f.j.p.bson.BSONStdReadVanilla.readPojoMediaItem        thrpt    9  311643.313 ± 36063.643  ops/s
c.f.j.p.cbor.CBORStdReadVanilla.readPojoMediaItem        thrpt    9  774108.518 ± 35444.075  ops/s
c.f.j.p.csv.CsvStdReadVanilla.readPojoMediaItem          thrpt    9  546327.588 ± 18188.808  ops/s
c.f.j.p.ion.IonStdReadVanilla.readPojoMediaItem          thrpt    9  179408.792 ±  7192.140  ops/s
c.f.j.p.json.JacksonJrStdReadVanilla.readPojoMediaItem   thrpt    9  777088.289 ± 14709.751  ops/s
c.f.j.p.json.JsonStdReadVanilla.readPojoMediaItem        thrpt    9  754571.907 ± 19127.808  ops/s
c.f.j.p.msgpack.MsgpackStdReadVanilla.readPojoMediaItem  thrpt    9  588950.979 ±  5973.814  ops/s
c.f.j.p.props.PropsStdReadVanilla.readPojoMediaItem      thrpt    9  140065.414 ±  1545.586  ops/s
c.f.j.p.protob.ProtobStdReadVanilla.readPojoMediaItem    thrpt    9  925366.247 ± 22674.691  ops/s
c.f.j.p.smile.SmileStdReadVanilla.readPojoMediaItem      thrpt    9  926623.904 ± 97314.726  ops/s
c.f.j.p.toml.TOMLStdReadVanilla.readPojoMediaItem        thrpt    9  158045.483 ± 10601.039  ops/s
c.f.j.p.xml.XMLStdReadVanilla.readPojoMediaItem          thrpt    9  356776.693 ± 10042.345  ops/s
c.f.j.p.yaml.YAMLStdReadVanilla.readPojoMediaItem        thrpt    9   53455.181 ±   495.742  ops/s

$ jenv global 21.0 && java -Xmx256m -jar target/perf.jar ".*StdWriteVan.*PojoMedia.*" -wi 3 -w 1 -i 3 -r 1 -f 3 -t 1

Benchmark                                                   Mode  Cnt        Score       Error  Units
c.f.j.p.avro.AvroStdWriteVanilla.writePojoMediaItem        thrpt    9   613614.464 ± 10309.633  ops/s
c.f.j.p.bson.BSONStdWriteVanilla.writePojoMediaItem        thrpt    9   517514.119 ± 31899.281  ops/s
c.f.j.p.cbor.CBORStdWriteVanilla.writePojoMediaItem        thrpt    9  1446736.718 ± 16120.590  ops/s
c.f.j.p.csv.CsvStdWriteVanilla.writePojoMediaItem          thrpt    9  1011013.776 ± 46175.560  ops/s
c.f.j.p.ion.IonStdWriteVanilla.writePojoMediaItem          thrpt    9   451937.382 ± 20203.925  ops/s
c.f.j.p.json.JacksonJrStdWriteVanilla.writePojoMediaItem   thrpt    9  1311307.741 ± 24259.011  ops/s
c.f.j.p.json.JsonStdWriteVanilla.writePojoMediaItem        thrpt    9  1180875.496 ± 58935.735  ops/s
c.f.j.p.msgpack.MsgpackStdWriteVanilla.writePojoMediaItem  thrpt    9   819188.508 ± 17924.771  ops/s
c.f.j.p.props.PropsStdWriteVanilla.writePojoMediaItem      thrpt    9   635256.708 ±  8112.452  ops/s
c.f.j.p.protob.ProtobStdWriteVanilla.writePojoMediaItem    thrpt    9  1268110.260 ± 58472.673  ops/s
c.f.j.p.smile.SmileStdWriteVanilla.writePojoMediaItem      thrpt    9  1276079.005 ± 24722.019  ops/s
c.f.j.p.toml.TOMLStdWriteVanilla.writePojoMediaItem        thrpt    9   634812.045 ± 42003.031  ops/s
c.f.j.p.xml.XMLStdWriteVanilla.writePojoMediaItem          thrpt    9   538341.481 ± 17356.806  ops/s
c.f.j.p.yaml.YAMLStdWriteVanilla.writePojoMediaItem        thrpt    9   101119.267 ±  4703.801  ops/s

$ jenv global 21.0 && java -Xmx256m -jar target/perf.jar ".*StdReadVan.*PojoMedia.*" -wi 3 -w 1 -i 3 -r 1 -f 3 -t 1

Benchmark                                                 Mode  Cnt       Score       Error  Units
c.f.j.p.avro.AvroStdReadVanilla.readPojoMediaItem        thrpt    9  883358.344 ± 38473.482  ops/s
c.f.j.p.bson.BSONStdReadVanilla.readPojoMediaItem        thrpt    9  356741.129 ±  1058.394  ops/s
c.f.j.p.cbor.CBORStdReadVanilla.readPojoMediaItem        thrpt    9  707527.031 ± 30697.108  ops/s
c.f.j.p.csv.CsvStdReadVanilla.readPojoMediaItem          thrpt    9  522711.729 ±  8845.077  ops/s
c.f.j.p.ion.IonStdReadVanilla.readPojoMediaItem          thrpt    9  175897.184 ±  4307.639  ops/s
c.f.j.p.json.JacksonJrStdReadVanilla.readPojoMediaItem   thrpt    9  706520.434 ± 10029.679  ops/s
c.f.j.p.json.JsonStdReadVanilla.readPojoMediaItem        thrpt    9  678177.349 ± 12237.221  ops/s
c.f.j.p.msgpack.MsgpackStdReadVanilla.readPojoMediaItem  thrpt    9  619370.674 ±  7608.224  ops/s
c.f.j.p.props.PropsStdReadVanilla.readPojoMediaItem      thrpt    9  134554.208 ±  1254.830  ops/s
c.f.j.p.protob.ProtobStdReadVanilla.readPojoMediaItem    thrpt    9  851437.188 ± 64361.233  ops/s
c.f.j.p.smile.SmileStdReadVanilla.readPojoMediaItem      thrpt    9  938552.295 ± 31819.350  ops/s
c.f.j.p.toml.TOMLStdReadVanilla.readPojoMediaItem        thrpt    9  185628.777 ±  1099.247  ops/s
c.f.j.p.xml.XMLStdReadVanilla.readPojoMediaItem          thrpt    9  328655.048 ± 10535.818  ops/s
c.f.j.p.yaml.YAMLStdReadVanilla.readPojoMediaItem        thrpt    9   48823.265 ±   924.303  ops/s

@cowtowncoder
Copy link

@komamitsu Nicely done!

On writeStartObject(Object. int)... It's tricky unfortunately. I know its implementation would help with many binary formats aside from MsgPack (Avro and Protobuf in particular, and in some ways CBOR too). So there is definitely desire to be able to call that variant.

But while in some cases entry count is known (simplest serializations), problem are dynamic filters (Views, @JsonFilter) which basically allow configured handlers to be called as part of serialization. Since these are evaluated incrementally (entry by entry) they won't be known at point where START_OBJECT is to be emitted. And at least some use delegation (that is, either block writes or pass, but won't change intermediate data structures).

It may be possible to use the entry-count-specifying variant for some serialization cases, where it can be guaranteed entry count is fully known. I hope this can be done in future.
But I suspect it is not possible/practical to try to make every writeStartObject pass entry count. So backends need to support both cases.

@komamitsu
Copy link
Member

@cowtowncoder Thanks for the details! I didn't think about the dynamic filter, but yeah, it seems to matter...

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

No branches or pull requests

4 participants