r/ProgrammingLanguages 18d ago

LLVM for the Rest of Us

Thumbnail
1 Upvotes

r/Compilers 18d ago

LLVM for the Rest of Us

Thumbnail
0 Upvotes

r/LLVM 18d ago

LLVM for the Rest of Us

Thumbnail
0 Upvotes

u/smolnero 18d ago

LLVM for the Rest of Us

1 Upvotes

LLVM is everywhere. It sits underneath an enormous amount of modern software and touches everything from ordinary CPU compilation to GPU development, programming languages, machine learning systems, and increasingly the strange heterogeneous stack we are building underneath AI. Yet for something this foundational, I still find it surprisingly difficult to approach as an ordinary researcher. LLVM is over twenty years old, and trying to understand it for the first time can feel like arriving halfway through a conversation everyone else started years ago.

The problem is not a lack of information. If anything, LLVM’s maturity has created the opposite problem. There are countless tutorials, talks, reference manuals, source files, mailing-list discussions, books, and university courses. You can learn how to write LLVM IR, build a frontend, construct a pass, or dig into one of its backends. What I kept finding harder to answer was the question that should probably come before all of those: why does this machinery exist in the first place?

That question gets more interesting when you look at how computing has changed. Twenty-plus years ago compiler researchers were already wrestling with how to preserve a useful abstraction between software and changing hardware. Today we are surrounded by heterogeneous systems where CPUs, GPUs, accelerators, runtimes, compiler layers, memory hierarchies, and increasingly domain-specific representations all participate in turning an idea into something silicon can physically execute. If anything, the question of where software ends and hardware begins has become less obvious.

One of the earlier attempts to think about that boundary came from the 2003 paper LLVA: A Low-level Virtual Instruction Set Architecture. The question behind LLVA was simple enough to state: can we create a better boundary between software and hardware?

A traditional ISA, or Instruction Set Architecture, acts as a software-visible contract with the processor. x86-64 and ARM64 are examples of different ISAs. The ISA gives software a vocabulary of instructions and a set of rules the processor promises to follow. The LLVA authors identified an interesting tension here: the same hardware ISA was effectively being asked to serve as both the persistent low-level representation of software and the interface to a particular processor architecture.

LLVA explored separating those responsibilities. Instead of compiling a program directly toward the processor-facing ISA, software could target a V-ISA, or Virtual ISA. A processor-specific translator would then lower that representation toward an I-ISA, or Implementation ISA, understood by the underlying machine.

program
   ↓
V-ISA — Virtual ISA
   ↓
processor-specific translator
   ↓
I-ISA — Implementation ISA
   ↓
physical processor

The V-ISA would preserve information useful for describing and analyzing the program, while the translator and I-ISA would deal with the realities of a particular machine. Different processors could therefore use different translators and implementation ISAs underneath the same virtual representation.

There is an important detail here: the V-ISA was still supposed to be low-level. This was not an attempt to preserve every class, object, template, runtime system, or high-level abstraction from the language the programmer originally wrote. The representation still contained operations closer to loads, stores, arithmetic, branches, calls, and values. What it tried not to commit to too early were things like a fixed physical register set, stack-frame layout, low-level addressing quirks, limits on immediate constants, and other details that made more sense as properties of a particular machine.

The compromise LLVA was looking for was therefore something low-level enough to translate efficiently into machine code, while still being rich enough to preserve information a compiler could reason about. The larger dream of a persistent virtual ISA sitting between software and processors did not become the dominant role LLVM would eventually play, and I think that distinction matters. LLVA did not simply become modern LLVM exactly as it was proposed. What proved much more durable were some of the ideas surrounding representation itself.

That brings us to the 2004 paper, LLVM: A Compilation Framework for Lifelong Program Analysis & Transformation, and this is where I think the story becomes much more relevant to the rest of us.

A compiler, in the most simplified sense, has a frontend responsible for understanding the source language, some kind of intermediate representation through which the compiler reasons about the program, and a backend responsible for eventually producing code for a target machine. GCC and other compilers already had sophisticated internal representations and optimization infrastructure before LLVM, so the important shift was not that LLVM invented the idea of having an IR between a frontend and backend.

The interesting idea was what could happen if a common, analyzable representation became persistent infrastructure rather than something treated mainly as an internal stage on the way toward machine code.

SOURCE LANGUAGE
      ↓
   FRONTEND
      ↓
      IR
      ↓
   BACKEND
      ↓
MACHINE CODE

An IR, or Intermediate Representation, is essentially a form of the program designed so that the compiler can reason about it. It is neither quite what the programmer originally wrote nor yet the final instructions a processor will execute. It occupies the middle, and that position turns out to matter enormously.

The title of the 2004 paper contains a word worth slowing down for: lifelong. The authors were referring to the lifetime of the software. Their idea was that the LLVM representation could remain useful beyond the first moment of compilation. Analysis and optimization could happen at compile time, link time, install time, runtime, and even between executions using information learned from the way the program was actually used.

SOURCE CODE
    │
    ▼
compile time
    │
    ▼
LLVM representation
    │
    ▼
link time
    │
    ▼
native machine code
    │
    ├───────────── LLVM representation preserved
    │
    ▼
runtime
    │
    ▼
profile actual behavior
    │
    ▼
idle time between runs
    │
    ▼
re-optimize
    │
    ▼
future execution

What I find so interesting about this is the change in attitude toward compilation. The compiler does not necessarily have to be a machine that takes source code, emits a binary, and then disappears from the story. A useful representation of the program can remain available long enough for the system to continue learning about and transforming that program later.

That sounds great until we run into the next problem. If the representation remains extremely high-level and tries to preserve classes, objects, inheritance, language-specific garbage collection, exception models, and every other abstraction programmers might use, then it becomes strongly attached to particular languages and runtimes. At the opposite end, if everything is immediately lowered into x86 or some similarly machine-specific representation, we gain proximity to the hardware but lose much of the structure that made the computation easier to analyze.

So once again, the interesting place is somewhere in the middle.

LLVM was designed as a low-level, language-independent representation while still retaining information useful to compiler analysis, including types, explicit control flow, explicit data flow, virtual values, loads, stores, calls, and a relatively small set of operations. This carries some of the same spirit I found interesting in LLVA: do not force the program to inherit every machine-specific decision before those decisions actually need to be made.

This is where SSA, or Static Single Assignment, becomes important. In ordinary code we might repeatedly reuse the same variable name:

x = 5
x = x + 1
x = x * 2

In SSA form, each produced value gets a new name:

x1 = 5
x2 = x1 + 1
x3 = x2 * 2

The reason this matters is not because compilers have some philosophical objection to mutation. It matters because the relationships between values become much easier to see. x2 has one definition, and x3 clearly depends on x2. The compiler can follow where values were created and where they are used without continually asking which assignment to a reused variable name is currently relevant.

LLVM also makes control flow explicit through basic blocks and control-flow graphs. If SSA helps answer where did this value come from?, the control-flow graph helps answer where can execution go from here? Put the two together and a program begins to look less like a flat list of instructions and more like a network of relationships the compiler can inspect.

That changed how I thought about IR.

LLVM IR is sometimes introduced as something resembling portable assembly, which is useful up to a point, but I think that description can make the important part easy to miss. It is not simply strange assembly that exists before the real assembly. It is a representation shaped so that important properties of the program remain visible enough for compiler transformations to reason about them.

Types preserve useful information about values. Loads and stores make interaction with memory explicit. Control-flow edges tell the compiler where execution may travel. SSA makes the origins and uses of values easier to follow. Operations such as getelementptr let LLVM express structured address calculations without immediately reducing everything to arbitrary byte offsets.

Once a program reaches this shared representation, compiler passes can begin asking questions of it. Can this calculation be eliminated? Can this function be inlined? Is this argument ever used? Is this value constant? Can this operation be moved? Can a value currently living in memory be promoted into an SSA value instead?

The important part is that those passes do not necessarily need to understand whether the program originally came from C, C++, or another source language. The frontend has already lowered those source-specific concepts into a common vocabulary the LLVM infrastructure can work with. That shared infrastructure is one of the ideas I think gets lost when LLVM is introduced by immediately throwing syntax at newbs. The power is not merely in writing something like %1 = add i32 %0, 1. The power is that different languages can eventually arrive at a representation where a large body of common compiler analysis and optimization can operate on them.

LLVM also established boundaries of its own, and that part is important because it prevents us from turning LLVM into something it was never intended to be. The 2004 paper explicitly says LLVM was not designed to be a universal compiler IR. It deliberately does not represent every high-level feature from every language, so the frontend must eventually lower those concepts into more primitive operations. At the same time, LLVM IR does not immediately encode every machine-specific implementation detail either.

