HN user

ridiculous_fish

6,842 karma
Posts8
Comments1,267
View on HN

Oklo | Remote (US) or Santa Clara or Brooklyn | Full time | https://oklo.com

Join us in pioneering the next generation of nuclear reactors! You'll leverage your software skills alongside nuclear engineers to model, simulate, design, and deploy advanced fission power technology. You will work at the forefront of the nuclear industry, developing novel techniques to reach new levels of safety, efficiency, and resiliency. Come be a part of powering the future with advanced fission power plants to provide clean, reliable, affordable energy.

We are hiring for:

- Software Engineer: https://job-boards.greenhouse.io/oklo/jobs/4018702004

- Senior Software Engineer: https://job-boards.greenhouse.io/oklo/jobs/5739483004

See more opportunities here: https://job-boards.greenhouse.io/oklo

Please mention Hacker News in your cover letter!

I bought one of these as soon as I heard about it ($74 from eBay) and tested it against my USB-4 AQC113 mainstays ($87, IO CREST brand on Amazon), from my MBP.

The new RTL-based adapter is physically smaller, runs way cooler, but only gets ~6 Gbps from my Mac to my Linux box, with a lot of jitter (iperf3).

The AQC adapter is all metal, gets uncomfortably hot, and sustains 9.3 Gbps, no problem. It's about the same size as the middle adapter in the photo.

The USB-4 AQC adapters are only ~$13 more, and yet are significantly faster with lower jitter. I'm staying with those.

Hope that helps someone!

This paper missed the state of the art!!!

This concerns unsigned division by a 32 bit constant divisor. Compilers routinely optimize this to a high-multiply by a "magic number" but this number may be up to 33 bits (worst-case, divisor dependent, 7 is a problem child). So you may need a 32x33-bit high multiply.

What compilers do today is some bit tricks to perform a 32x33 bit high multiply through a 32x32 multiply and then handling the last bit specially, through additions and bitshifts. That's the "GM Method" in the paper; the juice to be squeezed out is the extra stuff to handle the 33rd bit.

What the paper observes is that 32x33 high multiply can be performed via a 64x64 high multiply and then the extra stuff goes away. Well yes, of course.

But amazingly in ALL of these worst case situations you can compute a different magic number, and perform a (saturating) increment of the dividend at runtime, and ONLY need a 32 bit high multiply.

That is, these are the two algorithms for unsigned division by constants where the magic number overflows:

- This paper: Promote to twice the bit width, followed by high multiply (32x64 => 64) and then bitshift

- SOTA: Saturating increment of the dividend, then high multiply (32x32 => 32) and then bitshift

Probably the paper's approach is a little better on wide multipliers, but they missed this well-known technique published 15 years ago (and before that, I merely rediscovered it):

https://ridiculousfish.com/blog/posts/labor-of-division-epis...

Thank you for flagging this, that definitely shouldn't be happening. Possibly we have an over-zealous spam filter. If you and your friend are open to it, please email me at pca@[company].com and I will personally look into it.

Oklo | Remote (US) or Santa Clara or Brooklyn | Full time | https://oklo.com

Join us in pioneering the next generation of nuclear reactors! You'll leverage your software skills alongside nuclear engineers to model, simulate, design, and deploy advanced fission power technology. You will work at the forefront of the nuclear industry, developing novel techniques to reach new levels of safety, efficiency, and resiliency. Come be a part of powering the future with advanced fission power plants to provide clean, reliable, affordable energy.

We are hiring for:

- Software Engineer: https://job-boards.greenhouse.io/oklo/jobs/4018702004

- Senior Software Engineer: https://job-boards.greenhouse.io/oklo/jobs/5739483004

- Software Engineer (Infrastructure): https://job-boards.greenhouse.io/oklo/jobs/5784826004

- Software Quality Assurance Lead: https://job-boards.greenhouse.io/oklo/jobs/5480416004

See more opportunities here: https://job-boards.greenhouse.io/oklo

Please mention Hacker News in your cover letter!

Extraordinary project. I had several questions which I believe I have answered for myself (pizlonator please correct if wrong):

1. How do we prevent loading a bogus lower through misaligned store or load?

Answer: Misaligned pointer load/stores are trapped; this is simply not allowed.

2. How are pointer stores through a pointer implemented (e.g. `*(char **)p = s`) - does the runtime have to check if *p is "flight" or "heap" to know where to store the lower?

Answer: no. Flight (i.e. local) pointers whose address is taken are not literally implemented as two adjacent words; rather the call frame is allocated with the same object layout as a heap object. The flight pointer is its "intval" and its paired "lower" is at the same offset in the "aux" allocation (presumably also allocated as part of the frame?).

3. How are use-after-return errors prevented? Say I store a local pointer in a global variable and then return. Later, I call a new function which overwrites the original frame - can't I get a bogus `lower` this way?

