HNHacker News
TopNewBestAskShowJobs

raggi

2,842 karma · joined December 24, 2009

submissionscomments
raggi··on Go ahead, self-host Postgres
I have been self hosting a product on Postgres that serves GIS applications for 20 years and that has been upgraded through all of the various versions during that time. It has a near perfect uptime record modulo two hardware failures and short maintenance periods for final upgrade cutovers. The application has real traffic - the database is bigger than those at my day job.
raggi··on What Does a Database for SSDs Look Like?
It may not matter for clouds with massive margins but there are substantial opportunities for optimizing wear.
raggi··on Torvalds on Linux Security Modules
I think this is a fair take. Local security for Linux is nightmare fuel already, we don't need more.
raggi··on Go Proposal: Secret Mode
So you’re correct that covering the broadest general case is problematic. You have to block code from doing IO of any form to be safe.

In general though getting to a fairly predictable place is possible and the typical case of key material shouldn’t have highly arbitrary stacks, if you do you’re losing (see io comment above).

https://docs.rs/zeroize/1.8.1/zeroize/ has been effective for some users, it’s helped black box tests searching for key material no longer find it. There are also some docs there on how to avoid common pitfalls and links to ongoing language level discussions on the remaining and more complex register level issues.

raggi··on VPN location claims don't match real traffic exits
Do you have actual evidence of this? What ASN operates this way?
raggi··on Go Proposal: Secret Mode
This seems like it might be expensive (though plausibly complete), so I wonder if it’ll actually benchmark with a low enough overhead to be practical. We already struggle with a lack of optimization in some of the named target use cases - that said this also means there’s space to make up.
raggi··on Go Proposal: Secret Mode
It doesn’t but the problem space is more constrained as you are at least in control of heap vs stack storage. Register clearing is not natively available though. To put it more simply: yes but you can write this in rust- you can’t write it in go today.
raggi··on Go Proposal: Secret Mode
It is fundamentally not possible to be in complete control of where the data you are working with is stored in go. The compiler is free to put things on the heap or on the stack however it wants. Relatedly it may make whatever copies it likes in between actions defined in the memory model which could leak arbitrary temporaries.
raggi··on SSE sucks for transporting LLM tokens
Resumable “at least once” pub sub would be exactly the same architectural semantics as a more complete SSE implementation.

A server would keep a buffer of events and a cursor keyed by some kind of event id. Resuming clients would reattach on a new dissociated connection and ask to resume from a particular id.

This is what the id field in events and the last-event-id are for in the SSE specification.

A pub sub system would also not solve the described unidirectional problem.

As inference is so expensive it seems natural to add a sensible stream buffer solution in some middleware and that’s trivial to write. Hell it’s the kind of thing a one paragraph prompt would almost certainly one-shot.

The post seems to be more of a reaction to some specific situation than a meaningful commentary on the protocol or associated architectures.

raggi··on Golang's big miss on memory arenas
Sure, you drop an active arena pointer into TLS and allocate out of that then pop and free it once you pop the stack. Producing API guarantees that all incoming references are dead before you do that though, that's the real trick.
raggi··on Golang's big miss on memory arenas
It's not, but joining the two comments together sync.Pool is often close to what you want for a subset of cases, and it's sort of a locality biased generational storage (without actually providing you strong long-term guarantees that it is that).
raggi··on Golang's big miss on memory arenas
Yes, there's a case to be made that exposing "real" pointers in a GC'd language was a substantial mistake, but I guess it simplified _some_ parts of FFI. The trade-off so far maybe is fine, but it is a shame that there are certain things that can't be done without introducing new substantial costs. Maybe the compiler could learn to do something suuuper clever like recognize when pointers are being used non-transparently and automatically pin those, seems fraught with potential error though, trivial example being stuff like &a[0] (that ones easier to catch, others might not be).
raggi··on Golang's big miss on memory arenas
> You can do fully manual memory management in Go if you want. The runtime is full of tons of examples where they have 0-alloc, Pools, ring buffers, Assembly, and tons of other tricks.

