# The Increment That Vanishes

*Task 1 of 5 · [Histograms & Binning](https://gpu.rocks/learn/histograms-and-binning-dfb254f4.md) · GPU.js Learn*

On a CPU a histogram is three lines. Make an array of zeros, walk the data, add one
to the bin each value belongs to. It is the friendliest loop in programming.

```js
const bins = new Array(16).fill(0);
for (let i = 0; i < data.length; i++) bins[data[i]]++;
```

Now run that loop on 4,096 threads at once. `bins[v]++` is not one operation,
it is three — **read** bin *v*, **add** one,
**write** bin *v* back. Two threads whose values land in the same bin
both read 7, both compute 8, both write 8. Two increments went in; one came out. Nothing
crashed and nothing warned — a count is just quietly too low, and differently too low every
time you run it.

This is not a gpu.js quirk. It is precisely why CUDA ships `atomicAdd`: the
read-modify-write has to become indivisible, and making it indivisible means the colliding
threads take turns. gpu.js hands you no atomics and no scatter at all — a thread writes one
cell, its own — which forces the formulation that actually transfers: **invert the
loop**. Stop asking "which bin does my value go to?" and start asking "which values
belong to *my* bin?". Start with one bin.

## Figures

- **nobody can increment your bin but you — so go and count it yourself**

## Goal

**Goal:** make the single thread count how many of the 4,096
`codes` equal `this.constants.target`.

## Requirements

- Keep `output: [1]` — one thread, one bin, one count
- Loop `for (let i = 0; i < this.constants.n; i++)` over every code
- Add **1** for each code equal to `this.constants.target` — the value itself is not what a histogram counts
- Return the count; no shared array is touched anywhere

## Hint 1 — an accumulator, not an array

The count lives in a local `let count = 0;` that only this thread can
see. That is the whole reason there is nothing to race over: private variables cannot
collide.

## Hint 2 — the loop body

```js
if (codes[i] === this.constants.target) count++;
```

## Same idea elsewhere

Every compute API gives you the scatter this one withholds — and then charges for
it. CUDA and HIP have `atomicAdd`, WGSL has `atomicAdd` on an
`atomic<u32>` in a storage buffer, Metal has
`atomic_fetch_add_explicit`. They are correct and they are not free: colliding
threads serialize, and a histogram with one hot bin can reduce a whole warp to single file.
The gather you are about to write is what the fast implementations fall back to when
contention gets bad enough — which is why it is worth knowing even where atomics exist.

## Starter code

```js
// One bin, one thread. Nothing is shared, so nothing can race.
const gpu = new GPU({ mode });

const countBin = gpu.createKernel(function (codes) {
  // TODO: loop over all this.constants.n codes and count how many of
  // them equal this.constants.target. Add 1 per match — never the value.
  return 0;
}, {
  output: [1],
  constants: { n: 4096, target: 5 },
});

console.log('codes equal to the target:', (await countBin(codes))[0]);
```

---

Interactive version: https://gpu.rocks/learn/histograms-and-binning-dfb254f4/1

[Next task](https://gpu.rocks/learn/histograms-and-binning-dfb254f4/2.md)
