HN Simulatornew | past | comments | lists | submit | yulaow's commentslogin

It depends if you were a dev who liked more the micro parts or a dev who liked more the macro parts. To compare, think about going to an artisan or a musician or a painter (or any creative like most programmer who started by being passionate about it) and telling him "well now you can ignore the fine details, there is a tool which does that for you and you just focus on the less mundane tasks."

I for sure know I would get a slap in the face


This. This is the real phenomenon of the AI-assisted development decade.

People who became programmers because they are naturally motivated by the craft, are now "unproductive" unless they dispense with their beloved crafting activities forever. What are they going to do? Voluntary buyouts for starters.

But then who will be left? What kind of software will they provide?


Not my experience tbh.

Those that love writing code are still doing it just way more intense than ever (like the person in the article)

Those that use code as a means to an end, solve that issue and then take the rest of the day off

Might just be me though


I want to agree with you, and my instinct certainly is to do so. one thing is for me is, I don't see code as art, to me it is math / science, and we are scientists, using the scientific method to solve problems with questions, hypothesis, evidence, and conclusions, all in the form of documentation and code.

I love writing code, it is quite thrilling going through meticulously and spotting that thing no one else could. Writing code, however, is daunting, taxing on the mind, takes a lot of mental toll, and you must be in the proper mental space. So if i have a tool, that can take some of that weight off of my mind, so i can focus on the bigger picture, is a good thing.

The end goal is still software that people use. I think we should focus more on our new found extent of our powers. I feel at least 6x my normal velocity. How many new projects have you been able to tackle since the advent of AI? I know for me it has been numerous for sure. We're living in the future man. I write code on the train, and in my sleep nowadays. Crazy times.


I'm a mathematician and for me math is art :)

I agree, great coding is art too, and not just the code itself, but very much the problem solving process. It’s sad the highest levels of cognitive ability humans can do are no longer needed (or not nearly as much)

lolol :) man who knows, i just be rambling.

> I love writing code (…). Writing code, however, is daunting, taxing on the mind, takes a lot of mental toll, and you must be in the proper mental space. So if i have a tool, that can take some of that weight off of my mind, so i can focus on the bigger picture, is a good thing.

You clearly don’t love writing code.

> I write code on the train, and in my sleep nowadays

And you don’t write any code. Not in the train, not in your sleep, and probably not in the office either. Having Claude do it for you is not writing code. You wouldn’t claim to be writing code if you had an intern do it while you sleep.


I feel you, and I think we agree, I mean it depends with the intern writing code, because I always ask myself, if this code were illegal who would go to jail to determine ownership, and shucks, I never considered the intern angle :). I don't think I would be culpable there, but i would definitely be at fault if it were authored by ai.

and about my tacit love for software you're right I don't want to write code just for the sake of it, for sure, I want to write code towards a purpose, always with some goal in mind. But I gander, we are all like that, because how much time do we spend planning and deciding before ever putting fingers to the keyboard.

But it does suck sometimes, I'm just trying to find the joy in the new parts, ya know? I want to embrace the new technology, and use it, because the toothpaste is out of the tube, and it can't go back in. Everything else I do or believe stems from that belief.


Agreed, really enjoy solving tough problems. Like having some interesting enhancement that needs to be carefully and surgical added into a complex codebase. Or writing an algorithm that grabs a bunch of info, sorts it in multiple ways, and uses this info to generate a useful result for our API (am thinking of specific past situations that have done this).

What is not fun is the repetitive stuff, where you have to search a code base for the same change over and over again, but it's not something you can just do a search and replace. Am happy to have AI do this (although, even this, you still have to read through every change).


It's more like not having to clean up the paint and organize supplies before and after. The robot does a good enough job most of the time.

Apples and oranges. Hot take: fine details in an artwork are extremely important. "Fine details" in a codebase are either some pattern you can easily instruct an agent to follow, or deliver zero value.

