Why ARM MTE Has No Single Performance Cost

ARM Memory Tagging Extension (MTE) is meant to make a difficult security compromise more practical: detect memory-safety failures in native software without requiring every program to be rewritten. The question this series examines is not whether MTE has an overhead in the abstract. It is why the same protection can be cheap in one workload, sharply expensive in another, and useful for some security jobs but not for others. The reader’s practical task is to learn what must be measured before treating any MTE number as a deployment decision.

That distinction matters because security features live or die by the resources they consume. A feature that makes a critical service too slow, unpredictable, or difficult to diagnose may be disabled even when its protection is valuable. Conversely, a reassuring average can encourage adoption without revealing a rare workload that suffers a severe regression. MTE’s performance is therefore part of its security story: cost affects whether the feature is enabled, where it is enabled, and which guarantees operators are willing to accept.

The production question behind the benchmark

MTE attaches metadata to memory and checks that metadata when software accesses it. In broad terms, that allows hardware to notice many use-after-free and buffer-overflow bugs. But noticing an invalid access requires work around ordinary memory operations, and the work is carried out by a real processor, not by an idealized instruction-set diagram. The USENIX study ARM MTE Performance in Practice examines that reality across the Google Pixel 8 and 9, AmpereOne server processors, and a preliminary analysis of Apple’s M5. It tests both traditional CPU benchmarks and server workloads such as databases, a web server, and an in-memory key-value service.

The attraction is a rare combination of properties. MTE is designed to cover both temporal and spatial memory errors, to work with existing applications with relatively small operating-system and allocator changes, and to be inexpensive enough for production use. Those are design goals, not guarantees delivered uniformly by every processor. They also pull in different directions: broader checking means more accesses participate in the mechanism, compatibility means the hardware must fit beneath existing software, and production viability depends on the cost of the resulting checks. The performance study is valuable because it examines that combination in silicon rather than assuming that the architectural interface settles the question.

The study’s most important result is not a single average. Many runs have modest overheads, but selected cases slow dramatically. On a Pixel Performance core, one SPEC benchmark reaches 6.64 times the no-MTE runtime in SYNC mode; another reaches 2.37 times. On a Pixel Big core, some slowdowns remain large even in ASYNC mode, which is intended for lower-cost production detection. AmpereOne and Apple M5 show lower overall SPEC geomeans in the reported tests, yet each has its own outliers. Those observations do not contradict one another. They show that “the MTE cost” is an incomplete question.

A normalized runtime is a ratio to a particular baseline. A result of 1.20× means the measured run took 20% longer than that baseline; it does not mean every application on that device will be 20% slower. A geomean summarizes a set of programs, but it can hide the one hot path that dominates a service’s user-visible latency. Conversely, a local regression may disappear in a distributed deployment if network or another server becomes the bottleneck. The number is meaningful only with the boundary around it.

That boundary also changes when the comparison is not “MTE versus nothing.” A team might be choosing between MTE and copying data across an isolation boundary, changing page permissions for tracing, or inserting software checks for a sandbox. In those cases, the relevant result is the cost of the complete protection, including the work MTE replaces and the work it adds. A feature can be a poor general-purpose replacement while still being the best fit for a narrow security boundary.

flowchart LR N01["MTE tag check"] --> N02["Operating mode"] N02 --> N03["Core microarchitecture"] N03 --> N04["Workload and memory pattern"] N04 --> N05["Allocator and kernel integration"] N05 --> N06["Observed cost and security value"]

One feature, several owners of cost

The first owner is the MTE mode. SYNC stops at a mismatch and preserves precise information about the offending access, which makes it valuable for development and diagnosis. ASYNC relaxes the timing relationship between the tag check and the memory operation and reports the problem later, trading diagnostic precision for a lower-cost production posture. Android’s platform documentation also describes ASYMM, which checks reads synchronously and writes asynchronously. These modes change the handling of a mismatch, but they do not make the underlying tag-check work disappear.

The second owner is the core. A processor must decide how tag data is stored, fetched, checked, and tracked while ordinary instructions continue through the pipeline. Two cores can implement the same architectural interface while making different choices about cache lines, memory bandwidth, store ordering, or the number of checks that can remain in flight. A design that handles one extra piece of metadata with little disruption may expose a bottleneck when a stream of stores or cache misses arrives.