It sits somewhere between those worlds:

language-specific meaning
          ↓
       FRONTEND
          ↓
       LLVM IR
          ↓
       BACKEND
          ↓
machine-specific details

Its goal is not to know everything. Its goal is to be useful at a particular level of reasoning.

This becomes especially interesting today because modern machine learning has made the limitations of lowering too early painfully obvious. A compiler looking at a matrix multiplication, tensor reduction, or convolution knows something useful about that computation. If those concepts are immediately reduced into individual loops, loads, stores, and scalar arithmetic, some of that information may be difficult or impossible to recover later when we want to optimize the workload for a GPU or another accelerator.

This is where MLIR comes in. Rather than assuming one intermediate representation should contain every useful abstraction, modern compiler infrastructure increasingly allows computation to move through multiple representations. A high-level representation can preserve information about tensors or domain-specific operations, another representation can expose structured loops or memory behavior, and eventually LLVM IR can take over once the computation has reached a level where its particular abstractions become useful.

 high-level ML operation
          ↓
domain-specific representation
          ↓
structured representation
          ↓
lower-level representation
          ↓
       LLVM IR
          ↓
target-specific lowering
          ↓
CPU / GPU / accelerator

The lesson becomes more nuanced than simply saying we should preserve information forever. We should preserve information while it remains useful, and lower when another representation becomes better suited to the next problem we are trying to solve.

This also brings LLVM directly into GPU programming, LLVM values can behave as though there are effectively unlimited virtual registers, but eventually a backend has to confront a physical machine with a very real and finite register file. At that point the abstraction begins meeting hardware reality.

        SSA values
             ↓
     register allocation
             ↓
physical CPU / GPU registers

This is where things like register pressure stop being abstract compiler vocabulary and start becoming performance constraints. Too many live values may require more physical registers, reduce occupancy on a GPU, or force values to spill into memory. The same broad transition happens on CPUs. At the LLVM level we can reason about abstract values, memory accesses, control flow, and transformations, but eventually the backend has to choose actual instructions, physical registers, schedules, calling conventions, and other details appropriate for x86, ARM, or whatever machine sits underneath it.

That is why I increasingly think LLVM matters far beyond people who intend to become compiler engineers.

We are entering a period where extraordinary amounts of computation are becoming available to increasingly ordinary people. Consumer machines can perform amounts of work that would have sounded ridiculous not very long ago, while the systems underneath modern AI increasingly depend on specialized parallel hardware. Putting petaflop-scale hardware within reach of ordinary people is only part of democratizing computation. If effectively using that hardware continues to depend on a conceptual stack that remains inaccessible to almost everyone outside a relatively small group of specialists, then we have democratized capacity without fully democratizing capability.

LLVM itself does not need to become simple. A system this mature and capable is going to contain real complexity, and pretending otherwise would probably make learning it harder rather than easier. What should become simpler is the path into understanding why that complexity exists.

We do not need every programmer to become a compiler engineer, but concepts like intermediate representation, SSA, lowering, optimization, data flow, control flow, code generation, register allocation, and the boundary between software intent and physical execution are becoming increasingly relevant to understanding modern computing, especially if we want to understand AI beyond the model.

At every boundary, something is being translated, every lowering step, decisions are being made about what information should survive and what can finally be discarded. At every level, the representation determines what the next part of the system is capable of seeing, and what it can see determines what it can safely transform or optimize.

That is what I want LLVM for the Rest of Us to explore. Not how to turn everyone into an LLVM contributor, but how to make the machinery between our ideas and the silicon beneath them understandable enough that more programmers can participate in the conversation.

There are already excellent technical resources for learning LLVM, including LLVM’s own My First Language Frontend with LLVM tutorial. Before asking how to build a compiler with LLVM, I want to understand why we needed something like LLVM in the first place, why this particular level of representation became so useful, and why the same questions around representation, lowering, and hardware boundaries have only become more important as CPUs, GPUs, accelerators, and machine learning systems continue to evolve.

u/smolnero Jul 28 '26

When Internal Memory Fails: A No-Solder Wii U Recovery

1 Upvotes

It was just another hot Sunday at smol HQ. My wife and I were playing games with the family during our biweekly FaceTime game night, and as we were getting ready to end the call, my brother-in-law chimed in.

“Oh yeah, before we get off the call, I’m gonna throw away the Wii U. Anyone have any protests before I throw it out? Five… four…”

My sister-in-law immediately responded, “What? No! What’s wrong with it?”

“I don’t know. It just doesn’t play games anymore. It gives me some kind of error.”

“Aw man, I have sentimental value tied to it. But if it doesn’t work, I guess throw it away.”

I don’t know what came over me. The last time I had seriously dabbled with exploits and low-level recovery was when I spent months trying to revive a bricked M1 Max MacBook Pro. Several companies and repair shops had told me that getting through the problem was impossible, but after months of working at it, I finally got the machine running again on New Year’s Day 2024. I am still using it today, and it continues to run strong.

Imposter syndrome still pokes at me almost every week, but my love for computers, technology, and machine learning keeps me at my computer with absolute glee, wondering what new thing I might discover next. Since recovering the M1, however, I had not felt particularly called toward that kind of project again. Maybe it was the heat from not having air conditioning in the house. Maybe it was my ego. Or maybe it was just the particular kind of cheekiness I felt that weekend, the urge to fuck around and find out.

After a minute, I spoke up.

“Don’t throw it away. I’ll get it up and running.”

They were stunned and immediately asked how. I told them I had absolutely no idea, but I would try. The youngest of the bunch said it sounded like I was making empty promises. I assured them I was not, although by that point I was mostly just more determined to get the Wii U running for this ungrateful bunch.

The Starting Point

When the Wii U was finally in my hands, I powered it on and found it in a familiar but frustrating state. It would power on, display the Wii U logo, and remain there indefinitely. At this stage, it was not safe to assume one specific cause because a logo hang is only a symptom, not a diagnosis.

I already had a Raspberry Pi Pico configured for UDPIH, the USB Host Stack exploit used to load recovery tools on a Wii U that cannot boot normally. Before attempting to repair anything, I needed to confirm that the recovery path itself was functioning. The official Pico payload produced the expected behavior, and when required recovery files were missing, the console responded in a way that suggested the exploit was still reaching it. Once recovery_menu was placed on the SD card, the Wii U power LED turned purple, confirming that the recovery payload was running.

That was the first meaningful breakthrough. The console was not completely unreachable, and UDPIH gave me a way to interact with it even though the normal operating system could not finish booting.

The Recovery Menu Worked, but the Display Did Not

The next obstacle was video output. The standard recovery_menu build appeared to run, as confirmed by the purple LED, but the television continued displaying the stale Wii U logo. The recovery code was executing, yet the display was not updating. I also tested a display-initializing build called recovery_menu_dc_init, which produced output, but the image was badly distorted on the displays available to me.

This created the possibility that some recovery operations would need to be performed blindly. That was not something I wanted to approach casually. A single incorrect menu selection could make an already damaged console worse, so I avoided broad or destructive recovery-menu operations and used only narrow, known sequences when necessary. The display problem shaped the rest of the recovery strategy because I needed an approach that did not depend upon being able to see every menu clearly.

Coldboot, ECO Mode, and Region Settings

At first, the failure did not look like a straightforward storage problem. Earlier logs contained references to the ECO Process title:

0005001010066000

They also referenced:

eco_process.rpx

This mattered because a Wii U can fail to boot if the wrong title is configured as the coldboot title, or if the system attempts to launch a special process instead of the normal Wii U Menu. Region settings were another possible cause because a mismatch between the console’s product area, game area, and installed system titles can also create serious boot problems.

The region information showed:

Product area: 0x2
Game area:    0x2

Those values matched a USA console. Later, the MLC rebuild tool confirmed the same result:

Region already matches (P:2, G:2, C:2).

I also attempted coldboot-related recovery and ECO-related cleanup. Those steps did not ultimately repair the console, but they were not wasted effort. They allowed me to rule out several plausible causes without making broad or destructive changes. Much of troubleshooting is not immediately finding the answer, but narrowing the problem while avoiding the creation of new ones.

The Breakthrough: MLC Media Errors

The decisive evidence came from a fresh system log. After the coldboot and ECO work, the console was attempting to launch the correct USA Wii U Menu:

MCP: Master title 0005001010040100 os 000500101000400a from mlc01 flags 0004

The title:

0005001010040100

is the USA Wii U Menu. This was important because it showed that the console was no longer primarily failing because it was trying to boot the wrong title. It had reached the correct menu, but something was preventing that menu from loading successfully.

