The V5 is a great pen! They used to be my daily driver, and if you want what they do well, they're hard to beat. (Fountain pens can and will, but they're fussy, and everyone knows it. They're basically V5s on steroids: same highs, same lows, just more of them, with more choice and customization possible.)
But I would never call them "robust". Unfussy, yes. But a G2 glob is just a minor annoyance. A V5 leak, and they do leak, is a real problem. They're also prone to quick deaths if they roll off a table. G2s don't care about such minor mishaps.
I think there absolutely are 10x doctors! When every doctor or specialist you meet in a field says "yeah, Dr X is a massive asshole and I kind of hate him personally but if I ever need [not-particularly-rare procedure Y], I want him to be the one to do it", I think Dr X counts.
The G2 definitely does glob. That's one of its bigger faults. (Others being that I, personally, prefer a line width between the 05 and 07 options -- obviously this is world-stoppingly critically important -- and that really old ones, I mean really old, tend to get disgusting sticky grips.)
Mostly they're just nice for being fairly rugged and reliable in a way most nicer pens just aren't, for carrying loads of ink, and for being ubiquitous. They're far from perfect. They're just... Good Enough™. And that's good enough!
If you love the V5, then the next step is definitely a fountain pen. There are plenty of guides out there, so I'll not waste time doing an inferior job of making a specific recommendation.
Would anyone downvoting care to explain? I'm genuinely interested in seeing anything that suggests there's either some secret breakthrough (completely plausible, but there's no evidence that I've seen hint of) making quantum computers actually useful, or an argument that they'll be usable by (say) 2050?
Because right now my attitudes are trained by things like this https://algassert.com/post/2500 that explain just why 15 was factored in that famous run of Shor's algorithm and not, say, 21; and why 21 hasn't been factored yet and isn't likely to be any time soon....
Agreed. This looks from the outside like someone read a report, got unnecessarily spooked, and now the rest of the herd is following along.
But it's also very possible that hypothetical report was genuinely concerning. We just haven't seen it or anything like it.
However I'm pretty firmly in the "quantum computing won't be doing anything useful any time soon, if ever" camp, so that definitely colors my opinions. I don't have any particular recent expertise to support that, but I did used to share an office with some serious QC people and go to their talks so... make of my words what you will.
The word "uncorrelated" is doing a lot of heavy lifting in that claim. Most DRAM error sources are pretty clearly correlated, if you're paying any attention.
We're right here! Some of us just prefer to stay out of these silly irrational debates because we know that neither of those two crazy camps will listen to a word we, or anyone else, will say. We might be wrong about that (I hope we're wrong about that!) but there sure are enough other people chattering that it's easy to sit back and let them have it out.
I don't have anything covering recent generations. Try the usual suspects, I guess (Agner Fog et al). Sorry that's not more useful, but I haven't seriously worked on x86 in over a decade, so I'm a bit out of date.
Certainly, back then the prefetchers were a lot happier when they could easily identify patterns. They are more sophisticated now, but the old tricks still work. Avoiding register-based indirection is a major help to pretty much everything. When the base register gets updated, as well as the index register, that's hard to optimize. It shows up in both memory prefetch as well as speculation past an instruction.
The other idea to keep in your head is to start thinking in SSA form. Compilers live and breath SSA, so if your fast-path code looks like SSA with a couple of phi nodes, well, it's probably going to generate like you think it will. That's why I preferred the explicit `update_j` style: it's SSA form!
> in this particular case I think it's a little misguided ... only inherent difference between 8-bit and 32-bit code is the use of `movzx` versus `mov` ... generates ugly code for address calculation ... the induction heuristics didn't do their best here
OK, it seems I've been a bit confused myself. I think my final conclusion is actually just that clang is generating kind of crap code here, and this change gets good codegen out of clang. Since I was mostly looking at clang and was leaving gcc as an afterthought, I didn't pick up on this. (Obviously I'm a little rusty on my x86, I shouldn't have fallen for that!) As gcc shows, it doesn't matter much either way. But when clang is happy, its code is quite nice, so there's that.
That little address dependency chain is nastier than it looks, though, the way clang is writing it. Best done away with. There's really no reason for clang to be emitting that crud. gcc handles the addressing in a much cleaner manner whether it's byte- or dword-wide. But gcc also does need that fence when clang does not. I'm sure that's not a coincidence.
> Could you explain your thought process [on placing the compiler fence]?
I ended up dumping this in kind of carelessly and noting that it worked before moving on (it was a last-minute add and I was kind of done by this point). But GCC does care where it goes, since it doesn't work if placed before. Let's try this explanation: the fence basically means "resolve all funny business with this variable before proceeding". Before the write, there's no funny business to resolve: nothing has happened to that variable. No writes, no outstanding reads (we're well into the loop at this point, in theory). So it's a fancy nop. But if it's after the write, we've now got a consequence: `next_j[i][j]` is different now. The fence forces us to resolve that now and not let it linger until the next loop iteration. Where it can be handled perfectly well, but not particularly quickly (which we do care about), and by the way that choice puts the update in the fast path. Forcing it to be dealt with before we re-enter the fast path is how we force the stupid compiler to keep it out of the fast path.
> ugly code for address calculation... might affect throughput a little
What I'd actually worry most about is poisoning the prefetchers, and speculation more generally. They're very very good at handling things like "increasing stride off this base". They struggle more with things like "double indirect register access to determine next address", though there is so much compiler crud out there that they have some surprising capabilities. Basically: simple stupid loop stride is going to do well with them. Complicated four-instruction chains to generate an address that could have been `[base + 8*stride]` or whatever is just... not helping. gcc does perfectly well here. It has multiple offsets floating around, but all of those instructions to update them can update superscalar, in a single cycle. The clang chain is a four-cycle delay. And to top it all off the branch can probably fuse in the simple addressing case!
A huge part of the problem here is that you're playing with the 8-bit registers. They work, but they're like travelling the back roads: the CPU designers put all their effort into the big highway next door, and not so much into keeping the back roads clear. They're infamous for random weird stalls and such. I wouldn't be surprised at all if there's dependency chain tracking weirdness using them.
If you can change the type on `next_j` over to `unsigned` (or `size_t` or ...) then a lot of weird stuff goes away. The dependency chains in address calculation at the beginning of the loop are gone too, which seems a win. (Or I'm sure there's some other, more complicated, way to get the compiler to get rid of them.) But if the space hit from using `unsigned` is allowable, I'd expect it to be both faster and less brittle.
The processor doesn't really know what you're up to, it only sees registers. When `j` is stored in `ecx`/`rcx` and `ecx` isn't changing, it knows it's free to push ahead pretty far on speculation. If the update to `ecx` is rare, putting it behind a well-predicted-not-taken branch will make it go away, as far as the speculation engine is concerned, and let the processor go far and fast. (The rollback on mispredict can be pretty painful, but, well, that's out-of-order execution for you.) That's what we're really trying to accomplish here: stuff that single register write behind a rare branch, somehow.
Note that I disabled unrolling because some approaches got unrolled more than others. (I saw no unrolling, 2x, and more!) Comparing them without unrolling is fairest, I think, though it's also interesting to see how far they can unroll without assistance.
I also found that clang didn't need any additional fencing (or care if it was present), but gcc did, so there's an `asm volatile` style fence, which I think is a lot more clear than the other tricks. (Your mileage may vary; people who've done a lot of low-level work won't blink at these, while others will just stare agape. Perhaps also not blinking, but for opposite reasons!)
(Mind you, I didn't actually run any of this, so, well, you get what you pay for.)
TL;DR: I'm surprised this isn't a laser printer, as those are actually quite a bit easier to design and manufacture, especially if you can use a cheap, older, commonly available, remanufacturable toner cartridge.
Quantum mechanics is an excellent example here. It is not "defeatist" to accept that we don't know where the electron in the hydrogen atom actually is. Or to accept that if we really, really wanted to figure out where it is, we can only do so by disturbing it enough that its position is probably no longer a useful thing to know.
These are fundamental features of the world (at least according to our best theories of Nature), and it is only by accepting them and the uncertainties inherent to them that we are able to make progress using those theories. Among the consequences is that thinking about "the position of the electron" is not so useful; we instead need to leave position behind and start thinking using a new thing, "the orbital of the electron". This is a major conceptual change, and internalizing it can be Very Difficult for some people.
But the world does not care. It and its complexity owes nothing to anyone. It is us who must adapt to the world, in all its fuzziness and incompleteness. Nature will break the rigid, but if you bend, you can soar.
> optimistic that modern reactor designs and reprocessing technologies can overcome these issues
The obstacles aren't technical. They never really have been. The obstacles are human: political, bureaucratic, and corporate. It's not about "can we build a safe nuclear plant?". It's about "do you trust these bozos to build a safe nuclear plant?", remembering that if said bozos screw up, the damage is basically irreversible.
That's the problem.
LILCO Shoreham, for example, famously couldn't build backup gernerators that worked, until they exploded and had to be completely redesigned and replaced. Does that inspire confidence in the rest of their plant?
And following on from that, this has all the hallmarks of a successful appeal for unreasonable sentences. However, it's going to go to the Fifth Circuit, who are, ah, not known for their friendliness to criminal defendants.
This is a kind of thinking a lot of programmers fall prey to. The real world, outside of code, is a very fuzzy and inherently analog place. There is very rarely one in any complex system having a complex problem needing a complex solution. At some point even the definition of diagnosis gets fuzzy.
The best demonstration of this in medicine is probably the DSM-5. What, really, is the difference between Narcissistic Personality Disorder and Borderline Personality Disorder and Generalized Anxiety Disorder? Can they overlap? (Yes.) How do you treat them? (It's not easy.) What about depression: how do you tell if someone has Major Depressive Disorder or Bipolar Depression? (Again: not easy.) In some circumstances the only way to tell the difference between the two is what drugs work: if antidepressants help, it's Major Depression; if mood stabilizers help, it's Bipolar Depression. It's kind of odd to define a One True Diagnosis by "well we fixed it this way, so it must have been that", with no other way to do it, isn't it? (What if both work? What if one works for a while, then the other works? What if treatment with antidepressants induces bipolar (hypo)mania? All of those happen!)
Somehow I only managed to end up on one of these gorgeous birds once. In seat 64K, NRT-DTW (or was it NRT-MSP?). The main cabin is... nothing to write home about. I was in no hurry to book another 744 leg. Upper deck, perhaps a different story.
But I would never call them "robust". Unfussy, yes. But a G2 glob is just a minor annoyance. A V5 leak, and they do leak, is a real problem. They're also prone to quick deaths if they roll off a table. G2s don't care about such minor mishaps.
So the G2 is my vote for "sprinkle everywhere".