The runtime only exposes a small subset of what it uses internally and there's no stable ABI for runtime internals. If you're lucky to get big enough and have friends they might not break you, some internal linkage is being preserved, but in the general case for a general user, nope. Updates might make your code untenable.

> If you really want an arena like behavior you could allocate a byte slice and use unsafe to cast it to literally any type.

AIUI the prior proposals still provided automated lifetime management, though that's related to various of the standing concerns, so you can't match that from "userspace" of go, finalizers don't get executed on a deterministic schedule. Put simply: that's not the same thing.

As someone else points out this is also much more fraught with error than just typing what you described. On top of the GC issue pointed out already, you'll also hit memory model considerations if you're doing any concurrency, which if you actually needed to do this surely you are. Once you're doing that you'll run into the issue, if you're trying to compete with systems languages, that Go only provides a subset of the platform available memory model, in the simplest form it only offers acq/rel atomic semantics. It also doesn't expose any notion of what thread you're running on (which can change arbitrarily) or even which goroutine you're running on. This limits your design space quite significantly at the bounds your performance for high frequency small region operations. I'd actually hazard an educated guess that an arena written as you casually suggest would perform extremely poorly at any meaningful scale (lets say >=32 cores, still fairly modest).

> You could argue that C++ RAII overhead is “bounded performance” compared to C. Or that C’s stack frames are “bounded performance” compared to a full in-register assembly implementation of a hot loop. > But that’s bloody stupid. Just use the right tool for the job and know where the tradeoffs are, because there’s always something. The tradeoff boundary for an individual project or person is just arbitrary.

Sure, reducto ad absurdum, though I typically would optimize against the (systems language) compiler long before I drop to assembly, it's 2025 systems compilers are great and have many optimizations, intrinsics and hints.

> Man this person is mediocre at best.

Harsh, I think the author is fine really. I think their most significant error isn't in missing or not discussing difficult other things they could do with Go, it's seemingly being under the misconception prior to the Arena proposal that Go actually cedes control for lower level optimization. It doesn't, and it never has, and it likely never will (it will gain other semi-generalized internal optimizations over time, lots of work goes into that).

In some cases you can hack some in on your own, but Go is not well placed as a "systems language" if you mean by that something like "competitive efficiency at upper or lower bound scale tasks", it is much better placed as a framework for writing general purpose servers at middle scales. It's best placed on systems that don't have batteries, and that have plenty of ram. It'll provide you with a decent opportunity to scale up and then out in that space as long as you pay attention to how you're doing along the way. It'll hurt if you need to target state of the art efficiency at extreme ends, and very likely block you wholesale.

I'm glad Go folks are still working on ideas to try to find a way for applications to get some more control over allocations. I'm also not expecting a solution that solves my deepest challenges anytime soon though. I think they'll maybe solve some server cases first, and that's probably good, that's Go's golden market.

raggi··on Valve: HDMI Forum Continues to Block HDMI 2.1 for Linux
Not with good measured performance no. There are some which advertise good numbers (such as high refresh rates) but are unable to drive the panels to visibly change pixels at anywhere near the refresh rate.
raggi··on Rust in the kernel is no longer experimental
That first sentence though. Bitfields and ABI alongside each other.

Bitfield packing rules get pretty wild. Sure the user facing API in the language is convenient, but the ABI it produces is terrible (particularly in evolution).

raggi··on Rust in the kernel is no longer experimental
If it was being removed the title would be "An update on rust in the kernel"
raggi··on GrapheneOS is the only Android OS providing full security patches
Thanks for following up here. I’m glad to hear the OEM stuff is ongoing that’s going to be so big. Congrats and good luck!
raggi··on Spinlocks vs. Mutexes: When to Spin and When to Sleep
Some considerations can be similar, but the total set of details are different.

It also depends which lock free solutions you're evaluating.