Answer: no. Call frames are allocated by the GC, not the usual C stack. The global reference will keep the call frame alive.

That leads to the following program, which definitely should not work, and yet does. ~Amazing~ Unbelievable:

    #include <stdio.h>
    
    char *bottles[100];
    
    __attribute__((noinline))
    void beer(int count) {
        char buf[64];
        sprintf(buf, "%d bottles of beer on the wall", count);
        bottles[count] = buf;
    }
    
    int main(void) {
        for (int i=0; i < 100; i++) beer(i);
        for (int i=99; i >= 0; i--) puts(bottles[i]);
    }
Float Exposed 10 months ago

My favorite FP Fun Fact is that float comparisons can (almost) use integer comparisons. To determine if a > b, reinterpret a and b as signed ints and just compare those like any old ints. It (almost) works!

The implication is that the next biggest float is (almost) always what you get when you reinterpret its bits as an integer, and add one. For example, start with the zero float: all bits zero. Add one using integer arithmetic. In int-speak it's just one; in float-speak it's a tiny-mantissa denormal. But that's the next float; and `nextafter` is implemented using integer arithmetic.

Learning that floats are ordered according to integer comparisons makes it feel way more natural. But of course there's the usual asterisks: this fails with NaNs, infinities, and negative zero. We get a few nice things, but only a few.

The Core of Rust 11 months ago

Affine types, variance, higher-rank trait bounds, phantom data, MaybeUninit, and the whole macro and proc-macro systems are some examples of concepts that I found to be challenging when learning Rust.

Dyn-safety is another but I had encountered that previously in Swift.

Oklo | Remote (US) or Santa Clara or Brooklyn | Full time | https://oklo.com

Join us in pioneering the next generation of nuclear reactors! You'll leverage your software skills alongside nuclear engineers to model, simulate, design, and deploy advanced fission power technology. You will work at the forefront of the nuclear industry, developing novel techniques to reach new levels of safety, efficiency, and resiliency. Come be a part of powering the future with advanced fission power plants to provide clean, reliable, affordable energy.

We are hiring for:

- Software Engineer: https://job-boards.greenhouse.io/oklo/jobs/4018702004

- Software Quality Assurance Engineer: https://job-boards.greenhouse.io/oklo/jobs/5480416004

See more opportunities here: https://job-boards.greenhouse.io/oklo

Please mention Hacker News in your cover letter!

At $WORK we use SQLite in WASM via the official ES module, running read-only in browser.

The performance is very poor, perhaps 100x worse than native. It's bad enough that we only use SQLite for trivial queries. All joins, sorting, etc. are done in JavaScript.

Profiling shows the slowdown is in the JS <-> WASM interop. This is exacerbated by the one-row-at-a-time "cursor" API in SQLite, which means at least one FFI round-trip for each row.

Don't confuse "presence of dynamic types" with "absence of static types."

Think about the web, which is full of dynamicism: install this polyfill if needed, call this function if it exists, all sorts of progressive enhancement. Dynamic types are what make those possible.

No, it's not so.

If the allocation is backed by the kernel, then it will be zero-filled for security reasons. If it's backed by user-space malloc then who knows; but there's never a scenario where a mallocated page is quietly replaced by a zero-filled page behind the scenes.

SIMD is true, but the original guess is correct, and that effect is bigger!

using_map is faster because it's not allocating: it's re-using the input array. That is, it is operating on the input `v` value in place, equivalent to this:

    pub fn using_map(mut v: Vec<i32>) -> Vec<i32> {
        v.iter_mut().for_each(|c| *c += 1);
        v
    }
This is a particularly fancy optimization that Rust can perform.

"Numbers go into the numbers vector" is unusual - typically JS engines use either NaN-boxing or inline small integers (e.g. v8 SMI). I suppose this means that a simple `this.count += 1` will always allocate.

Have you considered using NaN-boxing? Also, are the type-specific vectors compacted by the GC, or do they maintain a free list?

Any thoughts on the best way to express global locks in Rust?

A classic example is a set of bank accounts, atomically transacting with each other. Fine-grained per-account locking is possible, but risks deadlock due to lock ordering inversion. A simple solution is to replace per-account locks with a singleton global lock, covering all accounts. Any transaction must first acquire this lock, and now deadlock is impossible.

But this is an awkward fit for Rust, whose locks want to own the data they protect. What's the best way to express a global lock, enforcing that certain data may only be accessed while the global lock is held?

It changes very little because there’s nothing to receive their kinetic energy.

Neutrons lose energy by colliding with things of similar mass, such as hydrogen nuclei (often in water). If they collide with a heavy nucleus, such as plutonium, they just bounce off without losing speed. (Or fission or capture.)

Think of billiards. The cue ball may slow or stop after hitting another ball, since they have similar masses. But hit the rail and it just bounces off, at the same speed, because the table is so much heavier.

If there are no light nuclei in the environment, then the neutrons won’t slow down.