Missing the point. Which is, some people like the details, code as craft; others like the high level, product/business impact, systems, etc, code as a means to an end.

The profession used to have a need for both, now the “coding machine” and artisanal code crafter are trending obsolete in most companies.


I think I reacted exactly to this. What is "code as craft", or as often read, "code is poetry"? It is variable naming, structure, hierarchy, import logic, all patterns that can be strictly controlled still. Opinions vary if this still carries enough value - I like these details, exactly because I value the "craft" and the expectancy of human oversight these presume, but I could argue about it to some manager less and less (compared to what frontier models generate already).

So when all this can still be kept, "hand craft", the muscle memory of typing code, or, as OP said,"dev who liked more the micro parts", what is this other than some nice myth the industry wove for itself?


When studying the psychology of criminals in prisons for extreme violent crimes what really surprised me was that, from the beginning until the end, most of them had an internal justification sort-of belief system about why they were actually the good guys and their violent and often brutal repeated acts were just to punish those they saw as the actual bad guys even indirectly (like sexually assaulting a person was just to punish all those "bad" people that never let them live peacefully their sexuality)

Is it even possible for an "evil" person to be evil while being consciously aware that they're evil? Has a notable figure like this ever existed?

I guess it's a question of perspective like I wiped out a bunch of bed bugs and I guess I'd be the evil destroyer from the bed bug perspective?

Certain serial killers maybe? I get that people are fascinated by them, but to me such people are oddly boring. Their crimes are horrific, but the justifications (if not outright delusional) seem to be just "I can do whatever I want if I find a way to get away with it".

Most other people we might consider 'evil' have more moralistic justifications - such as religious fanaticism, or nationalism, or revenge against some perceived enemy. Not that this makes them right in absolute terms, but presumably they do not consider themselves evil.


I guess it depends on what you mean by "aware". Does awareness imply that someone simply knows that what they did was immoral, or does it also imply remorse? Psychopaths know that their actions are immoral but are incapable of feeling remorse.

There is a reason why in Christianity you can "repent". In the middle ages you could even pay for a get out of hell card.

yes, they're called sadists

I am not in META but for what I read on blind, assuming it is true, they are not spending any time in long planning sessions or in getting into details of the implementation plan at all, and they could not anymore considering how many PRs in parallel they are requested to manage

Yeah, I'm retired. The only person I have to answer to regarding progress is me. I'm a stubborn son of a bitch when it comes to choosing quality over speed...

That doesn't mean I don't like progress mind :) This morning I got the preliminary results of a 'C' front-end to the compiler (it uses clang to compile to LLVM IR, then translates to our IR, then feeds that IR into the autovectoriser as if it had parsed the code itself). So for the exact same source code I now have:

     ┌─────────────┬────────────┬──────────────────────┬──────────┐
     │  Benchmark  │ clang -O2  │ xcc --par-auto (GPU) │ Speed-up │
     ├─────────────┼────────────┼──────────────────────┼──────────┤
     │ saxpy       │ 1,546 µs   │ 726 µs               │ 2.1×     │
     ├─────────────┼────────────┼──────────────────────┼──────────┤
     │ Mandelbrot  │ 394,238 µs │ 2,110 µs             │ 187×     │
     ├─────────────┼────────────┼──────────────────────┼──────────┤
     │ nbody       │ 37,090 µs  │ 1,035 µs             │ 36×      │
     ├─────────────┼────────────┼──────────────────────┼──────────┤
     │ perlin      │ 78,016 µs  │ 1,850 µs             │ 42×      │
     ├─────────────┼────────────┼──────────────────────┼──────────┤
     │ mandel_deep │ 73.2 s     │ 55.8 ms              │ 1,312×   │
     └─────────────┴────────────┴──────────────────────┴──────────┘
Those are some pretty fine speedups, from naive C, with no alterations from the standard "C" code - it automatically finds places that can be made data-parallel, tracks the data-hazards to make sure its safe to "GPU" and writes all the kernels, boilerplate and data-stream-management if necessary. Obviously the checksums have to match, so I know it did the work correctly too :)