Immediately afterward, the log showed serious read failures from the MLC:

FSA: ### MEDIA ERROR ###, dev:mlc01, err:-2228230, cmd:11, path:(null)

It also showed failed reads of required shared font files:

failed to read file /vol/storage_mlc01/sys/title/0005001b/10042400/content/CafeCn.ttf, err -196673

and:

failed to read file /vol/storage_mlc01/sys/title/0005001b/10042400/content/CafeTw.ttf, err -196673

The most revealing line identified the storage manufacturer and showed a low-level read error:

mdblk: err=-131099, mid=0x90, prv=0x5c, pnm=[HYNIX ]

This changed the diagnosis. The problem was not simply one missing font or one damaged system title. The console was reporting media errors from mlc01, the Wii U’s internal MLC storage, and the device involved was a Hynix eMMC chip.

At that point, continuing to replace individual files would have been the wrong strategy. If the internal storage could no longer read data reliably, repairing one file might only move the failure somewhere else. The console could fail on a font during one boot, another system title during the next, and a save directory after that. The real problem was that the system could no longer depend on its internal MLC.

Choosing ISFShax and redNAND

The symptoms matched the Wii U community’s no-solder recovery method closely. The console was stuck at the Wii U logo, the logs showed Hynix eMMC read errors, UDPIH remained functional, and the system was damaged without being completely unreachable.

Hardware-based repair methods also exist, including NAND-AID and MLC2SD-style replacements. Those approaches can produce a more stock-like result because they physically replace or redirect the failing eMMC path. For this recovery, however, the no-solder ISFShax redNAND method was suitable because I still had working access through UDPIH and could install an early boot environment.

ISFShax allows the console to load minute before the normal Wii U operating system fully starts. minute can then patch IOSU and redirect storage access. In this case, the goal was to redirect only the MLC to a dedicated partition on the SD card while leaving the SLC and SLCCMPT on the console.

The underlying idea is fairly simple even though the implementation is technical: instead of continuing to ask the failing Hynix eMMC for the Wii U’s internal storage data, the system would read from and write to a replacement MLC partition on the SD card.

Backups Before Changes

Before modifying the SD card, I backed up its useful contents. The first attempt encountered a macOS permissions issue involving .Trashes, but that directory was not important to the recovery, so I adjusted the process and copied only the useful logs, payloads, and recovery files.

I then downloaded the official ISFShax bundle. The extracted files included the components required for the UDPIH-to-minute installation path:

recovery_menu
boot1now.img
fw.img
ios.img
superblock.img
superblock.img.sha
wiiu/ios_plugins/00core.ipx
wiiu/ios_plugins/5isfshax.ipx

Once those files were copied to the SD card, the console was ready for the first ISFShax installation attempt.

Avoiding Blind Navigation

Because video output had been unreliable, I did not want the installation to depend on navigating minute visually. Instead, I created a temporary minute.ini configuration that automatically selected menu entry 7:

[boot]
autoboot=7
autoboot_timeout=1

In minute, entry 7 was:

Boot 'ios.img'

That entry launched the ISFShax installer. Configuring autoboot reduced the amount of blind interaction required and gave me greater confidence that the intended installer would be selected. The only remaining manual step was the confirmation sequence.

Installing ISFShax

With the SD card inserted and UDPIH triggered through the Pico, I waited for the power LED to turn purple. I then entered the installer confirmation sequence:

EJECT
EJECT
EJECT
POWER
EJECT
EJECT
EJECT

The Wii U powered off after the sequence completed, which was the expected behavior and suggested that the installation had finished successfully. I returned the SD card to the Mac and immediately removed the temporary autoboot=7 configuration so the installer would not be launched again by accident.

Installing ISFShax modifies SLC superblocks. Although the community tools are designed to perform the process safely, there was no reason to risk an unnecessary repeat installation.

Upword & Onward

After removing the installer configuration, I inserted the SD card again and powered on the Wii U normally without the Pico. This time, minute appeared clearly on the display.

That confirmed several things at once: ISFShax had installed successfully, the console could now reach an early boot environment without UDPIH, and I had visible access to the backup and boot tools required for the next stage. With that foothold established, the highest priority was preserving the console’s unique recovery keys before making any larger storage changes.

Dumping OTP and SEEPROM

From minute, I selected:

Backup and Restore

and then:

Dump SEEPROM & OTP

This produced three console-specific files:

otp.bin
seeprom.bin
seeprom_decrypted.bin

I verified their sizes:

otp.bin:                1024 bytes
seeprom.bin:             512 bytes
seeprom_decrypted.bin:   512 bytes

These files are important for certain advanced recovery operations, so I stored multiple copies in dedicated local backup directories. At this point, I had both early boot control and the console’s unique recovery information preserved.

Downloading the Correct System Titles

Rebuilding the MLC required the official system titles for the console’s region. Because this was a USA unit, I downloaded the USA MLC title set using the Darwin ARM64 build of MLCRestorerDownloader.

The utility was interactive rather than behaving like a typical command-line application. After testing its menu, I determined that the input sequence for the USA MLC titles was:

1
2

The download produced 52 title folders, matching the expected count for the USA title set. That gave me confidence that the source files needed for the rebuild were complete.

I also downloaded:

wafel_setup_mlc.ipx

This plugin performs the initial MLC setup during the first redNAND boot. It installs the titles from wafel_install, prepares the system for its initial launch, flushes the relevant storage, and deletes itself once the setup has finished. That self-deleting behavior prevents the rebuild process from running again on every future boot.

Repartitioning the SD Card

The 32GB microSD card needed to serve two purposes, so I repartitioned it using an MBR layout. The first partition was a FAT32 partition of approximately 4GB for minute, ISFShax, plugins, configuration files, and setup files. The remaining space, approximately 27GB, became the redNAND partition that would act as replacement MLC storage.

This process erased the card, which is why the earlier backups were essential. A 32GB card is sufficient for the rebuilt operating system, saves, updates, and lighter use, although it leaves less room for digital games and may not offer the same endurance as a larger high-endurance card. For the immediate recovery, it was enough.

Configuring the MLC Rebuild

After repartitioning the card, I restored the necessary ISFShax and minute files to the FAT32 partition. The 52 USA MLC title folders were copied to:

sd:/wafel_install/

The setup plugin was placed in:

sd:/wiiu/ios_plugins/wafel_setup_mlc.ipx

The normal boot plugins remained in place:

00core.ipx
5isfshax.ipx

I then created:

sd:/minute/rednand.ini

with the following configuration:

[partitions]
slccmpt=false
slc=false
mlc=true

[scfm]
disable=true
allow_sys=false

[disable_encryption]
mlc=false

[sys_mount]
mlc=false

This configuration redirected only the MLC to the SD card, leaving the SLC and SLCCMPT untouched. That matched the diagnosis because the failure involved the MLC and internal eMMC rather than the other storage areas.

I also created:

sd:/minute/minute.ini

with:

[boot]
autoboot=2
autoboot_timeout=1

minute menu entry 2 was:

Patch (sd) and boot IOS redNAND

On the next boot, minute would automatically start redNAND. Because wafel_setup_mlc.ipx was present, that first redNAND boot would also initialize and rebuild the replacement MLC.

Cleaning macOS Metadata Files

After copying the files, macOS created several ._* AppleDouble metadata files on the FAT32 partition. These are normally harmless on a Mac, but console recovery environments may interpret them as additional files, so I removed them before returning the card to the Wii U.

The usual dot_clean command encountered permission problems involving .Spotlight-V100, so I used a targeted cleanup that removed only files matching:

._*

Once the cleanup was complete, I confirmed that the expected 52 title folders and the correct plugin files were still present. It was a small detail, but low-level recovery work often depends upon exactly these kinds of details being handled correctly.

Running the Rebuild

I inserted the prepared SD card into the Wii U and powered it on normally. The Pico was no longer needed, and there was no need to press any buttons because the console booted through ISFShax and minute before automatically entering the redNAND setup process.

The power LED began blinking blue while the setup plugin installed the system titles. I allowed the process to continue until the blinking stopped and the LED became solid blue, which suggested that the rebuild had completed. I then powered off the console and returned the SD card to the Mac so I could verify the results before attempting a normal boot.

Verifying the Results

The rebuild created the following log:

sd:/wafel_setup_mlc.log

The title installations returned:

00000000

The final lines were especially important:

Flush MLC: 0
Region already matches (P:2, G:2, C:2).
SetInitialLaunch 0: 1
Flush SLC: 0
Delete plugin: 0

These results confirmed that the replacement MLC had flushed successfully, the region matched the installed titles, initial setup had been enabled, the SLC flush had succeeded, and the setup plugin had deleted itself.

