HNHacker News
TopNewBestAskShowJobs

jerrinot

343 karma · joined October 8, 2017

submissionscomments
jerrinot··on A 40-line fix eliminated a 400x performance gap
clock_gettime() goes through the vDSO shim, but whether it avoids a syscall depends on the clock ID and (in some cases) the clock source. For thread-specific CPU user time, the vDSO shim cannot resolve the request in user space and must transit into the kernel. In this specific case, there is absolutely a syscall.
jerrinot··on A 40-line fix eliminated a 400x performance gap
You raise a fair point about the percentiles. Those are reported as point estimates without confidence intervals and the implied precision overstates what system clock can deliver.

The mean does get proper statistical treatment (t-distribution confidence interval), but you're right that JMH doesn't compute confidence intervals for percentiles. Reporting p0.00 with three significant figures is ... optimistic.

That said I think the core finding survives this critique. The improvement shows up consistently across ~11 million samples at every percentile from p0.50 through p0.999.

jerrinot··on A 40-line fix eliminated a 400x performance gap
Hi Jonas, thanks for the work on OpenJDK and the post! I swear I hadn't seen your blog :) I finished my draft around Christmas and it’s been in the queue since. Great minds think alike, I guess.

edit: I just read your blog in full and I have to say I like it more than mine. You put a lot more rigor into it. I’m just peeking into things.

edit2: I linked your article from my post.

jerrinot··on A 40-line fix eliminated a 400x performance gap
In a system with green threads, you typically want the CPU time of the fiber or tasklet rather than the carrier thread. In that case, you have to ask the scheduler, not the kernel.
jerrinot··on A 40-line fix eliminated a 400x performance gap
Courtesy of Brendan Gregg and his flamegraph.pl scripts: https://github.com/brendangregg/FlameGraph

Normally, I use the generator included in async-profiler. It produces interactive HTML. But for this post, I used Brendan’s tool specifically to have a single, interactive SVG.

jerrinot··on A 40-line fix eliminated a 400x performance gap
no problem at all, I was confused too when I saw the profile for the first time.
jerrinot··on A 40-line fix eliminated a 400x performance gap
That's a brilliant trick. The setup overhead and permission requirements for perf_event might be heavy for arbitrary threads, but for long-lived threads it looks pretty awesome! Thanks for sharing!
jerrinot··on A 40-line fix eliminated a 400x performance gap
Exactly this.
jerrinot··on A 40-line fix eliminated a 400x performance gap
Only for some clocks (CLOCK_MONOTONIC, etc) and some clock sources. For VIRT/SCHED, the vDSO shim still has to invoke the actual syscall. You can't avoid the kernel transition when you need per-thread accounting.
jerrinot··on A 40-line fix eliminated a 400x performance gap
I was unsure whether to post it or not so I am glad you found it useful!
jerrinot··on A 40-line fix eliminated a 400x performance gap
Fair point. These were run on a standard dev workstation under load, which may account for the noise. I haven't done a deep dive into the outliers yet, but the distribution definitely warrants a more isolated look.
jerrinot··on A 40-line fix eliminated a 400x performance gap
Author here. After my last post about kernel bugs, I spent some time looking at how the JVM reports its own thread activity. It turns out that "What is the CPU time of this thread?" is/was a much more expensive question than it should be.
jerrinot··on A kernel bug froze my machine: Debugging an async-profiler deadlock
I have no practical experience with bpftrace, so it did not occur to me. I'll give it a try and perhaps there's gonna be a 2nd part of this investigation.
jerrinot··on A kernel bug froze my machine: Debugging an async-profiler deadlock
It's much tougher when it's so hard to reproduce. Perhaps the NMI watchdog could help? https://docs.kernel.org/admin-guide/lockup-watchdogs.html
jerrinot··on A kernel bug froze my machine: Debugging an async-profiler deadlock
Wow, someone is actually reading the article in detail, that's a good feeling! In C, the != operator has higher precedence than the || operator. That said, extra parentheses never hurt readability.
jerrinot··on A kernel bug froze my machine: Debugging an async-profiler deadlock
Thanks for the kind words!

Heatmaps are amazing for pattern spotting. I also use them when hunting irregular hiccups or outliers. More people should know about this feature.

jerrinot··on A kernel bug froze my machine: Debugging an async-profiler deadlock
Author here. I've always been kernel-curious despite never having worked on one myself. Consider this either a collection of impractical party tricks or a hands-on way to get a feel for kernel internals.
jerrinot··on IBM to acquire Confluent
Snowflake did not acquire RP after all.
jerrinot··on From Rust to reality: The hidden journey of fetch_max
I expect candidates to suggest similar optimisations, but I felt it was unnecessary for the article itself.
jerrinot··on From Rust to reality: The hidden journey of fetch_max
That’s a neat trick, albeit with limited applicability given the very narrow range. Thanks for sharing!
jerrinot··on From Rust to reality: The hidden journey of fetch_max
That's a very good question. A proper compiler engineer would know, but I will do my best to find something and report back.

