Skip to content

Performance anomaly: WasmEdge JIT is disproportionately slow on a sharp i16x8.max_u 0x8000-threshold case with lane-0 unsigned extraction #4826

Description

@gaaraw

Summary

I found a performance anomaly in WasmEdge JIT for a narrow SIMD micro-benchmark built around i16x8.max_u.

On the testcase below, WasmEdge JIT is a clear outlier:

runtime time
wasmer_llvm 0.64057
wasmedge_jit 2.44644
wamr_llvm_jit 0.66172
wasmer_cranelift 0.93965
wasmtime 0.94213

This makes WasmEdge JIT about 3.82x slower than Wasmer LLVM and about 3.70x slower than WAMR LLVM JIT on this testcase.

Current State

Primary reproducer:

(module
  (type (func (param i32)))
  (type (func))

  (import "wasi_snapshot_preview1" "proc_exit" (func (type 0)))

  (func (type 1)
    (local $i i64)
    (local $acc i64)
    (local.set $i (i64.const 1073741824))
    (local.set $acc (i64.const 1311768467463790320))
    (loop $body
      local.get $i
      i64.const 0x61C8864680B583EB
      i64.xor
      i32.wrap_i64
      i16x8.splat
      local.get $i
      i64.const 0x27BB2EE687B0B0FD
      i64.xor
      i32.wrap_i64
      i16x8.replace_lane 6
      i32.const 32768
      i16x8.splat
      i16x8.max_u
      i16x8.extract_lane_u 0
      i64.extend_i32_u
      local.get $acc
      i64.xor
      local.set $acc
      (local.set $i (i64.sub (local.get $i) (i64.const 1)))
      (br_if $body (i64.ne (local.get $i) (i64.const 0)))
    )
    (i32.const 0)
    (local.get $acc)
    (i64.store)
    (call 0 (i32.const 0))
  )

  (memory 1)

  (export "_start" (func 1))
  (export "memory" (memory 0))
)

This case appears to be alive in low-level inspection:

  • WasmEdge AOT LLVM IR still retains the hot loop and the consumed scalar path.
  • Wasmer LLVM still lowers the same benchmark to a compact SIMD loop centered on vpmaxuw + vpextrw.

So this does not look like a whole-benchmark elimination artifact.

The current evidence suggests the anomaly is tied to a very narrow trigger condition:

  • exact threshold constant 0x8000 (32768)
  • i16x8.max_u
  • extraction of lane 0
  • unsigned scalar extension/consumption
  • original splat-derived scaffold

A particularly important observation is that the exact 0x8000 threshold changes the WasmEdge AOT IR shape:

  • for 32768, WasmEdge AOT rewrites the consumed path into a threshold/select form;
  • for nearby constants such as 32767 and 32769, it keeps a direct @llvm.umax.v8i16 form.

Expected State

I would expect WasmEdge JIT to be in the same rough performance range as the other runtimes on this testcase, or at least not to be a strong outlier only at this exact threshold case.

Reproduction steps

  1. Save the WAT above as case.wat.
  2. Build the wasm file:
wat2wasm case.wat -o case.wasm
  1. Run the benchmark multiple times, for example:
perf stat -r 5 -e 'task-clock' /path/to/wasmedge --enable-jit case.wasm
perf stat -r 5 -e 'task-clock' /path/to/wasmer run --llvm case.wasm
perf stat -r 5 -e 'task-clock' /path/to/wasmtime case.wasm

### Screenshots

![DESCRIPTION](LINK.png)


### Any logs you want to share for showing the specific issue

The strongest narrowing evidence is the nearby-threshold comparison.

The severe WasmEdge slowdown collapses when changing only the threshold constant away from `32768`:

| variant | wasmer_llvm (ms) | wasmedge_jit (ms) | wasmtime (ms) |
|---|---:|---:|---:|
| original (`32768`) | 640.57 | 2446.44 | 942.13 |
| `32766` | 679.08 | 697.40 | 977.85 |
| `32767` | 668.31 | 689.31 | 96.93 |
| `32769` | 664.11 | 683.02 | 965.19 |
| `32770` | 670.24 | 690.66 | 959.66 |

Additional controls also collapse the slowdown:

- extracting lane 6 instead of lane 0;
- keeping lane 0 but switching to signed scalar consumption;
- replacing `max_u` with `max_s` and using signed extraction.

So I am not claiming a broad `i16x8.max_u` problem. The current evidence supports a **sharp threshold-sensitive WasmEdge JIT performance anomaly** for this specific scaffold.

I do not yet have a JIT-near WasmEdge code dump, so I am intentionally not claiming a proven root cause.

### Components

CLI

### WasmEdge Version or Commit you used

0.16.1-18-gc457fe30

### Operating system information

Ubuntu 22.04.5 LTS x64

### Hardware Architecture

x86_64, 12th Gen Intel(R) Core(TM) i7-12700

### Compiler flags and options

- WasmEdge run mode: `--enable-jit`
- wabt `wat2wasm` used to produce the wasm file

Additional local environment information:

```text
- wasmer: 6.1.0
- WAMR: iwasm 2.4.4
- wasmedge: 0.16.1-18-gc457fe30
- wasmtime: 41.0.0 (4898322a4 2025-12-18)
- wabt: 1.0.39
- llvm: 21.1.5
- Host OS: Ubuntu 22.04.5 LTS x64
- CPU: 12th Gen Intel® Core™ i7-12700 × 20

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Triage-required

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions