TechX

The 14 cores in an M4 Pro are not 14 of the same thing

One spec-sheet number hides two core designs, three cache clusters and a 4x asymmetry in shared L2. The command that exposes all of it is already on your Mac.

Tested on MacBook Pro (Mac16,8) · Apple M4 Pro · macOS 26.3.1 (25D771280a) · July 2026

Apple sells this machine as having a 14-core CPU. That is accurate, and it describes two different core designs arranged in three cache clusters with a fourfold difference in shared L2 between them. Every one of those details is readable with one command, and none of it appears on the spec sheet.

sysctl -a | grep -E "hw\.(nperflevels|physicalcpu|logicalcpu|perflevel[01]\.)" | sort

What the machine reports

hw.physicalcpu: 14
hw.logicalcpu: 14
hw.nperflevels: 2

hw.perflevel0.name: Performance
hw.perflevel0.physicalcpu: 10
hw.perflevel0.l1icachesize: 196608
hw.perflevel0.l1dcachesize: 131072
hw.perflevel0.l2cachesize: 16777216
hw.perflevel0.cpusperl2: 5

hw.perflevel1.name: Efficiency
hw.perflevel1.physicalcpu: 4
hw.perflevel1.l1icachesize: 131072
hw.perflevel1.l1dcachesize: 65536
hw.perflevel1.l2cachesize: 4194304
hw.perflevel1.cpusperl2: 4

Rendered in units people can hold in their heads:

Performance Efficiency Ratio
Cores 10 4 2.5×
L1 instruction 192 KB 128 KB 1.5×
L1 data 128 KB 64 KB
Shared L2 16 MB 4 MB
Cores per L2 5 4
L2 asymmetry n=1 perflevel0 l2cachesize 16 MB against perflevel1 4 MB

The cluster count nobody quotes

cpusperl2 is the field that changes the mental model. It reports 5 for the performance level. With 10 performance cores, that means the performance cores are not one pool of ten sharing a cache. They are two groups of five, each with its own L2.

Add the efficiency side, where 4 cores share one 4 MB L2, and the chip is three cache domains rather than one:

[ P P P P P ] 16 MB L2      cluster 1
[ P P P P P ] 16 MB L2      cluster 2
[ E E E E ]    4 MB L2      cluster 3

That arrangement has a consequence that a flat core count cannot express. Two threads sharing data run at different speeds depending on whether they landed in the same cluster. Inside a cluster they share L2 and coordinate cheaply. Across clusters they coordinate through the next level of the memory system, which is slower. Nothing in user space lets you choose, and macOS does not tell you afterwards which cluster a thread ran on.

L2, performance 5 cores share it 16 MB L2, efficiency 4 cores share it 4 MB L1d, performance per core 128 KB L1d, efficiency per core 64 KB
Cache sizes reported per performance level. The core count treats all fourteen as equivalent; the cache figures do not.

No hyperthreading, and why that is the interesting part

hw.physicalcpu and hw.logicalcpu both read 14. On an Intel machine with simultaneous multithreading these differ, typically by a factor of two, because each physical core presents two logical threads that share its execution resources.

Apple Silicon has never done this. 14 cores means 14 hardware threads, and each of them has a full set of execution resources to itself.

This matters when comparing against an x86 part with a similar-looking thread count. A 14-thread Intel chip is typically 7 physical cores with contention between paired threads, and its throughput under full load is well short of 14 independent cores. A 14-thread M4 Pro is 14 independent cores, four of which are deliberately smaller. The two “14s” describe quite different machines, and neither is straightforwardly better.

14
Hardware threads n=1 hw.logicalcpu equal to hw.physicalcpu, so no SMT

Reading a benchmark with this in mind

Two habits change once the topology is visible.

A multi-core score is not divisible by the core count to get a per-core figure. Four of the fourteen cores are efficiency cores with half the L1 data cache and a quarter of the shared L2, and they contribute meaningfully less. Dividing a 14-core result by 14 produces a number that describes no core on the chip.

A single-core score depends on where the work landed. macOS assigns by quality-of-service class, so a benchmark that declares a user-interactive QoS gets a performance core and one that does not may get an efficiency core. Comparing two single-core figures across machines is only meaningful if both ran on the same class of core, and the score alone does not tell you.

What the fields do not say

l2cachesize is reported per performance level, next to a cpusperl2 value. It does not state whether 16 MB is the size of each cluster’s L2 or a total across the level. Reading it alongside cpusperl2: 5 points strongly at per-cluster, but sysctl does not confirm it, and this article is not going to assert a chip-wide L2 total that the machine never reported.