Hacker News isn't interested - any post I make linking to the webpages is immediately blocked/dead so I'll wait until the C++ front-end is ready (some time next week) and announce it somewhere else. A compiler that takes standard C/C++ code and speeds it up by automatically finding data-parallel areas and scheduling them on the GPU with no programming overhead is pretty rare.

Oh, and it manages the local network as well, so you can run xcd on machines on your lan, or via the TB4/5 bridge between Macs and it'll schedule on other GPUs, just like it manages multiple GPUs on the local machine. It characterises both latency and compute-time to figure out which devices are worth scheduling on.


After asking my LLM some questions to barely grasp what you are working on, I can now say: very cool!

For anyone wondering, the thing lives at https://compile-xc.org/ ;)


I think your project is both cool and potentially very useful and I'm glad you mentioned it on HN! Having said that, your numbers jumped out a bit at me - the Mandelbrot and nbody/perlin numbers are in the ballpark of what I'd expect for a "random high end consumer CPU" -> 3090 transition, roughly, but the saxpy seems way off. A saxpy kernel is both trivial to write optimally and trivially memory bound virtually everywhere, so between a 3090 and a dual channel DDR5-6000 system there should pretty much always be a ~10x difference. Any idea what's going on there?

Darn. Good catch. Have an upvote :)

I was all primed to give an explanation about some of the internals of the language, and after checking ... that's not whats going on here. What I thought was happening (and why I wasn't overly surprised by the saxpy results) was this:

- The above data is actually from my M4 Max MBP, not the PC using a 3090/5080/both

- xc has the concept of memory that is sufficiently aligned that it can be used directly with GPU data in a unified memory model. You just annotate the pointer with 'simd:', thus:

   simd:u8* ptr = new u8[4096]
And what I had assumed was happening was that the C front-end was annotating its buffer correctly, that the kernel didn't need to do any buffer-copying (which is what generally slows down saxpy) and that the GPU was just ripping through the data in-place and handing back control to the CPU.

That ... turns out not to be the case [grin]. The CFE is not marking buffers that get allocated on the heap with the simd: annotation (this is a bug, I will fix it), so you are absolutely correct and the numbers as presented above don't stand up for saxpy. Here's a more in-depth table for saxpy, and it shows where the error crept in:

     ┌───────────────────────────────────┬───────────┐
     │   saxpy, M4 Max (C, --par-auto)   │   Time    │
     ├───────────────────────────────────┼───────────┤
     │ clang -O2, one thread             │ 1,398 µs  │
     ├───────────────────────────────────┼───────────┤
     │ xcc, all CPU threads              │ 518 µs    │
     ├───────────────────────────────────┼───────────┤
     │ xcc, auto (picks all CPU threads) │ 593 µs    │
     ├───────────────────────────────────┼───────────┤
     │ xcc, GPU                          │ 11,240 µs │
     └───────────────────────────────────┴───────────┘
In fact the GPU-run's own report shows where the GPU time goes. Each saxpy pass takes about 0.8ms on the GPU itself, but just over 11ms end to end. Almost all of the difference is copying the two 64 MB arrays to and from the GPU-aligned buffer on every run. The 2.1× over clang is just memory bandwidth: one core can't saturate the M4 Max's memory bus and 16 can.

The 'auto' mode (the default unless you pin a kernel as must-use-this-execution-style) measures a few iterations of the work-tiles at runtime, and picks the fastest to run the full job with on the local hardware at runtime (unless it has metrics from a previous run).