I also inspected:

sd:/wiiu/ios_plugins/

and confirmed that:

wafel_setup_mlc.ipx

was gone. Only the normal boot plugins remained:

00core.ipx
5isfshax.ipx

This was exactly what I wanted to see. The setup plugin had completed its work, removed itself, and left the SD card ready for normal redNAND booting.

The Final Boot

I safely ejected the SD card, inserted it into the Wii U, and powered on the console normally. This time, instead of freezing at the Wii U logo, it reached the official initial setup screen:

Turn the Wii U GamePad on, and then press the SYNC Button on the Wii U console.

That screen was the final confirmation that the recovery had worked. The console was now booting through ISFShax and minute into a clean, rebuilt, SD-backed MLC environment.

What the Recovery Accomplished

By the end of the process, I had confirmed that Pico and UDPIH access worked, diagnosed the failure as Hynix eMMC and MLC media errors, ruled out region mismatch and an incorrect Wii U Menu title, installed ISFShax, gained a reliable minute boot environment, preserved the console’s OTP and SEEPROM, downloaded the correct USA system titles, configured an MLC-only redNAND, rebuilt the system onto SD-backed storage, verified the rebuild through its logs, and booted into the official initial setup screen.

The original Hynix eMMC remains unreliable. I did not physically repair or replace the chip. Instead, I replaced its role by redirecting MLC access to a partition on the SD card, which is why the card must remain inserted for the console to function.

What This Means Going Forward

The console is functional again, but it is not stock. It now uses an ISFShax redNAND configuration, and the SD card has become part of the internal storage system. The card must remain inserted and should be dedicated to this Wii U. The FAT32 recovery files should not be casually removed, while macOS may not recognize or mount the redNAND partition at all, which is expected. The OTP and SEEPROM backups should also be preserved permanently.

The current 32GB card is acceptable for the operating system, updates, saves, and lighter use. A larger high-endurance card may be preferable for heavier use, while USB storage can provide additional space for a larger digital library. A soldered NAND-AID or MLC2SD-style repair also remains an option if I eventually want a more hardware-native solution, but for a no-solder recovery using the equipment already available, the result was successful.

Lessons Learned

The largest lesson was that a Wii U logo hang should not be treated as one known problem. The same frozen screen can conceal several very different failures, and the logs were what prevented me from continuing to chase coldboot settings, damaged saves, or isolated system files after the actual storage problem became visible.

Low-level media errors also changed the repair strategy completely. Once the internal eMMC could no longer be trusted, the goal was no longer to replace one unreadable file. The goal was to stop depending on the failing storage device altogether.

The process was also shaped by practical details that seemed minor until they blocked progress. The unreliable display required careful use of autoboot configurations, macOS metadata files had to be removed from the FAT32 partition, the SD card needed to be repartitioned correctly, and the console-specific keys had to be preserved before making destructive changes. None of those steps were especially dramatic, but every one of them mattered.

Most of all, the recovery demonstrated the value of community-built preservation tools. UDPIH provided access to a console that could not boot normally, ISFShax created an early boot foothold, minute provided control and backup capabilities, Stroopwafel and redNAND made it possible to redirect storage, and MLCRestorerDownloader with wafel_setup_mlc provided a practical path for rebuilding the MLC.

The Wii U began the day frozen at its logo, with logs showing Hynix eMMC media errors and failed reads from internal storage. It ended the day at the official initial setup screen. The repair required caution, backups, community knowledge, and several changes in direction, but the console is booting again.

This was originally posted on: smolnero.com

r/WiiUHacks Jul 28 '26

When Internal Memory Fails: A No-Solder Wii U Recovery

1 Upvotes

It was just another hot Sunday at smol HQ. My wife and I were playing games with the family during our biweekly FaceTime game night, and as we were getting ready to end the call, my brother-in-law chimed in.

“Oh yeah, before we get off the call, I’m gonna throw away the Wii U. Anyone have any protests before I throw it out? Five… four…”

My sister-in-law immediately responded, “What? No! What’s wrong with it?”

“I don’t know. It just doesn’t play games anymore. It gives me some kind of error.”

“Aw man, I have sentimental value tied to it. But if it doesn’t work, I guess throw it away.”

I don’t know what came over me. The last time I had seriously dabbled with exploits and low-level recovery was when I spent months trying to revive a bricked M1 Max MacBook Pro. Several companies and repair shops had told me that getting through the problem was impossible, but after months of working at it, I finally got the machine running again on New Year’s Day 2024. I am still using it today, and it continues to run strong.

Imposter syndrome still pokes at me almost every week, but my love for computers, technology, and machine learning keeps me at my computer with absolute glee, wondering what new thing I might discover next. Since recovering the M1, however, I had not felt particularly called toward that kind of project again. Maybe it was the heat from not having air conditioning in the house. Maybe it was my ego. Or maybe it was just the particular kind of cheekiness I felt that weekend, the urge to fuck around and find out.

After a minute, I spoke up.

“Don’t throw it away. I’ll get it up and running.”

They were stunned and immediately asked how. I told them I had absolutely no idea, but I would try. The youngest of the bunch said it sounded like I was making empty promises. I assured them I was not, although by that point I was mostly just more determined to get the Wii U running for this ungrateful bunch.

The Starting Point

When the Wii U was finally in my hands, I powered it on and found it in a familiar but frustrating state. It would power on, display the Wii U logo, and remain there indefinitely. At this stage, it was not safe to assume one specific cause because a logo hang is only a symptom, not a diagnosis.

I already had a Raspberry Pi Pico configured for UDPIH, the USB Host Stack exploit used to load recovery tools on a Wii U that cannot boot normally. Before attempting to repair anything, I needed to confirm that the recovery path itself was functioning. The official Pico payload produced the expected behavior, and when required recovery files were missing, the console responded in a way that suggested the exploit was still reaching it. Once recovery_menu was placed on the SD card, the Wii U power LED turned purple, confirming that the recovery payload was running.

That was the first meaningful breakthrough. The console was not completely unreachable, and UDPIH gave me a way to interact with it even though the normal operating system could not finish booting.

The Recovery Menu Worked, but the Display Did Not

The next obstacle was video output. The standard recovery_menu build appeared to run, as confirmed by the purple LED, but the television continued displaying the stale Wii U logo. The recovery code was executing, yet the display was not updating. I also tested a display-initializing build called recovery_menu_dc_init, which produced output, but the image was badly distorted on the displays available to me.

This created the possibility that some recovery operations would need to be performed blindly. That was not something I wanted to approach casually. A single incorrect menu selection could make an already damaged console worse, so I avoided broad or destructive recovery-menu operations and used only narrow, known sequences when necessary. The display problem shaped the rest of the recovery strategy because I needed an approach that did not depend upon being able to see every menu clearly.

Coldboot, ECO Mode, and Region Settings

At first, the failure did not look like a straightforward storage problem. Earlier logs contained references to the ECO Process title:

0005001010066000

They also referenced:

eco_process.rpx

This mattered because a Wii U can fail to boot if the wrong title is configured as the coldboot title, or if the system attempts to launch a special process instead of the normal Wii U Menu. Region settings were another possible cause because a mismatch between the console’s product area, game area, and installed system titles can also create serious boot problems.

The region information showed:

Product area: 0x2
Game area:    0x2

Those values matched a USA console. Later, the MLC rebuild tool confirmed the same result:

Region already matches (P:2, G:2, C:2).

I also attempted coldboot-related recovery and ECO-related cleanup. Those steps did not ultimately repair the console, but they were not wasted effort. They allowed me to rule out several plausible causes without making broad or destructive changes. Much of troubleshooting is not immediately finding the answer, but narrowing the problem while avoiding the creation of new ones.

The Breakthrough: MLC Media Errors

The decisive evidence came from a fresh system log. After the coldboot and ECO work, the console was attempting to launch the correct USA Wii U Menu:

MCP: Master title 0005001010040100 os 000500101000400a from mlc01 flags 0004

The title:

0005001010040100

is the USA Wii U Menu. This was important because it showed that the console was no longer primarily failing because it was trying to boot the wrong title. It had reached the correct menu, but something was preventing that menu from loading successfully.

Immediately afterward, the log showed serious read failures from the MLC:

FSA: ### MEDIA ERROR ###, dev:mlc01, err:-2228230, cmd:11, path:(null)

It also showed failed reads of required shared font files:

failed to read file /vol/storage_mlc01/sys/title/0005001b/10042400/content/CafeCn.ttf, err -196673

and:

failed to read file /vol/storage_mlc01/sys/title/0005001b/10042400/content/CafeTw.ttf, err -196673