There is also no field here for the system level cache that sits behind L2 and is shared with the GPU, and no per-core frequency reporting. Sustained frequency behaviour under thermal load requires powermetrics, which needs root and is a separate measurement.

The command, once more

sysctl -a | grep -E "hw\.(nperflevels|physicalcpu|logicalcpu|perflevel[01]\.)" | sort

Run it on any Apple Silicon Mac. The core count you paid for will be there, and so will the two or three numbers underneath it that determine what that count actually means on your particular chip.

Watching the split show up in practice

The topology is static description. The effect of it is observable with one experiment that needs nothing but the compiler already on the machine.

#include <stdio.h>
int main(void){
  volatile double x = 0;
  for (long i = 0; i < 400000000L; i++) x += i * 0.5;
  printf("%f\n", x);
  return 0;
}
clang -O1 -o spin spin.c
/usr/bin/time -p ./spin                    # default quality of service
/usr/bin/time -p taskpolicy -b ./spin      # background quality of service

On this machine the identical binary took 0.865 seconds under the first invocation and 2.61 seconds under the second, a factor of 3.02. taskpolicy -b places the process in the background quality-of-service band, which confines it to the efficiency cluster. Nothing about the code changed; only which four of the fourteen cores were willing to run it.

That is the core split made concrete, and it is why treating a 14-core figure as fourteen equivalent units produces conclusions that do not survive contact with a stopwatch.

What the cluster arrangement costs in software

Two threads that share data run at different speeds depending on whether they landed in the same cluster. Inside a cluster they share an L2 and coordinate through it. Across clusters they coordinate through the next level of the memory hierarchy, which is slower.

macOS gives user space no control over this. There is no affinity API on Apple Silicon that pins a thread to a core or to a cluster, and there is no way to query afterwards which cluster a thread used. The scheduler makes the decision from the quality-of-service class and its own view of the machine.

For most software that is the right arrangement and the absence of control is not a limitation worth complaining about. It matters in exactly one situation: when benchmarking a tightly-coupled parallel workload and finding run-to-run variance that no change to the code explains. Some of that variance is cluster placement, and it is not something you can eliminate by trying harder.

Comparing this against other chips honestly

The temptation with a core count is to compare it against another core count, and the topology here makes most such comparisons misleading in a specific direction.

Against an x86 part with simultaneous multithreading, 14 threads on this chip are 14 independent cores while 14 threads there are typically 7 physical cores sharing execution resources in pairs. The Apple part has more genuine parallelism than the number suggests relative to the Intel one.

Against another Apple Silicon part, the split is what varies. A base M4 carries fewer performance cores and proportionally more efficiency cores, so its total core count overstates its sustained throughput relative to a Pro. Reading the perflevel counts rather than the headline figure is the only way to see this, and it takes one command on any machine you can reach a terminal on.

The command, once more

sysctl -a | grep -E "hw\.(nperflevels|physicalcpu|logicalcpu|perflevel[01]\.)" | sort

Run it on any Apple Silicon Mac. The core count you paid for is in there, and so are the two or three values underneath it that determine what that count actually means on your particular chip.

Takeaways

  • The 14 cores are 10 performance and 4 efficiency, and the two types report different L1 and L2 sizes at every level.
  • Five cores share each performance L2, so the 10 performance cores sit in two separate clusters rather than one pool.
  • Performance cores report a 16 MB shared L2 against 4 MB for the efficiency cluster, a 4x difference.
  • physicalcpu equals logicalcpu at 14, so there is no simultaneous multithreading: 14 cores means exactly 14 hardware threads.

Questions

Why does this matter if macOS schedules work for me?
For most software it does not, and that is the intended outcome. It matters when you are interpreting a benchmark, because a test that saturates 14 threads is not exercising 14 equivalent cores, and a single-threaded result depends entirely on which core type the work landed on.
Can I force work onto the performance cores?
Not directly. macOS schedules by quality-of-service class, so the lever available to a developer is declaring the right QoS on a work item. Nothing in user space pins a thread to a specific core.
Is the 16 MB L2 per cluster or shared across all performance cores?
sysctl reports it per performance level alongside a cpusperl2 value of 5, which indicates 5 cores share one L2. With 10 performance cores that implies two such caches. The field does not state a total, so this article reports what it says rather than inferring a chip-wide figure.

Sources

What we read. Distinct from what we measured, which is in the article itself.

About the author

Teja Pagidimarri

11+ years in content marketing and SEO, based in Hyderabad, India. Every measurement published on TechX was taken by hand on the hardware listed in how we test.