u/AndrewHaley13
-
152points
AndrewHaley13
AndrewHaley13
That's not how it works. HotSpot probes the CPU it's running on, in order to discover what it can do. The compiler options used to build HotSpot make no difference to this.
AndrewHaley13
Re ScopedValue: thank you. It was my pleasure, and I'm glad you like it.
AndrewHaley13
Russian bot farm trying to make us unhappy?
AndrewHaley13
Pretty much. They need to sell many low CO2 vehicles in order to compensate for the high emission vehicles, which will be sold in relatively small numbers, at least in Europe. The success of an electric Boxster would be a very good thing all around.
AndrewHaley13
I thought you were exaggerating, but then I looked at the list. Eek!
AndrewHaley13
Porsche is required in Europe by Regulation EU 2019/631 to reduce average CO2 emissions. I'm sure Porsche would love to sell many more GT3 variants at 300k Euro each, but they'll have to make up for that somehow.
AndrewHaley13
You got me interested. I found the difference in performance genuinely surprising, despite working on this stuff for more than a decade, so I had to investigate.
P.S. u/pron98 is one of us too. Sh! Don't tell anyone. :-)
AndrewHaley13
I'm one of the OpenJDK JIT developers. So you got me curious, and I ran the benchmark through JMH perfasm to look at the code generation.
A few comments:
The benchmark measures latency rather than throughput, and runs at less than one instruction per clock, on a machine that can hit eight instructions per clock. This is because almost every instruction depends on the previous one, so no instruction can start until a previous one finishes.
I changed the loop counter from a byte to an int, because HotSpot doesn't do loop optimizations with a byte index.
Here's the generated code. Registers whose name begins with x are unsigned 64 bit, and those whose name begins with w aare signed 32 bit. The 32-bit version of the benchmark is slightly slower because it's a bit more fiddly to do the multiplication and division.
x12 += 1; *ladd
x13 = x12 >> 0x20;
x12 = x13 ^ x12; *lxor
x15 = (sint64_t)x12 >> 0x3f;
x13 = ((sint128_t)x12 * x23) >> 64; *idiv
x1 = x12 + (x15 >> 52);
x1 &= 0xfffffffffffff000;
x12 = x12 + (sint64_t)x13 >> 1;
x13 = x1 >> x15;
x12 -= x13;
x12 = x12 * x22 + x2;
w11 = w10 + 1; *iadd
w13 = w11 ^ (w11 >> 16); *ixor
x10 = (sint64_t)w13;
x10 = x10 * x19;
w14 = (sint32_t)w13 >> 0x1f; *idiv
x10 = (sint64_t)x10 >> 0x20;
w11 = w13 + (w14 >> 22)
w10 += w13;
w11 &= 0xfffffc00;
w12 = w13 + (sint32_t)w10 >> 2;
w10 = w11 + w14;
w11 = w12 - w10;
w10 = (w11 * w21) + w3;
AndrewHaley13
It's a bytecode interpreter written in C++. Think slow.
AndrewHaley13
It depends what you are doing. If you repeatedly read a scoped value, it'll be faster than ThreadLocal because scoped values are cached. In the extreme, the scoped value will be kept in a register. However, binding (i.e. setting) a scoped value can be a little more expensive than setting a ThreadLocal, and the first time a scoped value is accessed we have to search for a binding.
AndrewHaley13
It's because until JDK 9 every OpenJDK release had its own project for updates. That became too cumbersome with increased frequency of releases.
AndrewHaley13
So I'm curious. Did you experiment with the Aarch64 Top Byte Ignore feature? It was specifically intended for stuff like this.
AndrewHaley13
Please reply to the discussion at https://mail.openjdk.org/pipermail/jdk-dev/2025-April/009970.html
AndrewHaley13
> Let's say that I used the following code to synchronize file write access, where someFile is an instance of java.nio.file.Path
But the API says "A `Path` is An object that may be used to locate a file in a file system." There may be many paths to the same File. You may synchronize instead on the file writer. You'd have to check that there was only one writer for any given file, sure, but it would be more reliable than synchronizing on the file's `Path`.
> And barring that, what would be the equivalent class from java.util.concurrent.locks that we should use instead
`ReentrantLock` is the closest thing to built-n sychronized.
AndrewHaley13
Seems fine. I use a Kaiser backlight.
AndrewHaley13
Indeed so, yes. And new lenses too. I guess someone might try to pack 100 mpix into an X2D-size sensor, but it'd be a compromise. Phase 1 do use the bigger sensor, but the lenses are really expensive. I think we're good with the X2D for now.
AndrewHaley13
Maybe we should not be able to bind null to a ScopedValue. It's a fairly marginal thing to do, and off the top of my head I can't immediately see a good use for it. That is a conversation that we can have on the list.
AndrewHaley13
We can't make get() return null for an unbound scoped value because null is part of the value set. Obviously here is a difference between a scoped value being unbound and a scoped value being bound to null. For the same reason I'm not so keen on orNull().
I get that from a nullability analysis point of view, orElse() is a pain. But you say that it's useless. How so? Surely it's only useless to people who use nullability analysis. Or is it your contention that everybody should be using nullability analysis, and therefore orElse() is useless?
I was rather hoping that, with the latest preview, we'd be in with a chance to make this final, but maybeorElseGet()would be a better alternative than orElse(). The JEP is a preview, so we can talk about it elsewhere, on the list. I'd be interested to hear Alan Bateman's opinion.
AndrewHaley13
Can you explain a little more about what you'd do instead of orElse?
AndrewHaley13
https://www.35mmc.com/24/01/2020/instant-magny-35-review/ suggests adding at least 3 stops for long exposures
AndrewHaley13
I use a 60mm Micro Nikkor on a Novoflex adapter, which gives good results and full corner-to-corner coverage. No, I wasn't expecting that either, It's good for copying medium-format transparencies, as well as other less close up duties.
That's completely different. X86-32, which we no longer support, is a different ISA, and it would require a process switch to do the transition.