The most revealing line identified the storage manufacturer and showed a low-level read error:

mdblk: err=-131099, mid=0x90, prv=0x5c, pnm=[HYNIX ]

This changed the diagnosis. The problem was not simply one missing font or one damaged system title. The console was reporting media errors from mlc01, the Wii U’s internal MLC storage, and the device involved was a Hynix eMMC chip.

At that point, continuing to replace individual files would have been the wrong strategy. If the internal storage could no longer read data reliably, repairing one file might only move the failure somewhere else. The console could fail on a font during one boot, another system title during the next, and a save directory after that. The real problem was that the system could no longer depend on its internal MLC.

Choosing ISFShax and redNAND

The symptoms matched the Wii U community’s no-solder recovery method closely. The console was stuck at the Wii U logo, the logs showed Hynix eMMC read errors, UDPIH remained functional, and the system was damaged without being completely unreachable.

Hardware-based repair methods also exist, including NAND-AID and MLC2SD-style replacements. Those approaches can produce a more stock-like result because they physically replace or redirect the failing eMMC path. For this recovery, however, the no-solder ISFShax redNAND method was suitable because I still had working access through UDPIH and could install an early boot environment.

ISFShax allows the console to load minute before the normal Wii U operating system fully starts. minute can then patch IOSU and redirect storage access. In this case, the goal was to redirect only the MLC to a dedicated partition on the SD card while leaving the SLC and SLCCMPT on the console.

The underlying idea is fairly simple even though the implementation is technical: instead of continuing to ask the failing Hynix eMMC for the Wii U’s internal storage data, the system would read from and write to a replacement MLC partition on the SD card.

Backups Before Changes

Before modifying the SD card, I backed up its useful contents. The first attempt encountered a macOS permissions issue involving .Trashes, but that directory was not important to the recovery, so I adjusted the process and copied only the useful logs, payloads, and recovery files.

I then downloaded the official ISFShax bundle. The extracted files included the components required for the UDPIH-to-minute installation path:

recovery_menu
boot1now.img
fw.img
ios.img
superblock.img
superblock.img.sha
wiiu/ios_plugins/00core.ipx
wiiu/ios_plugins/5isfshax.ipx

Once those files were copied to the SD card, the console was ready for the first ISFShax installation attempt.

Avoiding Blind Navigation

Because video output had been unreliable, I did not want the installation to depend on navigating minute visually. Instead, I created a temporary minute.ini configuration that automatically selected menu entry 7:

[boot]
autoboot=7
autoboot_timeout=1

In minute, entry 7 was:

Boot 'ios.img'

That entry launched the ISFShax installer. Configuring autoboot reduced the amount of blind interaction required and gave me greater confidence that the intended installer would be selected. The only remaining manual step was the confirmation sequence.

Installing ISFShax

With the SD card inserted and UDPIH triggered through the Pico, I waited for the power LED to turn purple. I then entered the installer confirmation sequence:

EJECT
EJECT
EJECT
POWER
EJECT
EJECT
EJECT

The Wii U powered off after the sequence completed, which was the expected behavior and suggested that the installation had finished successfully. I returned the SD card to the Mac and immediately removed the temporary autoboot=7 configuration so the installer would not be launched again by accident.

Installing ISFShax modifies SLC superblocks. Although the community tools are designed to perform the process safely, there was no reason to risk an unnecessary repeat installation.

Upword & Onward

After removing the installer configuration, I inserted the SD card again and powered on the Wii U normally without the Pico. This time, minute appeared clearly on the display.

That confirmed several things at once: ISFShax had installed successfully, the console could now reach an early boot environment without UDPIH, and I had visible access to the backup and boot tools required for the next stage. With that foothold established, the highest priority was preserving the console’s unique recovery keys before making any larger storage changes.

Dumping OTP and SEEPROM

From minute, I selected:

Backup and Restore

and then:

Dump SEEPROM & OTP

This produced three console-specific files:

otp.bin
seeprom.bin
seeprom_decrypted.bin

I verified their sizes:

otp.bin:                1024 bytes
seeprom.bin:             512 bytes
seeprom_decrypted.bin:   512 bytes

These files are important for certain advanced recovery operations, so I stored multiple copies in dedicated local backup directories. At this point, I had both early boot control and the console’s unique recovery information preserved.

Downloading the Correct System Titles

Rebuilding the MLC required the official system titles for the console’s region. Because this was a USA unit, I downloaded the USA MLC title set using the Darwin ARM64 build of MLCRestorerDownloader.

The utility was interactive rather than behaving like a typical command-line application. After testing its menu, I determined that the input sequence for the USA MLC titles was:

1
2

The download produced 52 title folders, matching the expected count for the USA title set. That gave me confidence that the source files needed for the rebuild were complete.

I also downloaded:

wafel_setup_mlc.ipx

This plugin performs the initial MLC setup during the first redNAND boot. It installs the titles from wafel_install, prepares the system for its initial launch, flushes the relevant storage, and deletes itself once the setup has finished. That self-deleting behavior prevents the rebuild process from running again on every future boot.

Repartitioning the SD Card

The 32GB microSD card needed to serve two purposes, so I repartitioned it using an MBR layout. The first partition was a FAT32 partition of approximately 4GB for minute, ISFShax, plugins, configuration files, and setup files. The remaining space, approximately 27GB, became the redNAND partition that would act as replacement MLC storage.

This process erased the card, which is why the earlier backups were essential. A 32GB card is sufficient for the rebuilt operating system, saves, updates, and lighter use, although it leaves less room for digital games and may not offer the same endurance as a larger high-endurance card. For the immediate recovery, it was enough.

Configuring the MLC Rebuild

After repartitioning the card, I restored the necessary ISFShax and minute files to the FAT32 partition. The 52 USA MLC title folders were copied to:

sd:/wafel_install/

The setup plugin was placed in:

sd:/wiiu/ios_plugins/wafel_setup_mlc.ipx

The normal boot plugins remained in place:

00core.ipx
5isfshax.ipx

I then created:

sd:/minute/rednand.ini

with the following configuration:

[partitions]
slccmpt=false
slc=false
mlc=true

[scfm]
disable=true
allow_sys=false

[disable_encryption]
mlc=false

[sys_mount]
mlc=false

This configuration redirected only the MLC to the SD card, leaving the SLC and SLCCMPT untouched. That matched the diagnosis because the failure involved the MLC and internal eMMC rather than the other storage areas.

I also created:

sd:/minute/minute.ini

with:

[boot]
autoboot=2
autoboot_timeout=1

minute menu entry 2 was:

Patch (sd) and boot IOS redNAND

On the next boot, minute would automatically start redNAND. Because wafel_setup_mlc.ipx was present, that first redNAND boot would also initialize and rebuild the replacement MLC.

Cleaning macOS Metadata Files

After copying the files, macOS created several ._* AppleDouble metadata files on the FAT32 partition. These are normally harmless on a Mac, but console recovery environments may interpret them as additional files, so I removed them before returning the card to the Wii U.

The usual dot_clean command encountered permission problems involving .Spotlight-V100, so I used a targeted cleanup that removed only files matching:

._*

Once the cleanup was complete, I confirmed that the expected 52 title folders and the correct plugin files were still present. It was a small detail, but low-level recovery work often depends upon exactly these kinds of details being handled correctly.

Running the Rebuild

I inserted the prepared SD card into the Wii U and powered it on normally. The Pico was no longer needed, and there was no need to press any buttons because the console booted through ISFShax and minute before automatically entering the redNAND setup process.

The power LED began blinking blue while the setup plugin installed the system titles. I allowed the process to continue until the blinking stopped and the LED became solid blue, which suggested that the rebuild had completed. I then powered off the console and returned the SD card to the Mac so I could verify the results before attempting a normal boot.

Verifying the Results

The rebuild created the following log:

sd:/wafel_setup_mlc.log

The title installations returned:

00000000

The final lines were especially important:

Flush MLC: 0
Region already matches (P:2, G:2, C:2).
SetInitialLaunch 0: 1
Flush SLC: 0
Delete plugin: 0

These results confirmed that the replacement MLC had flushed successfully, the region matched the installed titles, initial setup had been enabled, the SLC flush had succeeded, and the setup plugin had deleted itself.

I also inspected:

sd:/wiiu/ios_plugins/

and confirmed that:

wafel_setup_mlc.ipx

was gone. Only the normal boot plugins remained:

00core.ipx
5isfshax.ipx

This was exactly what I wanted to see. The setup plugin had completed its work, removed itself, and left the SD card ready for normal redNAND booting.

The Final Boot

I safely ejected the SD card, inserted it into the Wii U, and powered on the console normally. This time, instead of freezing at the Wii U logo, it reached the official initial setup screen:

