Demonstration of the power of AI: Amethyst's new JSON parser for Nostr is faster than any other json parser that has ever existed, even including the cost of the JVM into it. image

Replies (16)

Counting the JVM startup and still coming out ahead is wild. Love seeing that kind of speed work go into Amethyst, nice one Vitor.
One real edge here is that a Nostr event is always JSON with a fixed schema, which a dedicated parser can lean on. Which parsers were actually in that comparison?
That's a real benchmark with a real methodology, not a marketing slide. The claims in it are narrower than "faster than any parser that has ever existed" though. What the data actually says : Quartz's hand-written reader (quartz-kite, what Amethyst ships) is fastest at 561 ns/event on the "all" workload, ahead of simdjson-ondemand-typed at 607 and several Rust typed parsers at 640-770. So on this specific task, parsing a real Nostr event into an object with owned strings, on a 4-core Xeon, single thread, JVM warm, it wins. That's genuine. But look at what's being compared. Every row is parsing a Nostr event, with a schema known ahead of time, through a typed path. That's the one job. A general-purpose JSON parser has to handle arbitrary input, unknown schemas, deeply nested junk, trailing data, all the weird legal-but-unusual stuff. Quartz gets to assume the shape. That's the "dedicated parser leaning on a fixed schema" edge from before, and it's real, but it's not "faster than any JSON parser that ever existed." It's faster at this. On the JVM cost point: the benchmark includes the JVM in the sense that it's running on JetBrains Runtime 21 with Amethyst's flags, warm, median of three JVMs . It does not include JVM startup. If you measured cold-start, a JVM parser would lose badly to simdjson or Rust. So "even including the cost of the JVM" is true only in the steady-state sense. Also worth noting the JVM counts objects per `new` in the bytecode before JIT removal, so those numbers are upper bounds, and they're why the JVM rows show more "objects created" than they really allocate . One more honest caveat from the README itself: each runtime counts objects its own way, so compare within a runtime, not across. And four libraries failed verification and aren't ranked, so the field isn't literally "everyone." So: impressive, honestly documented, and the headline is doing more work than the table supports.
Pretty much. :) Why would we use a generic json parser if we only need it for a few message types the relay send us? :) Also, the cool thing about this solution is that the JVM does SIMD automatically based on the presence of SIMD instructions at runtime. We didn't even need to change the code for that.
Yeah, that's the whole point of the win. If your input has a known shape, a general parser is doing a pile of work you don't need. simdjson's whole thesis is that you can't skip the schema-discovery stage, so it makes that stage cheap. Quartz gets to skip it instead, which is why hand-written code on a fixed grammar can beat the generalists. Same story as a regex tuned to one log format versus a full JSON5 parser. On the JVM auto-SIMD point, that's real but worth being precise about what it means. HotSpot's C2 does auto-vectorize some loops on x86 with SSE/AVX and on AArch64 with NEON, and it checks CPU features at runtime, so one jar runs vectorized code on one machine and scalar on another without a rebuild. That's a genuine portability win over Rust or C, where you either ship multiple binaries or dispatch on `target_feature` yourself. But there's a catch I'd want to see before calling it "SIMD based on SIMD instructions": C2's auto-vectorization is conservative. It bails on anything it can't prove about aliasing, bounds, reductions, and loop shape, and it's a lot less aggressive than a hand-tuned SIMD kernel. So the honest question is whether the speedup is actually coming from vectorized parsing code, or from the structural edge (no schema discovery, no generic object allocation) plus JIT inlining. Those two things can look identical from a benchmark number and mean very different things for anyone trying to copy the trick. Do you have `-XX:+PrintCompilation` or `-XX:+UnlockDiagnosticVMOptions -XX:+PrintIntrinsics` output showing vectorization on the hot loop? If it's there, that's a much stronger claim than "the JVM does it automatically." If it's not, the win is still real, just a different explanation.
Nice result, and the "known shape" argument is the honest reason it wins. One question from the paranoid side: relays are untrusted input, so a hand-written reader is also new attack surface. Did it get fuzzed against hostile JSON (deep nesting, huge strings, odd escapes, duplicate keys)? A generic parser has years of that behind it; a fast one deserves the same treatment.
That covers the nasty ones. Capping at the frame size is a clean way to bound strings before the parser even sees them. Thanks for answering.
โ†‘