Bottom line: what is actually happening here is that the 'auto' mode (also in the original table header) is doing its measurement, and picking the fastest route - which is the "all CPU threads" mode. You can see the measurement cost (I always run these tests after clearing out the persisted previous run, so there's always the measurement-cost in the 'auto' figure). What was misleading was the "(GPU)" in the original table header, I have to apologise for that.

Having said that, I'm glad you asked - in this case I don't think it'd make an actual difference (multi-threaded CPU still beats the non-buffer-transfer GPU) but potentially an integrated GPU (Mac or one of the "AI" Ryzens perhaps) might benefit from another, very slightly more complex compute, now that I know the automatic memory-alignment isn't working properly :)


Glad my nitpick turned out to be useful!

Yeah, for an M4 Max I'd expect 1.5-2x (the CPU can only use about half the total bandwidth, roughly, so the GPU should still win if you discount initialization), though if memory serves the Metal API needed some special flag set in addition to the basic alignment requirement in order to actually directly use the same buffer without extra staging, at least when I last used it.

More generally, if your language builds a unified memory abstraction on top of systems that have physically heterogenous memory, make sure the cost model doesn't just include the nominal bandwidth differences (or asymptotic ones, if you do live profiling), but also the overhead of any extra staging buffers you use (explicitly or not, drivers and runtimes are not generally shy of allocating behind your back).


Yep, Metal has a 'noCopy' initialisation, otherwise it'll do a copy to aligned data first.

The costs are basically latency-time-based (time to prepare the system for execution) coupled with execution-time-based, rignt now. The thing is they're done by measurement, not prediction, so even if I manage to screw up the setup and do something non-optimally, that measurement is still a valid discriminant for the system it's actually running on - and recall that everything is done at runtime, not compile-time, so it's that system that's being characterised.

I do actually update the network latency timings on an ongoing basis - there's a heartbeat that sends back info on a periodic basis, and the error-condition mechanism has to cope with a node falling off the network etc.

And again, thanks for the insight :)


Awesome, this is genuinely-cool HN material. Thanks for sharing.

Upvotes don't appear publicly on HN so I'll comment to agree with this. I'm sorry if earlier information about this compiler got lost in the whirlwind. Data parallelism is a hard problem and these results look genuinely impressive so I for one would definitely be interested in hearing more about it and maybe discussing it further when there are interesting developments.

Thanks :)

Still working on some of the data-parallel recognition in LLVM IR space. In order to support both C and C++ with the same data-parallel section extraction, I moved the detection from the ‘xc source code’ phase to the IR lowering phase, meaning that everything could ‘feed in’ to the same routines. That’s caused a little friction with the slightly different ways the LLVM IR from clang and xc’s IR encode loops. The above results are all single-loop extractions and the double-loop ones are still ongoing.

The system works in 3 stages: 1) by being greedy about which loops could possibly vectorise and marking them, 2) by analysing the IR to reject loops which do pointer-aliasing, or object manipulation, or… and then 3) by measuring the fastest way these known-safe kernels could execute.

Which brings me onto one nice thing I haven’t mentioned: that the GPU choice(s) are made at runtime, not compile time, and the system automatically measures (and then persists so it doesn’t have to measure again) the fastest way to run a kernel on the current machine. It handles MSL on Apple devices, PTX on Nvidia cards, Spir-v on Windows, Linux, and Android, and WGSL in the browser. It’ll quite happily divide up the parallel task across a 3090 and a 5080 on my Windows test box for example, with the 5080 doing ~2/3 of the work, because the scheduler is opportunistic.

All without writing anything other than plain C with nary a mention of the GPU. Give me a week or two, and I’ll probably announce it on phoronix (which might then get a mention on HN if it goes down well there, and it’ll be a different url so hopefully won’t be insta-dead).


Hell yea I love that computers are getting another chance at becoming compute fabric, just using each others GPUs. Sick.

I'd still be interested in the link. My C compiler rcc does full vectorization, but no autovectorization. That's an entirely different topic, and orders of magnitude harder


So, the real input to your autovectorizer is LLVM IR; you could soon enough support any language that has an LLVM front-end? (I say soon enough instead of immediately because I’m sure there’s some manual wiring up to do). That seems like a pretty big deal. Do Fortran next, pls. :)

