Vectorization and the ARM advantage
Vectorization means one instruction processing several data elements at once, using the processor's wide registers. Sixteen additions in the time of one.
The idea
A scalar loop adds one pair per instruction:
a[0] + b[0] → one instruction
a[1] + b[1] → one instruction
...
A vector instruction loads several elements into a wide register and operates on all of them together:
a[0..7] + b[0..7] → one instruction
Same result, a fraction of the instructions. This is SIMD (single instruction, multiple data), and it
is the reason np.sum(values ** 2) outruns the equivalent Python loop by a wide margin.
Why ARM Neoverse
Eugo's compute nodes are built on ARM Neoverse cores, and Eugo maintains a custom LLVM and Clang toolchain targeting them.
Two things follow:
Performance per watt. Neoverse cores deliver strong throughput on numeric work at lower power than comparable alternatives, which is why the platform can offer the capacity it does at the price it does.
A toolchain we control. Because Eugo builds its own compiler stack rather than relying on generic builds, vectorization is applied to ordinary numeric Python rather than only to code someone hand-tuned. Eugo also contributes upstream to the projects this depends on.
What blocks vectorization
Worth recognizing, because these are the patterns that leave performance on the table.
Loop-carried dependencies. Each iteration needing the previous result forces sequential execution:
# Cannot vectorize: every step depends on the last
for i in range(1, n):
values[i] = values[i - 1] * decay + inputs[i]
This is a genuine dependency, not a coding mistake. Some such recurrences have parallel formulations; many do not.
Branching per element. Different elements taking different paths defeats uniform execution:
# Divergent
for i in range(n):
out[i] = expensive(x[i]) if x[i] > threshold else cheap(x[i])
# Vectorizable: compute both, select
out = np.where(x > threshold, expensive_vec(x), cheap_vec(x))
The second does more arithmetic and is usually faster anyway, because it stays in vector form.
Irregular memory access. Vector loads want contiguous elements. Random indexing or heavy striding means the loads cannot be coalesced.
Calling into opaque Python. A vectorizer cannot see through an arbitrary Python callback:
# Row-wise Python call: a barrier
df["out"] = df["value"].apply(my_python_function)
# Array operation: optimizable
df["out"] = np.log1p(df["value"]) * 2
apply with a Python function is the most common performance mistake in pandas code, and no amount of
platform optimization removes it.
Precision
Narrower types fit more elements per register:
data = data.astype(np.float32) # twice as many per vector op as float64
float32 is standard for GPU work and adequate for most machine learning and much scientific
computing. Confirm your problem tolerates it. Some numerical methods genuinely need double precision, and a
silently wrong answer is worse than a slow right one.
What to take from this
You do not enable vectorization. You avoid blocking it: prefer array operations over element loops, use
np.where over per-element branches, keep memory access contiguous, and keep Python callbacks out of
hot paths.
Writing code the optimizer can help turns this into practice.