Cortex-A · 12 pages
big.LITTLE & DynamIQ
ARM's asymmetric multiprocessing — the evolution from big.LITTLE cluster migration through global task scheduling to DynamIQ's mixed-core single-cluster design, with the Linux Energy Aware Scheduler tying it all together.
Phones can't run their cores at full speed for long — the battery dies, the silicon throttles, the user notices. The traditional answer was DVFS (dynamic voltage and frequency scaling) on a homogeneous CPU set: clock down when idle, clock up when busy. ARM's answer was bolder: ship two CPU designs in the same SoC — a small, efficient core for low-load work and a big, fast core for bursts — and let the scheduler migrate threads between them.
That idea, big.LITTLE, launched with the Cortex-A15 (big) + Cortex-A7 (LITTLE) in 2013 and has driven every subsequent mobile and many automotive ARM SoCs. DynamIQ, introduced with Cortex-A75 in 2017, generalizes the idea: rather than two separate clusters, DynamIQ allows up to eight cores of mixed types in a single L3-shared cluster, with finer-grained voltage and frequency control. This page walks through the architecture, the scheduler decisions, and the engineering details that make it work.
- Original big.LITTLE (2013)
- Cortex-A15 + Cortex-A7. Two separate clusters with CCI-400 between. Same ISA, same memory model.
- Modern big.LITTLE
- Cortex-A76 + Cortex-A55, A78 + A55, Cortex-X1 + A78 + A55 (tri-cluster). Mobile SoCs 2018+.
- DynamIQ (2017+)
- Cortex-A75 onward. Mixed cores in one DSU cluster, shared L3, per-core DVFS, voltage rails per core type.
- Migration modes
- Cluster migration (early), CPU migration (in-kernel switcher, IKS), Global Task Scheduling (GTS), Energy Aware Scheduling (EAS)
- L3 cache (DynamIQ)
- 512 KB – 8 MB, shared across all cores in the DSU cluster
- Per-core capacity scaling
- /sys/devices/system/cpu/cpuN/cpu_capacity — scheduler-visible capacity number, typically 256–1024
- Linux EAS
- Energy Aware Scheduler, mainline since 4.5. Uses an Energy Model from DT or sysfs.
- Examples
- Snapdragon 8 Gen 2 (X3+A715+A510), MediaTek Dimensity 9300 (X4+A720), Apple M-series uses similar concept (P+E cores)
Why asymmetric
The fundamental observation: the curve of "performance per watt" is not linear across CPU designs. A big out-of-order superscalar core delivers high IPC but at a cost — more transistors, more leakage, more switching capacitance per cycle. At low loads, a small in-order core delivers far better perf/W. Plot watts vs. compute throughput for a small core and a big core overlaid, and the small core's curve lies entirely below the big core's curve at low end and the big core dominates above some crossover point.
A homogeneous design picks a single point on that surface. A heterogeneous design lets the OS pick the right core for each thread, dynamically. That's the big.LITTLE bet: matching threads to cores in real time can give 30–60% energy savings at iso-performance, or significantly better burst performance at iso-thermal-budget.
Generation 1: Cluster Migration
The original big.LITTLE configuration migrated entire clusters at a time. When load was low, the big cluster was powered off and all threads ran on LITTLE. When load rose, the big cluster powered up, threads migrated en masse, and the LITTLE cluster powered down.
This was simple but coarse. A single demanding thread would force the entire big cluster online — all four big cores — even though only one was needed. Energy was wasted on idle big cores.
Generation 2: IKS (In-Kernel Switcher)
The In-Kernel Switcher paired each big core with a LITTLE core: vCPU 0 was either big-core 0 or LITTLE-core 0 depending on load, but never both simultaneously. The kernel saw the system as N "virtual CPUs," each backed by a pair, with the kernel choosing which physical core ran the work.
Still coarse — you couldn't have one big core busy and three LITTLE cores busy at once. But it allowed per-vCPU power tuning.
Generation 3: Global Task Scheduling (GTS)
GTS was the breakthrough. The kernel sees all cores as schedulable resources — 8 cores on a 4+4 system — and chooses for each thread which to run. Threads can be on big and LITTLE simultaneously. The scheduler uses per-CPU load-tracking signals (PELT — Per-Entity Load Tracking, mainline since 3.8) to decide.
GTS exposed the missing piece: the scheduler didn't natively understand that different cores have different capacities. A 50%-loaded big core might be doing more work than a 100%-loaded LITTLE core. The scheduler would balance load (say, by RT runqueue length or by raw cycles) without understanding this — leading to suboptimal placement.
Generation 4: EAS (Energy Aware Scheduling)
EAS, mainline since Linux 4.5 and now baseline for all mobile ARM Linux kernels, gives the scheduler an Energy Model of the SoC. The energy model is a table per performance domain (clock-domain typically maps to a CPU type) of (frequency, capacity, power) tuples. The scheduler can answer: "if I place this task on this CPU at this frequency, what's the cost in watts?"
// Simplified EAS placement logic
for_each_candidate_cpu(cpu) {
cap = get_cpu_capacity(cpu);
new_util = task_util + cpu_util(cpu);
if (new_util > cap) continue; // exceeds capacity
new_freq = required_frequency(new_util, cap);
energy = energy_model[cpu][new_freq];
if (energy < best_energy) {
best_cpu = cpu;
best_energy = energy;
}
}
return best_cpu;The model is populated from device tree energy-model nodes or from sysfs at runtime. Vendor BSPs ship the table for their SoC; mainline Linux's cpufreq-policy and EAS framework consume it.
The result: per-task placement that's energy-optimal. A latency-sensitive UI thread runs on the big core; a background sync thread runs on the LITTLE; CPU-bound benchmarks max all cores; the scheduler picks based on the cost-function rather than a heuristic.
DynamIQ — one cluster, mixed cores
DynamIQ replaces the two-cluster architecture with the DSU (DynamIQ Shared Unit): a single cluster that holds up to eight cores of any mix, sharing an L3 cache and a snoop unit. The CPU types within a single DSU can be heterogeneous — for example, one Cortex-A78 plus three Cortex-A55s plus four more A55s in a single DSU.
Key DynamIQ properties:
- Shared L3 — typically 1–4 MB, accessed at single-cluster latency by all cores. Avoids the cross-cluster snoop traffic that big.LITTLE had through CCI.
- Per-core voltage and frequency — each core has its own DVFS domain. A single core can boost while others stay idle.
- Adaptive cache partitioning — the L3 can be partitioned per core to limit interference (Cortex-A78+).
- Up to 8 cores per cluster — the DSU-110 supports 8, DSU-120 supports 14, DSU-AE (automotive) supports 16.
The Cortex-X line (X1, X2, X3, X4) is designed as the "biggest" core in a DynamIQ cluster, typically deployed as a 1+3+4 configuration (1×X-class, 3×big, 4×LITTLE). The Cortex-A510 and A520 are the modern LITTLE cores, designed in pairs that share a single L2 cache (one of the more interesting DynamIQ-era choices).
Per-CPU capacity
Linux exposes per-CPU capacity to the scheduler via:
$ cat /sys/devices/system/cpu/cpu0/cpu_capacity
256
$ cat /sys/devices/system/cpu/cpu4/cpu_capacity
1024Capacity is a relative number scaled so the biggest core in the system has capacity 1024. A Cortex-A55 typically reports ~256 against a Cortex-X1's 1024. The scheduler uses capacity in three places:
- Util tracking — task utilization is normalized against capacity. A 100% utilized A55 is "256 units" of compute, equal to ~25% of an X1.
- Misfit detection — a task running on an A55 that would benefit from a bigger core is flagged "misfit" and considered for migration.
- Frequency selection —
schedutilcpufreq governor uses task utilization to pick the lowest frequency that meets demand on the current CPU.
Vendor kernels often tune these numbers based on workload measurements. Stock Android Common Kernel uses the values from DT.
DVFS — voltage/frequency tuning
Each performance domain has a list of <frequency, voltage> operating points (OPPs). The cpufreq driver (scmi-cpufreq or armada-cpufreq or vendor-specific) talks to the SCMI firmware or the SoC's PMU to change OPP.
A typical big core OPP table:
| Frequency | Voltage | Power (mW) |
|---|---|---|
| 614 MHz | 0.6 V | 90 |
| 1050 MHz | 0.65 V | 250 |
| 1804 MHz | 0.75 V | 720 |
| 2400 MHz | 0.85 V | 1450 |
| 2900 MHz | 1.00 V | 3200 |
The power-frequency curve is roughly cubic — doubling frequency more than doubles power. At the top OPP, the same chip can hit 3 W on one core; running at half frequency at half voltage, it draws 1/8 the power for half the compute — much better perf/W if you can afford the latency.
EAS uses this curve to make decisions like: "running a task on the big core at 1050 MHz costs less than running it on the LITTLE core at 1800 MHz because the LITTLE core would be at its top OPP and burning voltage."
Frequency-invariant accounting
A subtle but crucial detail: when EAS computes utilization, it does so in frequency-invariant units. A task that consumes 100% of one CPU running at 1 GHz is "scaled" against the CPU's maximum frequency — say 3 GHz — and tracked as 33% utilization. If the scheduler decides to migrate it to a CPU with capacity 1024 that's currently running at 1.5 GHz, it knows the task will need (33% × 1.5 GHz) / 3 GHz = 16.7% of that CPU at that frequency.
Without this scaling, the scheduler would think the task "fits" on a small CPU because it only used 33% of its current CPU — but the small CPU might not have the absolute capacity.
The kernel reads the current frequency from the cpufreq driver and divides by max_frequency to compute the scaling factor. Each PELT tick of util is multiplied by both the capacity ratio and the frequency ratio.
Migration cost
Moving a thread from one core to another has overhead — register state moves, cache state is lost (or re-pulled via coherency), TLB entries are cold. Within a DynamIQ cluster sharing L3, migration is cheap (~5–10 µs typically) because the working set is still in L3. Cross-cluster migration on traditional big.LITTLE is more expensive (~30–50 µs) due to having to re-fetch from the other cluster's L2.
The scheduler tracks migration cost via the sched_migration_cost_ns tunable (default 500 µs on most systems). Tasks aren't migrated more often than this even if rebalancing would otherwise suggest it.
Examples — modern SoCs
Snapdragon 8 Gen 3: 1×Cortex-X4 @ 3.3 GHz, 3×A720 @ 3.15 GHz, 2×A720 @ 2.96 GHz, 2×A520 @ 2.27 GHz. Three performance levels, all in one DynamIQ DSU-120 cluster.
MediaTek Dimensity 9300: 1×X4, 3×X4 (smaller), 4×A720. No LITTLE cores at all — radical departure, with all 8 cores being relatively big. Tuned aggressively with DVFS to manage power.
Apple M-series (similar concept, different design): separates Performance (P) cores from Efficiency (E) cores in distinct clusters, with macOS's QoS classes acting as scheduling hints rather than kernel-driven EAS. The architectural ideas overlap.
Cross-references
- SMP & cache coherency — cross-cluster snoop traffic and CCI/CMN
- TLB & address translation — TLB sizing differences across core types
- PMU & profiling — measuring per-CPU utilization
- ISA across generations — SVE availability differs across LITTLE and big cores
- Linux kernel:
kernel/sched/fair.c,kernel/sched/sched.h,Documentation/scheduler/sched-energy.rst