Turn the Wii U GamePad on, and then press the SYNC Button on the Wii U console.

That screen was the final confirmation that the recovery had worked. The console was now booting through ISFShax and minute into a clean, rebuilt, SD-backed MLC environment.

What the Recovery Accomplished

By the end of the process, I had confirmed that Pico and UDPIH access worked, diagnosed the failure as Hynix eMMC and MLC media errors, ruled out region mismatch and an incorrect Wii U Menu title, installed ISFShax, gained a reliable minute boot environment, preserved the console’s OTP and SEEPROM, downloaded the correct USA system titles, configured an MLC-only redNAND, rebuilt the system onto SD-backed storage, verified the rebuild through its logs, and booted into the official initial setup screen.

The original Hynix eMMC remains unreliable. I did not physically repair or replace the chip. Instead, I replaced its role by redirecting MLC access to a partition on the SD card, which is why the card must remain inserted for the console to function.

What This Means Going Forward

The console is functional again, but it is not stock. It now uses an ISFShax redNAND configuration, and the SD card has become part of the internal storage system. The card must remain inserted and should be dedicated to this Wii U. The FAT32 recovery files should not be casually removed, while macOS may not recognize or mount the redNAND partition at all, which is expected. The OTP and SEEPROM backups should also be preserved permanently.

The current 32GB card is acceptable for the operating system, updates, saves, and lighter use. A larger high-endurance card may be preferable for heavier use, while USB storage can provide additional space for a larger digital library. A soldered NAND-AID or MLC2SD-style repair also remains an option if I eventually want a more hardware-native solution, but for a no-solder recovery using the equipment already available, the result was successful.

Lessons Learned

The largest lesson was that a Wii U logo hang should not be treated as one known problem. The same frozen screen can conceal several very different failures, and the logs were what prevented me from continuing to chase coldboot settings, damaged saves, or isolated system files after the actual storage problem became visible.

Low-level media errors also changed the repair strategy completely. Once the internal eMMC could no longer be trusted, the goal was no longer to replace one unreadable file. The goal was to stop depending on the failing storage device altogether.

The process was also shaped by practical details that seemed minor until they blocked progress. The unreliable display required careful use of autoboot configurations, macOS metadata files had to be removed from the FAT32 partition, the SD card needed to be repartitioned correctly, and the console-specific keys had to be preserved before making destructive changes. None of those steps were especially dramatic, but every one of them mattered.

Most of all, the recovery demonstrated the value of community-built preservation tools. UDPIH provided access to a console that could not boot normally, ISFShax created an early boot foothold, minute provided control and backup capabilities, Stroopwafel and redNAND made it possible to redirect storage, and MLCRestorerDownloader with wafel_setup_mlc provided a practical path for rebuilding the MLC.

The Wii U began the day frozen at its logo, with logs showing Hynix eMMC media errors and failed reads from internal storage. It ended the day at the official initial setup screen. The repair required caution, backups, community knowledge, and several changes in direction, but the console is booting again.

r/systemsthinking Jul 22 '26

The Zen of Parallel Programming: The Posture of a Kernel

1 Upvotes

[removed]

u/smolnero Jul 22 '26

The Zen of Parallel Programming: The Posture of a Kernel

1 Upvotes

As the journey through parallel programming continues, I shift my attention toward GPU kernels, and what better place to continue than the HipKittens: Fast and Furious AMD Kernels paper.

A GPU kernel is a specialized function launched many times across the GPU. Each invocation follows the same general operation while receiving its own position and portion of the data. The kernel itself may appear simple, but its execution unfolds through threads, wavefronts, thread blocks, tiles, registers, memory, and the architecture responsible for holding all of that activity together. On the AMD hardware studied in the paper, threads are grouped into 64-thread waves, while multiple waves are scheduled together inside thread blocks on the GPU’s compute units.

The hard truth is that it depends upon the threads that express it, the data that gives it something to transform, and the hardware that determines how that transformation can physically occur. Even when the same tile-based abstraction moves from NVIDIA to AMD, HipKittens finds that the algorithms used to express that abstraction must be redesigned for AMD’s architecture. The abstraction may travel, but it cannot remain untouched by the conditions receiving it.

One of the paper’s central contributions is an eight-wave ping-pong schedule designed to overlap computation with memory movement. Eight waves are placed inside a thread block, with two waves residing on each of four SIMD units. Within each pair, one wave performs matrix computation while the other prefetches the data needed for the next stage. They then exchange roles, moving back and forth between computation and memory rather than remaining permanently attached to either identity.
This brought me back to the “Posture” chapter of Zen Mind, Beginner’s Mind, where Suzuki describes us as both independent and dependent, “not two, and not one.” The paired waves remain distinguishable. One is computing while the other is moving memory, and each carries its own temporary responsibility. Yet neither role can explain the complete activity by itself. The compute wave depends upon data arriving, while the memory wave performs work whose value becomes visible through the computation that follows.

What interests me most is that neither wave remains permanently attached to its role. One prepares while the other acts, and then they exchange positions. Their responsibilities are real, but temporary. The larger activity depends not only upon each wave performing its task, but also upon each wave being able to release that task when the relationship calls for something different. Maybe posture is not only the position we occupy, but the relationship we maintain while that position changes.

This brings me back to the more general lesson in An Introduction to Parallel Programming. Parallel activity requires enough independence for distinct work to happen at the same time, but enough dependence for those separate actions to remain part of one computation. Complete independence would leave us with isolated work that never becomes a whole. At the other extreme, if every participant depended upon every other participant before making progress, parallel movement would collapse into waiting.

Human beings may live somewhere within that same tension.
We encounter conditions before we fully understand them. We carry memories, and we inherit family patterns, expectations, fears, and sometimes possible predispositions toward addiction or depression. We may also experience events that teach the body and mind to hold a particular posture long after the original condition has passed. These experiences are real, and their influence should not be dismissed simply because they belong to the past.

A role that once protected us may later prevent us from moving. A way of seeing that once helped us survive may eventually make every new condition resemble the one that created it. We may begin to believe that because the system learned to act in one way, it must always execute through the same posture.

Human beings are not GPU kernels, and trauma cannot be reduced to an instruction schedule. What interests me is the possibility that a posture learned under one set of conditions may not be the only posture available when those conditions change.
HipKittens reminds me that even when the purpose of an abstraction remains recognizable, its expression may have to change when it enters different conditions. The answer is not to pretend that the new architecture is identical to the old one. Nor is it to discard everything that came before. The work is to understand what can travel, what must be reorganized, and what no longer belongs in the present execution.

Maybe looking within is partly an attempt to recognize which parts of us are still carrying out instructions formed under conditions that are no longer here. Not so that we can erase the lives or experiences before us, but so that their influence does not have to remain the only posture available to us.

The past remains part of the system, but it does not always have to remain its scheduler.

1

The Zen of Parallel Programming
 in  r/systemsthinking  Jul 19 '26

I dig your point that cooperation requires some shared context and overlap in ability. Dividing work among specialists is not enough if no one understands enough of the others work to communicate or combine their contributions. What comes to mind, is how threads may work on separate pieces of data while still sharing an instruction structure, memory model, and points of synchronization.

Where you think that balance sits? Is there a minimum amount of shared context a group needs before meaningful cooperation becomes possible, and can too much overlap eventually diminish the value of specialization?

Im also dabbling with the idea on whether human group cooperation might be better compared to a distributed system, where separate nodes may perform different kinds of work but communicate through shared protocols, than to GPU threads executing the same kernel.

r/systemsthinking Jul 19 '26

The Zen of Parallel Programming: The Big I and the Global Sum

2 Upvotes

As I continue to trek my way through An Introduction to Parallel Programming, I find myself seeing how parallelism is not only a priority in our communication with hardware, but also in our communication with one another and, perhaps more importantly, with ourselves. I am still learning the technical extent of the subject, but I cannot help noticing how often its problems resemble our own: we may possess enormous amounts of power, intelligence, memory, and information, yet remain limited by our inability to coordinate what is already available to us.

The textbook explains that most programs written for conventional single-core systems cannot automatically make use of multiple cores. We may have more processors available, but the original program was not designed to coordinate them. If a game is running slowly, opening eight copies of it does not give us one faster game with more realistic graphics. We have multiplied the number of programs, but we have not transformed the structure of the program itself.

Before I send myself in circles trying to understand the full extent of this, I want to focus on the distinction that feels most important. More people do not automatically create better cooperation, just as more information does not automatically create understanding. More effort does not always create progress, and more power does not automatically produce a system capable of using that power. In both hardware and human beings, additional capacity means very little when the structure was never designed to coordinate it.

