# Understand performance

> Inspect Alice lowering, allocation, SIMD, automatic parallelism, columnar data, and floating-point semantics.

Canonical: https://alice-lang.org/documentation/guides/performance/

[Documentation index](https://alice-lang.org/documentation/llms.txt) · [Complete book](https://alice-lang.org/llms-full.txt)

## Inspect before rewriting

Alice's normal backend lowers source to MIR, emits C#, and uses Roslyn to generate .NET IL. The aim is efficient .NET code without making source authors manually express every loop optimization.

```sh
alice emit program.al
alice build --release
```

The playground exposes HIR, MIR, C#, and IL tabs. Inspect these to explain a transformation; benchmark locally in Release mode to measure its effect. Browser timings are not desktop throughput measurements.

## Pipelines become loops

```alice
xs = [1.0, 2.0, 3.0, 4.0]
val scale = 2.0
puts xs.map { |x| x * scale }.select { |x| x > 4.0 }.sum
```

Expected output:

```text
14
```

[Edit and run in the Alice playground](https://playground.alice-lang.org/#code=u.eHMgPSBbMS4wLCAyLjAsIDMuMCwgNC4wXQp2YWwgc2NhbGUgPSAyLjAKcHV0cyB4cy5tYXAgeyB8eHwgeCAqIHNjYWxlIH0uc2VsZWN0IHsgfHh8IHggPiA0LjAgfS5zdW0)

Literal blocks on supported iterator operations can inline into loops. A `map`/`select`/`reject` chain ending in a reduction can fuse into one pass without intermediate collections. A standalone `map` still needs a result array, which is preallocated to the correct size when possible.

Capture-free lambdas can become static delegates. Passing an arbitrary stored delegate is not always equivalent to a literal block for optimization purposes.

## Vectorization

Numeric array pipelines with eligible arithmetic, comparisons, and captured scalars can lower to `Vector(T)` operations with a scalar tail. Filters can use masked selection. A call the vectorizer does not support, such as `Math.Sin` in the block, can keep the loop scalar.

Vector width, supported element types, and actual hardware acceleration depend on the host. Readable source plus inspection is more useful than assuming all arithmetic has become SIMD.

## Automatic parallelism

Pure large array pipelines can receive parallel paths. The current pipeline threshold is 65,536 elements with more than one available worker. Eligible counted-loop reductions and disjoint indexed writes have their own workload decisions; heavy pure method calls may use smaller grain sizes.

Unsafe capture writes, I/O, unknown or impure calls, `break`, list appends, and order-dependent accumulation prevent transformations where they could change behavior. The [race checker](https://alice-lang.org/documentation/concurrency/race-safety.md) and purity gate are part of eligibility.

## Columnar data

An `@[SoA]` record and `SoA(T)` store keep each field in a separate array. Eligible `each`, `sum`, and `count` operations work over those columns directly.

Consecutive row-local passes can fuse, and eligible repeated steps can interchange with the row loop so values stay in registers longer. A pass reading another row prevents fusion because the ordering can matter. Use this representation for suitable numerical state, not as a universal object replacement.

## Other recognized patterns

| Source shape                                       | Possible lowering                       |
| -------------------------------------------------- | --------------------------------------- |
| Count words from `Split` into a dictionary         | Span splitting and alternate-key lookup |
| `d[k] = d.GetValueOrDefault(k) + 1`                | Single dictionary probe                 |
| Numeric loop with a supported inner escape `while` | Masked vector lanes (SIMT)              |
| Untyped parameters used with known call-site types | Typed specializations                   |
| A class with no Alice subclass                     | Sealed CLR class                        |

A missing dictionary key in `d[k] += value` still throws; optimization does not initialize it implicitly. SIMT currently excludes unsupported candidates such as integer division and Float32 bodies.

## Floating-point results

Parallel sums can change addition order and therefore the last bits. Fused multiply-add contracts supported expressions such as `a*b + c` into one rounding. `@[StrictMath]` on a method keeps separate multiply/add rounding. Neither choice makes floating-point arithmetic exact.

Use tolerances based on your algorithm, and compare checksums or numerical error as well as speed. Integer reductions are exact subject to their numeric overflow behavior.

## Measure a complete workload

Warm up the JIT, avoid including setup unless setup is the workload, run several trials, and record the runtime, CPU, input size, allocation, and output. Keep baseline and optimized versions semantically comparable.

The [benchmark suite](https://github.com/alicelanguage/alice/tree/main/benchmarks) includes idiomatic and hand-optimized C# comparisons. Results are workload- and machine-specific. A historical ratio does not guarantee the same improvement for an unrelated program.

## Continue reading

- Previous: [Test Alice programs](https://alice-lang.org/documentation/guides/testing.md)
- Next: [Build and distribute programs](https://alice-lang.org/documentation/guides/publishing.md)
