HNHacker News
TopNewBestAskShowJobs

obl

1,695 karma · joined August 9, 2015

submissionscomments
obl··on Borrow Checking, RC, GC, and Eleven Other Memory Safety Approaches
It is not ridiculous at all. Those things have pretty precise definitions and type segregation absolutely does remove a bunch of soundness issues related to type confusion.

You can think of it as the rather classic "Vec of struct + numeric IDs" that is used a lot e.g. in Rust to represent complex graph-like structures.

This combined with bound checking is absolutely memory safe. It has a bunch of correctness issue that can arise due to index confusion but those are not safety issues. When combined with some kind of generational counters those correctness issue also go away but are only caught at runtime not at compile time (and they incur a runtime cost).

Rust's memory safety is about avoiding liveness issues (that become type confusions since all memory allocators will reuse memory for different types), nothing more, nothing less.

obl··on The C bounded model checker: criminally underused
Weird that this treats uninitialized variables as unknown values. For example in ex3.c, the program

  int main(){
      int x;
      if (x <= 42){
              assert(x != 12345);
      }
  }
is of course UB in C, even though under a "uninitialized is random" model the program is valid and does not assert (as the model checker concludes).

(even in O1 clang gets rid of the whole function, including even the ret instruction, I'm surprised it does not at least leave an ud2 for an empty function to help debugging since it would not cost anything https://godbolt.org/z/eK8cz3EPe )

obl··on Memory safety without borrow checking, reference counting, or garbage collection
This is memory safe if you never re-use a (generational index, address) pair.

They seem to use 64 bit ones so this means that to overflow a single memory cell you would have to allocate and free it every cycle (!) at 4 ghz for about 150 years.

Basically as long as you accept this incredibly small "memory leak" you're fine.

obl··on Full screen triangle optimization
Actual clipping is expensive so indeed a "guard band" is used : inside the region allowed by the internal precision of the rasterizer, outside pixels are simply "ignored".

See e.g. https://fgiesen.wordpress.com/2011/07/05/a-trip-through-the-... for a nice detailed explanation.

obl··on Full screen triangle optimization
It would be interesting to see how you were testing for that, because at least on AMD it's fairly certain that a single thread can be shading multiple primitives.

For example, from the ISA docs [1], pixel waves are preloaded with an SGPR containing a bit mask indicating just that :

> The new_prim_mask is a 15-bit mask with one bit per quad; a one in this mask indicates that this quad begins a new primitive, a zero indicates it uses the same primitive as the previous quad. The mask is 15 bits, not 16, since the first quad in a wavefront begins a new primitive and so it is not included in the mask

The mask is used by the interp instructions to load the correct interpolants from local memory.

In fact, in the (older) GCN3 docs [2] there is a diagram showing the memory layout of attributes from multiple primitives for a single wavefront (page 99).

That being said, of course I expect this process to be "lazy" : you would not want to buffer execution of a partially filled thread forever, so depending on the workload you might measure different things.

[1] https://developer.amd.com/wp-content/resources/RDNA2_Shader_...

[2] http://developer.amd.com/wordpress/media/2013/12/AMD_GCN3_In...

obl··on Full screen triangle optimization

  In actual hardware shading is done 32 or 64 pixels at a time, not four. The problem above just got worse.
While it's true that there are "wasted" execution in 2x2 quads for derivative computation, it's absolutely not the case that all lanes of a hardware thread (warp / wavefront) have to come from the same triangle. That would be insanely inefficient.

I dont think that it's publicly documented how the "packing" of quads into lanes is done in the rasterizer for modern GPUs. I'd guess something opportunistic (maybe per tile) taking advantage of the general spatial coherency of triangles in mesh order.

obl··on Building the fastest Lua interpreter automatically
If you didn't already, I'd recommend compiling llvm/clang in debug or release+assert mode when working on it. The codebase is quite heavy in debug-only assertions even for relatively trivial things (like missing implementation of some case, some combination of arguments being invalid, ...) which means that it's pretty easy to get into weird crashes down the line with assertions disabled.
obl··on The Problem with RISC-V V Mask Bits
Wait, I'm pretty sure operand collection logic & banking is there to keep the number of ports on the SRAM low, so basically you're arbitrating and buffering requests coming from high register count instructions (say 3 input fma) and potentially multiple pipelined SMT threads (not thread in the nvidia sense, thread in the "a whole wavefront/warp" sense).

However to me it seems that's completely orthogonal to the vector lanes : I don't see why two parallel lanes in a single thread (eg a 64-element GCN wavefront) would need cross-connected logic at the register file, since almost all instructions _do not_ read/write data from another lane.

There are a few cross-lane shuffles / reduce instruction but it seems to me that those would be handled in a dedicated execution unit. (they are not really the fast-path/common case)

obl··on Noita – roguelite where every pixel is simulated
If you're interested the dev had a cool GDC talk going over the design : https://www.youtube.com/watch?v=prXuyMCgbTc
obl··on Why did post-8008 CPUs not keep the on-chip stack idea?
That sounds very unlikely ?

"The reason" why memory is slower than registers (apart from size obviously) is that register dependencies are static and can be easily tracked by the core. Memory is way harder since you don't know all the addresses in advance (any other random store could actually be storing to the stack).

That's why they have to use costly (associative) structures like the store queue.

The way cores track the stack is usually for return address prediction because it's a huge win for little cost and almost no well behaved program overwrites return addresses manually (low mispredict rate).

As far as I know, all x86 cores emit 2 uops for a push or a pop (load/store + sp adjust). I guess it can save you some frontend bandwidth but that's about it.

obl··on It’s Time for a Modern Synthesis Kernel
Nice article.

Of course if you get some of the benefits of run time specialization, you also get some of the downside, i.e., overspecialization.

The heuristics to know when to stop specializing is a really hard part of those kind of systems.

You could have a program that does a single write() on 100k different files. You could have thousands of processes each writing to a single file and bloating the I$ with useless copies of write.

obl··on First steps towards a made-in-Europe high-performance microprocessor
If I was more optimist, I'd say that this would be a good opportunity to open up silicon design by requiring some amount of transparency that is usually expected of publicly funded research.

However I'm guessing that this initiative has probably close to no leverage on the EDA vendors & the fabs, so at best we'd get the RTL source.

TBH I'd be happy with a fully open 130nm design kit that is actually supported by a fab.

obl··on Orange_slice: Research Kernel and Hypervisor in Rust
Nice. I'm sure you could do a lot of cool things once you have this working well by playing around with the "butterfly effect".

For example introduce a single X us jitter in the RTC interrupt and see how long it takes or which part of the machine state diverges from the baseline run.

obl··on The CPython Bytecode Compiler Is Dumb
There is a reason why basically every attempt to make this kind of language fast has to support some form of on-stack replacement.

For example, it's hard to optimize even local variable dataflow in python since it's part of the API : you can inspect the local frame of your caller, so you have a problem as soon as your function contains a single call. And no you can't know statically what is the call target since it can be replaced dynamically.

So either you perform the optimization anyway and then have to try to support reconstructing values correctly to support introspection, or you just do that generically with OSR and use the simple introspection on the interpeter.

Either way, there are not a lot of "simple optimization" when the language is so dynamic.

obl··on Mesh: Compacting Memory Management for C/C++ Applications
Very clever use of virtual memory.

Unfortunately I would expect this technique not to scale well with increasing page size, and I sure hope that we will be slowly moving to >4k pages as years go by since the TLB is a very common bottleneck.

obl··on Slack Says It's Filed to Go Public
Of course ?

Yes it often makes sense to produce inefficient code for many business reasons (development speed, users don't care, easier platform to deploy to, etc).

However what Slack does would be nowhere near taxing for a modern computer if it were to be done remotely efficiently.

obl··on Faster hash joiner with vectorized execution
The "core" of the trick is nice : amortizing interpreter dispatch over many items. (ignoring the column layout/SIMD stuff which basically helps in any case)

Essentially it's turning :

  LOAD
    DISPATCH
    OP1
    DISPATCH
    OP2
    ... (once per operation in the expression)
  STORE
  ... (once per row)
into

  DISPATCH
    LOAD
    OP1
    STORE
    LOAD
    OP1
    STORE
    ... (once per row)
  DISPATCH
  ... (once per operation in the expression)
The nice trade-off here is that you don't require code generation to do that, but it's still not optimal.

If you can generate code it's even better to fuse the operations, to get something like :

  LOAD
    OP1
    OP2
    ...
  STORE
  LOAD
  ...
It helps because even though you can tune your batch size to get mostly cached loads and stores, it's still not free.

For example on Haswell you can only issue 1 store per cycle, so if OP is a single add you're leaving up to 3/4 of your theoretical ALU throughput on the table.

obl··on Analyzing the Performance of WebAssembly vs. Native Code
What's the point of using this for native applications ?

I mean yeah, it might be a little easier to distribute but it's kind of absurd to agree to throw away 20% performance for a bit of convenience and then sched tears on how the latest intel chips only delivered 5% improvement over the previous ones.

obl··on TSMC Nanke 14 Factory Production Interruption Could Affect NVIDIA and Others
If you have time : https://www.youtube.com/watch?v=NGFhc8R_uO4

It's great.

obl··on Game Loop
Extrapolating up to one physics frame is still not a good solution, it will be noticeable.

For example a falling object will clip in the ground for tens of ms of displacement which is definitely visually significant.

A better solution is to either only interpolate and live with the additional frames of input latency (fine for a lot of games) or resimulate the next physics frame with the new player input, and live with the additional CPU overhead.

obl··on Revery – Native, high-performance, cross-platform desktop apps
Of course that's a choice for everyone to make, but I feel like in general the benefit of fitting in the platform is overrated.

After all the whole webapp-everything somewhat shows that people don't care that much, they are happy to use GMail for example. Another family of examples would be the big software packages like the Adobe or Autodesk stuff, they tend to have a fairly custom look&feel.

IMO it's probably sufficient for the thing to look "modern" (ie up to date wrt to UI fashion trends). Then you get the huge upside of easier maintenance and less bugs.

obl··on Volume Rendering with WebGL
You should probably use mipmaps to avoid aliasing when rendering from far away.

I guess you'll have to compute the LOD by hand since neighbor fragments are not necessarily performing the same texture fetches.

obl··on Bytecode compilers and interpreters
Since this is intented to be educational I find it a bit unfortunate to implement function calls using the host (python) stack since it's an important part of an interpreter.

It means that you can't really add things like stack traces, coroutines, exceptions, single stepping, etc and understand how they work under the hood.

obl··on An Introduction to GPU Programming in Julia
I wonder how they are going to pull that off without security implications.

If you've played with compute shaders (or any of the modern "general purpose" shader stuff, ie arbitrary loads & stores etc) you probably know that it's quite easy to crash drivers. Of course you do so generally by provoking some form of UB (although not always, their runtime/compilers are far from bug-free).

But WebGL can't have that, so I don't see how they could pull that off without adding a ton of runtime bound checks to shaders, like they do for index buffers right now but on the GPU side this time.

Not only would that be bad for performance, but I still would never trust this whole stack to run arbitrary code.

obl··on Discerning the Out-Of-Order Advantage: Is It Speculation or Dynamism? (2013) [pdf]
It's not free though. If you can actually remove most of the power/area hungry ooo scheduling logic for only 10% less performance on real world workload, you can pack a lot more cores or a bigger GPU on the same chip without blowing up TDP or die size.

Sure, some use case will always require the highest single thread perf at all cost but that's less and less true these days.

obl··on Java’s new garbage collector promises low pause times on multi-terabyte heaps
The memory mapping trick they use on x86 to avoid masking only works up to the maximum 48 bits of addressable virtual memory, so there is much less than 22 free bits in that case.

It's also not quite free since it takes up TLB space.

obl··on Automatic Generation of a Hybrid Query Execution Engine
It's a cute idea to cobble together a meta-tracing JIT for sqlite's query interpreter using source extraction and gcc.

I think it's basically a local minimum for implementation complexity vs performance though. To push that further you probably need to modify the original interpreter or encode more (any) knowledge about the semantics in the JIT, at which point you lose the main advantage of maintaining only one codebase.

obl··on DX12 Ray Tracing Tutorials
It's disappointing to have this whole business go inside the driver / dx runtime.

I'm sure the vast majority of it could be done from user code (CPU code & compute shaders) and it would be much more profitable for everyone if they'd expose the couple driver hooks they needed to achieve peek performance.

As it is now, it's super opaque and bundled (do you even know what kind of acceleration structure you're using ?) and seems to be going the exact opposite way that GPU programming has been going (more general & programmable).

Haven't tried it yet, but AMD has gone the open-source library way on this. I sure hope it works out well for them.

(also this seems like a nightmare for the wine people)

obl··on Stacked Borrows: an aliasing model for Rust
Beyond the technical aspect, the pedagogical side of this is huge.

An argument often made in favor of Rust's static analysis restrictions is that "worst case scenario, you just drop down to unsafe and you're back to C semantics".

However, this only holds true as long as the rules to uphold in unsafe code are easy to explain. Strict type aliasing in C is already considered as somewhat of a disaster by many, and is way simpler.

I hope they get this right.

obl··on HHVM JIT: A profile-guided, region-based compiler for PHP and Hack
Half a gig of machine code...

In the paper they mention trying to limit the code size to 10% of that and getting ~60% of the baseline perf.

However, they got this number by simply dropping to the interpreter for the rest of the code. I'm curious what kind of figures they'd get if they got to this 10% goal by being more aggressive in the type guard widening pass.

Page 1 of 3Next →