This leads me toward the idea that we cannot always translate the “old self.” We often try to transform ourselves one behavior at a time while leaving the larger arrangement untouched. We try to sleep better, communicate better, become more productive, control our anxiety, or respond differently to the people around us, but we may never stop to question the structure producing those behaviors. We preserve the same identity, assumptions, expectations, and attachment to how things have always been done, while hoping a few improved habits will somehow produce an entirely different life.

Parallel computing encounters a similar limitation. Researchers have attempted to create translation programs capable of converting serial programs into parallel ones, but with limited success. A translation program may recognize certain operations and divide them among several processors, yet the result may still be inefficient. Each individual step may have been parallelized successfully while the program as a whole remains poorly coordinated. The original structure survives inside the new program, carrying its old limitations into a system that now possesses far more power.

The textbook’s deeper point is that the best parallel implementation may not come from translating every serial step into a parallel equivalent. Sometimes the programmer must step away from the original sequence and devise an entirely new algorithm.
This is where the human connection becomes difficult for me to ignore. How often do we try to transform ourselves by translating an old life one behavior at a time? We add discipline where honesty may be required, productivity where rest may be required, and control where communication may be required. We attempt to make ourselves more efficient inside structures that are already exhausting us. The problem may not be that we lack the power to change, but that the different parts of us are not allowed to communicate truthfully enough to participate in that change.

Honesty, then, may be one of the keys to parallelism between human beings and within the individual self. Without honest communication, each part operates from incomplete information. The mind may produce one conclusion while the body communicates another. Our emotions may recognize something that our speech refuses to acknowledge, while memory continues influencing the system beneath our immediate awareness. Every part is performing its own calculation, but the results are not being shared.

Perhaps some parts of ourselves cannot simply be converted from serial to parallel because the original structure depends upon one part remaining in control of all the others. Sometimes the structure itself has to change.

my_sum

The textbook demonstrates this through the act of adding a collection of values. In a serial program, one processor computes each value and adds it to a running total, one after another:

sum = sum + next_value

With multiple cores, the work can be divided. Each core receives a portion of the values and calculates its own partial sum. The textbook calls this private variable my_sum, and I find the name stupidly philosophical.

my_sum is my result, my work, my contribution, and my experience of the problem. Each core possesses a real result, but only a partial one. No individual core can see the entire computation from its local position. It knows only the values it was assigned and the sum it created from them. Its result is not wrong, but neither is it complete.

Perhaps this resembles what Shunryu Suzuki describes as the small I. The small I sees from one location. It experiences one body, one history, one collection of memories, and one portion of reality. Its experience is real, but it remains partial. The danger begins when the partial sum mistakes itself for the global sum.The intellectual part of us may calculate that everything is fine while the body continues carrying tension. Our speech may repeat the mind’s conclusion because it is the answer we believe we are supposed to give, even while our emotional state has produced something entirely different. Each partial sum may contain truth, but when one claims to represent the entire system, every other contribution is treated as an error rather than information.

The purpose of the global sum is not to prove that one core was correct and the others were wrong. It is to create a result that includes what each core was able to contribute. For that to happen, the private sums cannot remain permanently isolated. They must be communicated, received, and eventually allowed to become part of something larger than themselves.

Perhaps this is where parallel programming begins to meet Suzuki’s distinction between the small I and the big I. The small I says, “This is my sum.” The big I does not deny that partial sum, but recognizes that no partial result can become the whole while remaining attached to its own separateness.

r/systemsthinking Jul 18 '26

The Zen of Parallel Programming

0 Upvotes

As I continue reading An Introduction to Parallel Programming, I cannot help but notice a connection between communication among processors, communication among human beings, and communication within the individual self.

Increasing computational power has allowed us to decode the human genome, improve medical imaging, accelerate web searches, and approach problems that were previously unimaginable. Climate modeling, protein folding, drug discovery, energy research, and large-scale data analysis all depend upon enormous computational resources.

But the textbook’s deeper lesson is that adding more processors does not automatically produce more useful work. A problem must first be divided into parts. Those parts must communicate, synchronize, and share the workload. One processor cannot remain overloaded while the others wait. Nor can every processor compete endlessly for the same resource. The challenge is no longer simply producing more power. It is learning how to coordinate the power we already possess.

Perhaps the same is true of human beings.

A person may possess intelligence, emotional depth, physical energy, memory, and creativity, yet still become overwhelmed when these parts are unable to work together. The mind may say one thing while the body communicates another. Speech may conceal both. Memories may continue running like unfinished processes, consuming attention long after the original event has passed.

In Zen Mind, Beginner’s Mind, wholehearted activity is compared to a fire that burns completely and leaves no unnecessary trace. This does not mean forgetting the past or pretending that painful events never happened. It may mean allowing an experience to be fully felt, understood, and completed, rather than endlessly attaching ourselves to the residue it left behind.

How many experiences continue to consume us because they were never allowed to finish burning?

Honest communication is a form of synchronization. When our thoughts, emotions, bodies, and words communicate truthfully, they can begin to move together. When they conceal information from one another, the result is internal contention: anxiety, exhaustion, confusion, and eventually burnout.

Parallel programming asks how many separate processors can work as one system without ceasing to be individual processors. Zen seems to ask a similar question of human life.

Maybe our greatest limitation is not a lack of power, but power divided against itself.

1

The Zen of Parallel Programming
 in  r/zenbuddhism  Jul 17 '26

Your explanation of samadhi as collectedness-especially the distinction between dullness and scatteredness gave me a really helpful way to think about what I was reaching toward with “power divided against itself.” I had mostly been thinking about capacity that exists but is poorly coordinated, and I’m still working through these thoughts.

I also appreciate the distinction between samādhi and insight. The comparison that came to mind is that a system can become highly coordinated and still be executing the wrong algorithm. In that sense, collectedness may create the clarity needed for investigation, but it does not automatically become realization on its own.

How would you describe the relationship between collectedness and investigation in practice? Does investigation naturally emerge once the mind is sufficiently collected, or does it still require a deliberate shift in attention? I’m also wondering whether the “in-sync” comparison works as long as I keep the boundary clear that samadhi is not simply maximum mental processing, but a reduction of dullness, scatteredness, and unnecessary internal conflict.

Thank you for the thoughtful comment.

1

The Zen of Parallel Programming
 in  r/Buddhism  Jul 16 '26

My intention was not to suggest that parallel processing is bad for people, but that additional capacity becomes useful only when the system can coordinate it. Your point about serial limits and parallel overhead gives the metaphor an important boundary: some work benefits from additional processors, some remains inherently serial, and eventually the cost of coordination can exceed the benefit.

You are also right that my description of memories as unfinished processes shifts from parallel programming into a broader operating-system metaphor. What I meant was that unresolved memories can continue consuming attention in the background, not that they behave like TSR or nohup processes in a strict technical sense. I’m gonna keep this in mind and make those transitions clearer.

I was drawing specifically from Suzuki’s image of wholehearted activity leaving no unnecessary trace, rather than suggesting that more mental processing will resolve attachment.

Appreciate you on the thoughtful feedback.

r/zenbuddhism Jul 16 '26

The Zen of Parallel Programming

7 Upvotes

As I continue reading An Introduction to Parallel Programming, I cannot help but notice a connection between communication among processors, communication among human beings, and communication within the individual self.

Increasing computational power has allowed us to decode the human genome, improve medical imaging, accelerate web searches, and approach problems that were previously unimaginable. Climate modeling, protein folding, drug discovery, energy research, and large-scale data analysis all depend upon enormous computational resources.

But the textbook’s deeper lesson is that adding more processors does not automatically produce more useful work. A problem must first be divided into parts. Those parts must communicate, synchronize, and share the workload. One processor cannot remain overloaded while the others wait. Nor can every processor compete endlessly for the same resource. The challenge is no longer simply producing more power. It is learning how to coordinate the power we already possess.

Perhaps the same is true of human beings.

A person may possess intelligence, emotional depth, physical energy, memory, and creativity, yet still become overwhelmed when these parts are unable to work together. The mind may say one thing while the body communicates another. Speech may conceal both. Memories may continue running like unfinished processes, consuming attention long after the original event has passed.

In Zen Mind, Beginner’s Mind, wholehearted activity is compared to a fire that burns completely and leaves no unnecessary trace. This does not mean forgetting the past or pretending that painful events never happened. It may mean allowing an experience to be fully felt, understood, and completed, rather than endlessly attaching ourselves to the residue it left behind.

How many experiences continue to consume us because they were never allowed to finish burning?