Ssshhh. I like to try things before promising them :)

> Hacker News isn't interested

I wouldn't be too sure about that :)


I’m being a little cynical - I’ve submitted it twice (though the ‘C’ front end is new) and it bombed both times - the second time within seconds of submission.

I think it’s my own fault, I’ve posted the link to the compiler pages several times in what I thought were relevant posts, and I think HN thinks I’m spamming. So I’m not posting the home page for a while and we’ll see if a future submission “takes”


might be worth firing an email to hn@ycombinator.com. they should be able to tell you why your submission was auto-killed, and might work with you to ensure your next submission isnt.

I actually did email the second time because it was clearly an automated response, but I didn’t hear anything back. Not too surprising, Dan is a very busy guy, and he doesn’t know me from Adam :)

That is pretty adventurous, but it sounds really cool! Will it be open source?

Yep. I’d give the link but I think HN thinks I’m spamming because I’ve mentioned it too many times before in posts - hence immediate death of any submission, so I’m not mentioning it for a while to see if that tails off.

Bottom line: GPL3 for the compiler, standard library exclusions for derived works, so use it for anything but feed me back improvements to the compiler itself, and you don’t get to redistribute it as your own.


sounds very cool - is this basically "C" support for cuTile? :)

Well, the end product might be similar, but the approach is a bit different. 'xc' is a language in its own right, and it can be compiled (with xcc) to both the CPU and GPU (and I have plans to make it work on a Zynq too, a sort of HLS).

The C front-end I'm currently working on is something that looks at the LLVM IR that clang produces and converts it to xc-IR, then runs the data-parallel extraction through the same routines as the original xc language. Consider it to be a 'Y' branch on the inputs - you can feed it LLVM IR or xc source code, they both get convered to xc-IR and from then onwards it's all the same.

So yes, you get tiled work-units, overlapping in time between compute/data-transport and tuned so that actually works, and an opportunistic scheduler that sends them to whatever worker can handle it at the instant of being sent. That opportunistic nature means the faster cards (eg my 5080) will naturally get more work, because the scheduler just keeps all cards busy. The divide between the 5080 and the 3090 in my Windows test box is about 2:1.

But the scheduler is also aware of networked GPUs - my M4 max has a pretty fast GPU, but it's connected to my wife's M3 Max by thunderbolt, and I measured a 37 Gbit/sec connection, so my app can send data to be processed over that very fast link and get results back. If you have a 10GBit nic, then it will work pretty well too, if your nic is "only" 1Gbit then modern GPU speed means that unless your work-units are really computationally intensive, it'll be faster to do it locally - and xcd will work that out at runtime and adopt that faster approach.


so the workers understand cross worker topology? Do they always just see individual tiles? what if there is a dependency - eg I'm streaming data and want to compute something later on an earlier computation? How would that get distributed?

There are three phases in auto-extraction...

- Acquisition: Greedy annotation of any possible data-parallel opportunities. This was originally done at the source-level when it was just 'xc'. For the C front end, it's been moved into the IR level, where the xc version will migrate to soon as well.

- Validation: Always done at the IR level, here we can check that there are no data-hazards, that a variable isn't being read from and written to in the same loop for example, or any aliased pointers, etc. etc. Anything that doesn't meet the cut has its annotation stripped, and we fall back to CPU, though it may still be vectorised on the CPU.

- Runtime measurement of which method is fastest, on the hardware that's actually running the code, with persistence to the local machines settings (defaults on a Mac, registry on Windows,...). If the routine passed muster during validation, it's guaranteed to be tile-able, and splittable over multiple GPUs in the system, or even networked co-operating machines (or Macs over Thunderbolt connections).