Some are higher order spins (more similar high level problems), others have different secondary costs (such as copying). A common overlap is the inter-core, inter-thread, and inter-package side effects of synchronization points, for a lot of stuff with a strong atomic in the middle that'll be stuff like sync instruction costs, pipeline impacts of barriers/fences, etc.

raggi··on Spinlocks vs. Mutexes: When to Spin and When to Sleep
> Spinlocks outside the kernel are a bad idea in almost all cases, except dedicated nonpreemptable cases; use a hybrid mutex. Spinning for consumer threads can be done in specialty exclusive thread per core cases where you want to minimize wakeup costs, but that's not the same as a spinlock which would cause any contending thread to spin.

Very much this. Spins benchmark well but scale poorly.

raggi··on Thoughts on Go vs. Rust vs. Zig
Yup, your example was fine, as I said I just wanted to show a safe method too :-)
raggi··on GrapheneOS is the only Android OS providing full security patches
Their contributions upstream go way back, I think someone could misread this comment that they've not contributed, and that would be an unfortunate misunderstanding.
raggi··on Thoughts on Go vs. Rust vs. Zig
OP you keep comparing to doesn't even declare the variable. I'm done with you.
raggi··on GrapheneOS is the only Android OS providing full security patches
> I don't think that's a fair comparison.

Fair?

> OEMs have quite a lot of extra steps before releasing any build to the public.

AIUI updates are less stringent and burdensome than initial certification. Regardless much of the process is automated. Graphene has CI too. 3PL's taking 4 weeks to run automated tests is also absurd. There are some "manual steps" to run CTS-V but they shouldn't be weeks level burdensome either. This is the point, this is an industry problem.

The reason that the OEMs even have to deal with this 3PL test mess is for GMS certification, so again this is a policy decision that enforces a poor process. The bad properties of the process are not inherent to the problem space of validating builds against requirements. An industry problem.

> There are "quicker" release channels for security fixes, but I don't think it's common for OEMs to only ship those without any other change to the system.

Seems like a decision that is not user-centric.

> I don't think Graphene does anything of sort, they take what's already certified in the Pixel builds and uses it. Not like they could do much aside testing on the public part of xTS.

Private test suites for software are a toxic idea, it's in the same box as "SSO tax", and other such "pay for security" models. Given the software industry can't be trusted not to do this, I'm almost keen to see legislation to explicitly ban this practice.

raggi··on Thoughts on Go vs. Rust vs. Zig
I agree precise tracing GC's are a huge mess of integration so making them pluggable is likely a pain. I think I'm fairly down on the notion of tracing GC's though and I'd rather have other lifetime tracking mechanisms.
raggi··on GrapheneOS is the only Android OS providing full security patches
Understaffed gift product wants 1 week cycles.

OEMs want 2-4 month cycles.

This is a perfect representation of the state of the software industry.

raggi··on Thoughts on Go vs. Rust vs. Zig

    use std::sync::Mutex;
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        static PEDANTRY: Mutex<u64> = Mutex::new(0);
        *PEDANTRY.lock()? += 1;
        println!("{}", PEDANTRY.lock()?);
        Ok(())
    }
raggi··on Thoughts on Go vs. Rust vs. Zig
> How so? Garbage collection has inherent performance overhead wrt. manual memory management, and Rust now addresses this by providing the desired guarantees of managed memory without the overhead of GC.

I somewhat disagree, specifically on the implicit claim that all GC has overhead and alternatives do not. Rust does a decent job of giving you some ergonomics to get started, but it is still quite unergonomic to fix once you have multiple different allocation problems to deal with. Zig flips that a bit on it's head, it's more painful to get started, but the pain level stays more consistent throughout deeper problems. Ideally though I want a better blend of both - to give a still not super concrete version of what I mean, I mean I want something that can be setup by the systems oriented developer say, near the top of a request path, and it becomes a more implicit dependency for most downstream code with low ceremony and allowing for progressive understanding of contributors way down the call chain who in most cases don't need to care - meanwhile enabling an easy escape hatch when it matters.