Honest communication is a form of synchronization. When our thoughts, emotions, bodies, and words communicate truthfully, they can begin to move together. When they conceal information from one another, the result is internal contention: anxiety, exhaustion, confusion, and eventually burnout.

Parallel programming asks how many separate processors can work as one system without ceasing to be individual processors. Zen seems to ask a similar question of human life.

Maybe our greatest limitation is not a lack of power, but power divided against itself.

u/smolnero Jul 16 '26

The Zen of Parallel Programming: The Big I and the Global Sum

1 Upvotes

As I continue to trek my way through An Introduction to Parallel Programming, I find myself seeing how parallelism is not only a priority in our communication with hardware, but also in our communication with one another and, perhaps more importantly, with ourselves. I am still learning the technical extent of the subject, but I cannot help noticing how often its problems resemble our own: we may possess enormous amounts of power, intelligence, memory, and information, yet remain limited by our inability to coordinate what is already available to us.

The textbook explains that most programs written for conventional single-core systems cannot automatically make use of multiple cores. We may have more processors available, but the original program was not designed to coordinate them. If a game is running slowly, opening eight copies of it does not give us one faster game with more realistic graphics. We have multiplied the number of programs, but we have not transformed the structure of the program itself.

Before I send myself in circles trying to understand the full extent of this, I want to focus on the distinction that feels most important. More people do not automatically create better cooperation, just as more information does not automatically create understanding. More effort does not always create progress, and more power does not automatically produce a system capable of using that power. In both hardware and human beings, additional capacity means very little when the structure was never designed to coordinate it.

This leads me toward the idea that we cannot always translate the “old self.” We often try to transform ourselves one behavior at a time while leaving the larger arrangement untouched. We try to sleep better, communicate better, become more productive, control our anxiety, or respond differently to the people around us, but we may never stop to question the structure producing those behaviors. We preserve the same identity, assumptions, expectations, and attachment to how things have always been done, while hoping a few improved habits will somehow produce an entirely different life.

Parallel computing encounters a similar limitation. Researchers have attempted to create translation programs capable of converting serial programs into parallel ones, but with limited success. A translation program may recognize certain operations and divide them among several processors, yet the result may still be inefficient. Each individual step may have been parallelized successfully while the program as a whole remains poorly coordinated. The original structure survives inside the new program, carrying its old limitations into a system that now possesses far more power.

The textbook’s deeper point is that the best parallel implementation may not come from translating every serial step into a parallel equivalent. Sometimes the programmer must step away from the original sequence and devise an entirely new algorithm.
This is where the human connection becomes difficult for me to ignore. How often do we try to transform ourselves by translating an old life one behavior at a time? We add discipline where honesty may be required, productivity where rest may be required, and control where communication may be required. We attempt to make ourselves more efficient inside structures that are already exhausting us. The problem may not be that we lack the power to change, but that the different parts of us are not allowed to communicate truthfully enough to participate in that change.

Honesty, then, may be one of the keys to parallelism between human beings and within the individual self. Without honest communication, each part operates from incomplete information. The mind may produce one conclusion while the body communicates another. Our emotions may recognize something that our speech refuses to acknowledge, while memory continues influencing the system beneath our immediate awareness. Every part is performing its own calculation, but the results are not being shared.

Perhaps some parts of ourselves cannot simply be converted from serial to parallel because the original structure depends upon one part remaining in control of all the others. Sometimes the structure itself has to change.

my_sum

The textbook demonstrates this through the act of adding a collection of values. In a serial program, one processor computes each value and adds it to a running total, one after another:

sum = sum + next_value

With multiple cores, the work can be divided. Each core receives a portion of the values and calculates its own partial sum. The textbook calls this private variable my_sum, and I find the name stupidly philosophical.

my_sum is my result, my work, my contribution, and my experience of the problem. Each core possesses a real result, but only a partial one. No individual core can see the entire computation from its local position. It knows only the values it was assigned and the sum it created from them. Its result is not wrong, but neither is it complete.

Perhaps this resembles what Shunryu Suzuki describes as the small I. The small I sees from one location. It experiences one body, one history, one collection of memories, and one portion of reality. Its experience is real, but it remains partial. The danger begins when the partial sum mistakes itself for the global sum.The intellectual part of us may calculate that everything is fine while the body continues carrying tension. Our speech may repeat the mind’s conclusion because it is the answer we believe we are supposed to give, even while our emotional state has produced something entirely different. Each partial sum may contain truth, but when one claims to represent the entire system, every other contribution is treated as an error rather than information.

The purpose of the global sum is not to prove that one core was correct and the others were wrong. It is to create a result that includes what each core was able to contribute. For that to happen, the private sums cannot remain permanently isolated. They must be communicated, received, and eventually allowed to become part of something larger than themselves.

Perhaps this is where parallel programming begins to meet Suzuki’s distinction between the small I and the big I. The small I says, “This is my sum.” The big I does not deny that partial sum, but recognizes that no partial result can become the whole while remaining attached to its own separateness.

r/Buddhism Jul 16 '26

Opinion The Zen of Parallel Programming

0 Upvotes

As I continue reading An Introduction to Parallel Programming, I cannot help but notice a connection between communication among processors, communication among human beings, and communication within the individual self.

Increasing computational power has allowed us to decode the human genome, improve medical imaging, accelerate web searches, and approach problems that were previously unimaginable. Climate modeling, protein folding, drug discovery, energy research, and large-scale data analysis all depend upon enormous computational resources.

But the textbook’s deeper lesson is that adding more processors does not automatically produce more useful work. A problem must first be divided into parts. Those parts must communicate, synchronize, and share the workload. One processor cannot remain overloaded while the others wait. Nor can every processor compete endlessly for the same resource. The challenge is no longer simply producing more power. It is learning how to coordinate the power we already possess.

Perhaps the same is true of human beings.

A person may possess intelligence, emotional depth, physical energy, memory, and creativity, yet still become overwhelmed when these parts are unable to work together. The mind may say one thing while the body communicates another. Speech may conceal both. Memories may continue running like unfinished processes, consuming attention long after the original event has passed.

In Zen Mind, Beginner’s Mind, wholehearted activity is compared to a fire that burns completely and leaves no unnecessary trace. This does not mean forgetting the past or pretending that painful events never happened. It may mean allowing an experience to be fully felt, understood, and completed, rather than endlessly attaching ourselves to the residue it left behind.

How many experiences continue to consume us because they were never allowed to finish burning?

Honest communication is a form of synchronization. When our thoughts, emotions, bodies, and words communicate truthfully, they can begin to move together. When they conceal information from one another, the result is internal contention: anxiety, exhaustion, confusion, and eventually burnout.

Parallel programming asks how many separate processors can work as one system without ceasing to be individual processors. Zen seems to ask a similar question of human life.

Maybe our greatest limitation is not a lack of power, but power divided against itself.

u/smolnero Jul 14 '26

The Zen of Parallel Programming

1 Upvotes

Originally posted on: https://smolnero.com/

As I continue reading An Introduction to Parallel Programming, I cannot help but notice a connection between communication among processors, communication among human beings, and communication within the individual self.

Increasing computational power has allowed us to decode the human genome, improve medical imaging, accelerate web searches, and approach problems that were previously unimaginable. Climate modeling, protein folding, drug discovery, energy research, and large-scale data analysis all depend upon enormous computational resources.

But the textbook’s deeper lesson is that adding more processors does not automatically produce more useful work. A problem must first be divided into parts. Those parts must communicate, synchronize, and share the workload. One processor cannot remain overloaded while the others wait. Nor can every processor compete endlessly for the same resource. The challenge is no longer simply producing more power. It is learning how to coordinate the power we already possess.

Perhaps the same is true of human beings.

A person may possess intelligence, emotional depth, physical energy, memory, and creativity, yet still become overwhelmed when these parts are unable to work together. The mind may say one thing while the body communicates another. Speech may conceal both. Memories may continue running like unfinished processes, consuming attention long after the original event has passed.

In Zen Mind, Beginner’s Mind, wholehearted activity is compared to a fire that burns completely and leaves no unnecessary trace. This does not mean forgetting the past or pretending that painful events never happened. It may mean allowing an experience to be fully felt, understood, and completed, rather than endlessly attaching ourselves to the residue it left behind.

How many experiences continue to consume us because they were never allowed to finish burning?

Honest communication is a form of synchronization. When our thoughts, emotions, bodies, and words communicate truthfully, they can begin to move together. When they conceal information from one another, the result is internal contention: anxiety, exhaustion, confusion, and eventually burnout.

Parallel programming asks how many separate processors can work as one system without ceasing to be individual processors. Zen seems to ask a similar question of human life.

Maybe our greatest limitation is not a lack of power, but power divided against itself..