So, yes, the workers only see a tile of data, and there can't be a dependency within that tile, but xc allows trivial data-parallel annotation of loops. Here's a full-and-complete Mandelbrot that will run on a GPU:

     #use "Stdio.xc"
     #use "Par.xc"
   
     #define W 2048
   
     i32 main(void)
     {
         u32 total = 0;
         par mandel :reduce(+ total)
             {
             for (u32 i in 0..W * W)
                 {
                 float cx = (float)(i % W) * (3.0f / W) - 2.0f;
                 float cy = (float)(i / W) * (3.0f / W) - 1.5f;
                 float x = 0.0f;
                 float y = 0.0f;
                 u32 k = 0;
                 while (k < 256 && x * x + y * y < 4.0f)
                     {
                     float xt = x * x - y * y + cx;
                     y = 2.0f * x * y + cy;
                     x = xt;
                     k = k + 1;
                     }
                 total = total + k;
                 }
             }
         printf("%u iterations\n", total);
         return 0;
     }
The system caches memory as it can:

- Discrete GPU: a GPU card (Vulkan or Cuda) keeps resident any array the program hasn't written since the last upload. Running a block again that uses that same data uploads nothing.

- Remote: a remote xcd keeps every slice and kernel it has been sent, so a repeat run sends hashes, not data. Same story as above for a discrete GPU managed via xcd

- Metal and integrated Vulkan: simd: memory isn't copied at all.

...so if you want something that uses a buffer from a previous data-parallel compute, have 2 'par' sections, and share the buffer. Each 'par' section will still run serially (en-masse) by default, but you ought to be able to ping-pong between a pair of them. I haven't yet run such a thing on the CFE :)

More specifically:

- Within a block, iterations must be independent. A loop where each iteration reads the one before (b[i] = b[i-1] + 3) stays an ordinary loop.

- Reductions are the one cross-tile dependency it handles. Each tile, on whatever device, produces a partial sum, min or max, and the runtime combines them. That's what the :reduce(+ total) does above.

- The scheduler sees the topology, not the workers. It splits a block into tiles and hands them out by each device's measured speed, local or remote. Each worker sees only its tiles plus the slices of input those tiles read.

- For streaming, two blocks in sequence works. Each block finishes on every device before the next statement runs, so the second can safely read the first's output. With CUDA residency, data the CPU hasn't touched in between isn't re-sent.

One thing I'm not trying to do is cover all possible cases automatically - that way lies unbounded complexity, and I'm a fan of simple code working well with low cognitive load. xc will work well automatically for non-self-dependent data, and allow you to work far more easily with self-dependent data.


I appreciate the time you took to reply to me.

Thank you!


I like it! The Rust crew would love this I bet.

Do you think they are actually shipping anything useful any faster? Muse is pretty impressive. I’m not seeing radical progress otherwise

I noticed a few weeks ago it started being very bad at explaining things (even things itself was doing) and started committing absurd errors (like reading a test of 5 lines and not noticing there was an explicit mock created in one of those, then saying that the test was failing while it was not)

I fear this is just the classic "nerf the model just before we release a new version of it"


This seems a worsening that seems to have started at Opus 4.8. When I (was forced to) switched from 4.7 to 4.7, I noticed that 4.8 had a very strong bias against viewing tool output or reading files. It ALWAYS wanted to 'grep' things. So for example, it would run the test suite and grep for 'PASS', thus completely missing the 4 tests that FAILed. Its bias is so strong, that it does this despite explicit instructions to the contrary, and continues to do so even after having noticed its own mistake, in the same (claude code) session.

For editing files, it again seems to prefer writing small python scripts, rather than read the file and rewrite it (even small files, like notes). This again causes it to constantly miss duplications, inconsistencies, etc.

And from 4.8 to 5, it doubled down on this. At this point not moderately-long-horizon task is getting done consistently, due to its pigeon-hole view of the workdir.

Anybody else notice this?


oh yes, exactly the same things are happening to me


Guidelines | FAQ | Lists | API | Security | DMCA | Apply to YC | Contact

Search: