Overview
WaferLens finds excursions in batch: its pattern alarm caught all 13 spatial excursions in its simulated fab, a median of 52 hours after they began, almost all of it spent waiting for wafer sort. WaferEdge asks the next question: how fast can that same excursion be caught, and the lot put on hold, at the equipment itself, before the next wafer is processed?
Tool emulators send wafer sort results over SEMI HSMS / SECS-II, the protocol every fab tool speaks to the factory host. An edge host decodes them without copying, finds spatial signatures on the wafer maps (CPU with AVX2, or batched on the GPU with CUDA), runs FabEye's CNN on its own CUDA inference engine, and sends a lot hold (S2F41) back to the tool.
The answer, in short
- The hold reaches the tool within milliseconds of the sort result. With the rules on one CPU core, sort result to decision is 0.3–0.5 ms at the median and 0.7–2.3 ms at p99, at 1,000–5,000 wafers/s. A tool sorts a wafer every few seconds to minutes, so the hold always lands before the lot's next wafer.
- What decides how early an excursion is caught is the hold rule and the detector, not the machinery. Replayed over WaferLens's 24,090 wafers, every one of its 13 spatial excursions is held. The default per-lot rule (3 of a lot's last 5 wafers) holds after a median 8.1 hours, slower than WaferLens's own batch alarm (3.0 hours), because an excursion spreads its wafers over many lots. Adding a rule that counts across lots holds after 2.0 hours, with only 31 patterned wafers sorted first against 72 for the batch alarm, for 5 false holds out of 211.
- The CNN is more accurate than the rules (macro-F1 0.858 vs 0.655 on WM-811K's test lots) and runs at 11,000–13,000 maps/s on WaferEdge's own GPU kernels. At a tool's actual wafer rate, the CPU rules are the faster choice anyway: the GPU's batch deadline and driver calls cost more than classifying one map one at a time.
Tool emulator ──HSMS/SECS-II (TCP)──► Edge host
(replays WaferLens / WM-811K maps) ├─ net thread: Asio coroutines, zero-copy SECS-II decode
▲ ├─ lock-free SPSC rings, no allocation on the hot path
│ ├─ analytics: wafer-map signatures, CPU (AVX2) or GPU (CUDA)
│ ├─ inference: FabEye's CNN on our own CUDA kernels
└──────── S2F41 HOLD ◄─────────└─ decision rule (per lot, and across lots) → lot hold
Results
Accuracy against FabEye's CNN
Macro-F1 on the same maps:
| Data | Rules (WaferEdge) | CNN (FabEye) | Trivial (density threshold) |
|---|---|---|---|
| WM-811K test, lot-disjoint, 25,875 maps | 0.655 | 0.858 | 0.118 |
| WaferLens, simulated, 24,090 maps | 0.645 | 0.909 | 0.132 |
The rules explain every call in one line and run at ~14,000 maps/s on one core; they hold up on none, edge-ring, center and near-full, and lose on edge-loc, loc and scratch. FabEye's CNN on WaferEdge's engine keeps FabEye's macro-F1 and conformal coverage across precisions (90% target: 0.8925 / 0.8926 / 0.8951 for fp32 / fp16 / int8).
CPU against GPU, and the crossover
All three wafer-map signatures from one upload, 40×40 maps, end to end per batch:
| Batch | Whole CPU (6 cores) | GPU | GPU with CUDA Graphs |
|---|---|---|---|
| 1 | 14.1k maps/s | 5.1k | 9.1k |
| 16 | 48.9k | 56.3k | 137k |
| 1,024 | 80.9k | 807k | 906k |
| 16,384 | 86.9k | 819k | — |
The GPU passes the whole CPU from ~16 maps a batch (~4 with CUDA Graphs) and is ~9× it at large batches. Overlapping the next batch's packing with the GPU's work on this one adds 1.3–1.7× throughput, up to ~1.07M maps/s. Below ~1,000 maps a batch is all overhead, above it all throughput, so batches close on a size or a deadline, whichever comes first.
Decoding the equipment protocol
SECS-II wafer reports decode in place, as views over the receive buffer, zero allocations:
| Message | Bytes | Decode and read every field | Encode |
|---|---|---|---|
| Wafer report, 40×40 map | 1,653 | 118 ns | 120 ns |
| Wafer report, 200×200 map | 40,053 | 120 ns | 1.46 µs |
| S2F41 HOLD | 29 | 40 ns | 59 ns |
About 8M wafer reports/s on one core, whatever the map size. An HSMS transaction over TCP loopback takes ~7 µs (p99 20 µs). The decoder, the HSMS framing and the GEM layer are fuzzed with libFuzzer in CI.
The closed loop on WaferLens's excursions
WaferLens's demo set replayed in sort-time order through the edge host's own detector and decision rule; a hold lands 5 ms after its wafer's sort. Hours from an excursion's first patterned wafer at sort to the hold, medians over the 13 excursions:
| Monitor | Excursions held | In-line hours | Patterned wafers sorted first (of 1,891) | False holds |
|---|---|---|---|---|
| WaferLens batch alarm (all lots) | 13 | 3.0 | 72 | – |
| Rules, 3 of 5 per lot (default) | 13 | 8.1 | 147 | 2 |
| Rules, 2 of 5, or 3 in 24h, across lots | 13 | 2.0 | 31 | 5 |
The default per-lot rule's 8.1 hours is a kept negative result: a per-lot window fills slowly because an excursion spreads its wafers over many lots.
Engineering
- Zero-copy, zero-allocation hot path: SECS-II decodes to views over the receive buffer; lock-free SPSC rings move data between the network thread and the detectors.
- Two detector tiers: hand-written rules that explain every call in one line, and FabEye's CNN running on WaferEdge's own CUDA inference engine (GEMM ladder up to tensor cores, implicit-GEMM convolution, kernel fusion, int8).
- Open-loop latency measurement: latency from each wafer's scheduled time, so a stall delays the wafers behind it and coordinated omission is counted rather than hidden.
- Reproducible and fuzzed: architecture decision records from ADR-0001 to ADR-0019, GPU tests run locally and labelled separately from CI (no GPU on GitHub's runners), the SECS-II decoder fuzzed with libFuzzer.
- Python bindings: the CPU signatures, rule classifier and clustering exposed on NumPy arrays through the buffer protocol, no copy.
Build
cmake --workflow --preset dev # configure, build, test (Debug, GCC 13)
cmake --workflow --preset cuda # Release with the CUDA backend, GPU tests included
build/release/tools/tool-emulator data/waferlens_demo.wmap --port 5000 --rate 50
build/release/tools/waferedge-edge --port 5000
Limitations
- Simulated fab. The excursions, their timing and their ground truth come from WaferLens's simulator; WM-811K is real but has no process history.
- GPU tests run locally only. No GPU on GitHub's runners; CI compiles the CUDA code and runs the CPU tests.
- One laptop under WSL2. Each CUDA call costs ~20–90 µs there, and GPU clocks move with power and heat, so kernels are compared in cycles rather than absolute time.
- A subset of SEMI E5 / E30 / E37, implemented from public descriptions, not certified.