I think people make far too much of a distinction between a GC and an allocator, but the reality is that all allocators in common use in high level OS environments are a form of GC. That's of course not what they're talking about, but it's also a critical distinction.

The main difference between what people _call a GC_ and those allocators is that a typical "GC" pauses the program "badly" at malloc time, and a typical allocator pauses a program "badly" at free time (more often than not). It's a bit of a common oddity really, both "GC's" and "allocators" could do things "the other way around" as a common code path. Both models otherwise pool memory and in higher performance tunings have to over-allocate. There are lots of commonly used "faster" allocators in use today that also bypass their own duties at smarter allocation by simply using mmap pools, but those scale poorly: mmap stalls can be pretty unpredictable and have cross-thread side effects that are often undesirable too.

The second difference which I think is more commonly internalized is that typically "the GC" is wired into the runtime in various ways, such as into the scheduler (Go, most dynlangs, etc), and has significant implications at the FFI boundary.

It would be possible to be more explicit about a general purpose allocator that has more GC-like semantics, but also provides the system level malloc/free style API as well as a language assisted more automated API with clever semantics or additional integrations. I guess fil-C has one such system (I've not studied their implementation). I'm not aware of implicit constraints which dictate that there are only two kinds of APIs, fully implicit and intertwined logarithmic GCs, or general purpose allocators which do most of their smart work in free.

My point is I don't really like the GC vs. not-GC arguments very much - I think it's one of the many over-generalizations we have as an industry that people rally hard around and it has been implicitly limiting how far we try to reach for new designs at this boundary. I do stand by a lot of reasoning for systems work that the fully implicitly integrated GC's (Java, Go, various dynlangs) generally are far too opaque for scalable (either very big or very small) systems work and they're unpleasant to deal with once you're forced to. At the same time for that same scalable work you still don't get to ignore the GC you are actually using in the allocator you're using. You don't get to ignore issues like restarting your program that has a 200+GB heap has huge page allocation costs, no matter what middleware set that up. Similarly you don't want a logarithmic allocation strategy on most embedded or otherwise resource constrained systems, those designs are only ok for servers, they're bad for batteries and other parts of total system financial cost in many deployments.

I'd like to see more work explicitly blending these lines, logarithmically allocating GC's scale poorly in many similar ways to more naive mmap based allocators. There are practical issues you run into with overallocation and the solution is to do something more complex than the classical literature. I'd like to see more of this work implemented as standalone modules rather than almost always being implicitly baked into the language/runtime. It's an area that we implicitly couple stuff too much, and again good on Zig for pushing the boundary on a few of these in the standard language and library model it has (and seemingly now also taking the same approach for IO scheduling - that's great).

raggi··on Thoughts on Go vs. Rust vs. Zig
Can you give some examples of " ... not excruciatingly painful" and why you think they're inherent to RAII?
raggi··on Thoughts on Go vs. Rust vs. Zig
Not enough to say yes in earnest. I help maintain some swift at work, but I put my face in the code base quite rarely. I've not authored anything significant in the language myself. What I have seen is some code where there are multiple different event/mutex/thread models all jumbled up, and I was simultaneously glad to see that was possible in a potentially clean way alongside at least the macos/ios runtime, but the code in question was also a confused mess around it and had a number of fairly serious and real concurrency issues with UB and data races that had gone uncaught and seemingly therefore not pointed out by the compiler or tools. I'd be curious to see a SOTA project with reasonable complexity.
raggi··on Thoughts on Go vs. Rust vs. Zig
People always complain about unsafe, so I prefer to just show the safe version.

  use std::sync::Mutex;

  static LIST: Mutex<Vec<String>> = Mutex::new(Vec::new());

  fn main() -> Result<(), Box<dyn std::error::Error>> {

      LIST.lock()?.push("hello world".to_string());
      println!("{}", LIST.lock()?[0]);

      Ok(())
  }
← PreviousPage 4 of 25Next →