Edit: I could not find any pass with a pattern matching to replace CAS loops. The closest thing I could find is this pass: https://github.com/llvm/llvm-project/blob/06fb26c3a4ede66755... I reckon one could write a similar pass to recognize CAS idioms, but its usefulness would be probably rather limited and not worth the effort/risks.

jerrinot··on From Rust to reality: The hidden journey of fetch_max
Hi, author here. My superpower is spending unreasonable amounts of time researching things with no practical purpose. Occasionally I blog about it - as a warning to others.
jerrinot··on Building a faster hash table for high performance SQL joins
A QuestDB engineer here: These are cool benchmarks! The idea to try Robin Hood probing came to me after receiving some feedback on Reddit. I ran initial experiments, and the results were promising, leading to its integration into our codebase. Thank you so much for sharing your repository. Perhaps one day we'll explore bidirectional probing as well!

A snapshot of my happiness after running first experiments with Robin Hood: https://twitter.com/jerrinot/status/1730147245285150743 :)

jerrinot··on Ask HN: Does anyone use InfluxDB? Or should we switch?
What are your requirements? We see some people switching from InfluxDB to QuestDB. Common reasons include SQL support (InfluxDB strategy is a bit confusing here), performance and issues with high-cardinality in InfluxDB.

Full Disclosure: I work for QuestDB and I am obviously biased.

jerrinot··on Leveraging Rust in our Java database
QuestDB engineer here:

It's true that our non-idiomatic Java usage denies us some of the benefits typically associated with Java programming. Automatic memory management and the old "Write Once, Run Anywhere" paradigm are difficult to maintain due to our reliance on native libraries and manual memory management.

I see two classes of reasons for choosing Java:

1. Historical: The QuestDB codebase predates Rust. According to Wikipedia, the initial Rust release was in 2015. The oldest commit in the QuestDB repo is from 2014: https://github.com/questdb/questdb/commit/95b8095427c4e2c781... What were the options back in 2014? C++? Too complicated. C? Too low-level. Pretty much anything else? Either too slow or too exotic.

2. Technical: Java, even without GC or WORA, still offers some advantage. 2a: The tooling is robust, especially when compared to C++. This starts with build systems (don't get me started on CMake!), and extends to aspects like observability. Stacktraces in Java are taken for granted. What's the state of stacktrace walking/printing in C++? I think it boils down to either Boost, C++23, or some other form of black magic. (I might be wrong here tho) 2b: It's a simpler language, especially when compared to C++ or even Rust. This makes it easier to hire people and also attracts external contributors: https://github.com/questdb/questdb/graphs/contributors 2c: The HotSpot JIT still provides us with solid peak performance without having to mess with PGO, etc. 2d: Concurrency is easier with Java's managed memory, eliminating the need for hazard pointers and the like.

jerrinot··on Leveraging Rust in our Java database
QuestDB engineer here: We use jlink to create images for selected platforms. This means not even JRE is a dependency: You unpack a tarball and you are good to go. See: https://questdb.io/docs/get-started/binaries/
jerrinot··on Designing a new concurrent data structure
I could use DirectByteBuffer instances as CHM values. But Java deallocates the backing memory of DirectByteBuffers during object finalization. If there is no on-heap memory pressure then there is no GC and thus no finalization. So it would leak offheap memory. I could also use Unsafe to hack into DirectByteBuffer and call the Cleaner explicitly. Many libraries do that anyway. But then I would still need some kind of reference counting to make sure I won't deallocate a buffer with active readers.
jerrinot··on Designing a new concurrent data structure
I only learned about the left-right schema after finishing my design. I thought I came up with something novel - it turns out it was just my ignorance:)

Still, I think the left-right crate could benefit from one optimization I came up with. This is what the lib says in the docs:

> When WriteHandle::publish is called, the writer, atomically swaps the reader pointer to point to the other T. It then waits for the epochs of all current readers to change, and then replays the operational log to bring the stale copy up to date.

I think the lib could postpone the log replaying until the next publish. Chances are all readers will have the new epoch by than = the writer thread won't have to wait at all.

jerrinot··on Designing a new concurrent data structure
That's actually exactly what I did! I removed this part from the article as I felt it was not relevant for the concurrent protocol design and it was adding mental load for readers not that fluent in Java.
jerrinot··on Designing a new concurrent data structure
That's indeed a very good question! There are 2 sets of reasons:

1. Technical

The contract is given - I'm receiving usernames as CharSequence(String). I could change that, but that would likely require changes in the SQL parser - not simple at all. Alternatively, I could pass the whole CharSequence to Rust - but passing objects over the JNI boundary comes with perf. penalty (when compared to passing primitive) and we avoid that whenever possible. Or I could encode CharSequence content to a temporary offheap buffer and pass just the pointer to Rust. But this brings back some of the questions from the article - like who owns the buffer?

2. Other reasons

I realized this was a possibility only when I was nearly done with the design (this whole endeavor took less than one day) and I felt the urge to finish it. Also: This article wouldn't have been created!

Page 1 of 2Next →