The third owner is the workload. Sequential accesses, random pointer chasing, large working sets, frequent stores, and large allocations stress different parts of a processor and allocator. A benchmark with a low average memory rate can still create an unfavorable sequence of tag checks. The relevant question is not simply how much memory a program touches, but what kind of access arrives, how much locality it has, and how many operations the hardware must keep pending.

The fourth owner is the surrounding software stack. Tagging can consume time when allocations are created or reused. Kernel policy can cause tag-check work outside the application’s own heap. Whether a test runs locally with its load generator or across machines can change which cost is visible. Even the coverage of tagged mappings matters: a result from a path where only some memory is actually protected cannot be treated as evidence about a fully protected process.

Finally, MTE may be doing more than ordinary probabilistic heap protection. Retagging a buffer can protect a boundary against a time-of-check to time-of-use attack. A tag mismatch can be used as a data-tracing event. Tags can also be compared with software fault isolation or control-flow defenses. In each case, the right baseline changes. Replacing a copy, a page-permission change, or dynamic instrumentation is a different performance question from enabling MTE on an otherwise unchanged application.

These owners are coupled rather than independent. A mode changes the ordering requirements that a core must implement; a workload determines whether that ordering becomes visible; and the allocator or kernel can add work before the application reaches its hot loop. The useful question is therefore not which component is “to blame” in isolation. It is which path through the system owns the measured time, and whether changing that path preserves the protection the team actually needs.

Why a low average can hide a serious decision

The headline contrast in the study is between broad modestness and narrow severity. Pixel Little cores show relatively small variation in the SPEC measurements, while out-of-order Pixel cores expose much larger differences. AmpereOne’s reported SPEC 2006 geomean is 1.10×, but one benchmark reaches 1.43×. The AmpereOne and M5 SPEC 2017 geomeans are close to baseline in the single-core tests, yet a particular large-allocation input reaches 1.25× and 1.29× respectively. An operator deciding whether to protect a service cannot use the geomean without asking whether the service resembles the outlier.

The reverse mistake is equally dangerous. Seeing a 6.64× result does not justify saying that MTE makes a device 6.64 times slower. The study links that extreme case to a store-heavy loop on a particular Pixel Performance core and SYNC implementation. It finds a different pattern on the Pixel Big core, where certain mixed access streams create pressure on structures that track in-flight tag checks. AmpereOne’s prominent case is associated with store-to-load forwarding. These are different mechanisms with different prospects for repair.

The server results make the same point from another direction. Several server workloads have overheads that are generally below the largest SPEC outliers, but Memcached initially shows a slowdown as high as 1.40× on many cores. The authors trace that regression to unnecessary kernel tag checks in the tested AmpereOne Linux configuration and reduce the worst case to about 1.05× with a kernel change. In a remote multi-server setup, Memcached and Nginx show no statistically significant difference between MTE and no MTE. The performance question has moved because the system boundary has moved.

This is why a credible MTE evaluation needs more than a device name and an average. It needs the mode, core type, workload and access pattern, allocator behavior, operating-system policy, baseline, and measurement topology. Those details are not bureaucratic decoration. They identify which component owns the observed result and whether the result transfers to the system being considered.

What the evidence can—and cannot—say

The evidence supports a strong but bounded conclusion. Current MTE implementations can often provide useful memory-safety defense with modest cost, and they can produce severe slowdowns in particular combinations of core, mode, and workload. Some of the largest observed costs look like implementation limitations rather than unavoidable consequences of tagging: the study identifies store ordering, in-flight tag-check capacity, and store-to-load forwarding as distinct failure surfaces, and Ampere reported that its forwarding issue was fixed in a later generation. Other costs, such as diagnostic precision or handling a mismatch as a tracing event, involve deliberate trade-offs rather than simple bugs.

The evidence does not support a universal MTE tax, a guarantee that ASYNC is always cheap, or a claim that the tested Apple, Pixel, or Ampere results apply unchanged to every ARM system. Nor does MTE provide deterministic memory safety: its tags are probabilistic, and its protection has boundaries that matter independently of performance. Android’s guidance consequently treats MTE as a staged policy—precise checking during development, lower-cost coverage in production, and device-specific configuration—not as a switch whose consequences are known in advance.

The right opening question, then, is not “How much does MTE cost?” It is “What does MTE add to this access, on this core, in this mode, inside this software stack, for this security purpose?” Answering that question starts with the smallest unit MTE actually checks: a tagged 16-byte memory granule and the pointer that claims to refer to it.

References