Live data from Hacker News

Memory access on the Apple M1 processor

lemire.me

31–40 of 278 posts

Re: Memory access on the Apple M1 processor

#31
post #2

Great practical information. Nice to see people who know what they are talking about putting data out there. I hope eventually these persistent HN memes about M1 memory will die: that it's "on-die" (it's not), that it's the only CPU using LPDDR4X-4267 (it's not), or that it's faster because the memory is 2mm closer to the CPU (not that either). It's faster because it has more microarchitectural resources. It can load…

> it can do with a single core what an Intel part needs all cores to accomplish.

Care to explain what you mean specifically by this?

Re: Memory access on the Apple M1 processor

#32
post #25

Is the article saying that the M1 is slower than we would have expected in this case? My understanding, based on the article, is that a normal processor, we would have expected arr[idx] + arr[idx+1] and arr[idx] to take the same amount of time. But the M1 is so parallelized that it goes to grab both arr[idx] and arr[idx+1] separately. So we have to wait for both of those two return. Meanwhile, on a less parallelized…

Its a little confusing because they're conflating the idea that you almost certainly read at least the entire word (and not a single byte) at a time with the other idea that you could fetch multiple words concurrently.

Any cached memory access is going to read in the entire cache line -- 64 bytes on x86, apparently 128 on M1. This is true across most architectures which use caches; it isn't specific to M1 or ARM.

Re: Memory access on the Apple M1 processor

#33
post #16

Earlier quoted context omitted.

Is it possibly exposed via sysctl, which does support a flag to list all variables?

From sysctl -a on my M1: hw.cachelinesize: 128 hw.l1icachesize: 131072 hw.l1dcachesize: 65536 hw.l2cachesize: 4194304 EDIT: also, when run under Rosetta hw.cachelinesize is halved: hw.cachelinesize: 64 hw.l1icachesize: 131072 hw.l1dcachesize: 65536 hw.l2cachesize: 4194304

M1 cache lines are double of what is commonly used by Intel, AMD and other ARM microarchtectures use. That's significant difference.

Re: Memory access on the Apple M1 processor

#34
post #11

Earlier quoted context omitted.

I seem to recall OSX didn't used to have clock_gettime, so it's news to me that it even exists -- I might have been away from OSX too long. Is there any performance difference between that and mach_absolute_time() ?

It was added some years ago, and I believe mach_absolute_time is actually now implemented in terms of (the implementation of) clock_gettime. The documentation on mach_absolute_time now even says you should use clock_gettime_nsec_np(CLOCK_UPTIME_RAW) instead. macOS also has clock constants for a monotonic clock that increases while sleeping (unlike CLOCK_UPTIME_RAW and mach_absolute_time).

Not yet, at least :)

  _mach_absolute_time:
  00000000000012ec        pushq   %rbp
  00000000000012ed        movq    %rsp, %rbp
  00000000000012f0        movabsq $0x7fffffe00050, %rsi   ## imm = 0x7FFFFFE00050
  00000000000012fa        movl    0x18(%rsi), %r8d
  00000000000012fe        testl   %r8d, %r8d
  0000000000001301        je      0x12fa
  0000000000001303        lfence
  0000000000001306        rdtsc
  0000000000001308        lfence
  000000000000130b        shlq    $0x20, %rdx
  000000000000130f        orq     %rdx, %rax
  0000000000001312        movl    0xc(%rsi), %ecx
  0000000000001315        andl    $0x1f, %ecx
  0000000000001318        subq    (%rsi), %rax
  000000000000131b        shlq    %cl, %rax
  000000000000131e        movl    0x8(%rsi), %ecx
  0000000000001321        mulq    %rcx
  0000000000001324        shrdq   $0x20, %rdx, %rax
  0000000000001329        addq    0x10(%rsi), %rax
  000000000000132d        cmpl    0x18(%rsi), %r8d
  0000000000001331        jne     0x12fa
  0000000000001333        popq    %rbp
  0000000000001334        retq

Re: Memory access on the Apple M1 processor

#35
post #16

Earlier quoted context omitted.

Is it possibly exposed via sysctl, which does support a flag to list all variables?

From sysctl -a on my M1: hw.cachelinesize: 128 hw.l1icachesize: 131072 hw.l1dcachesize: 65536 hw.l2cachesize: 4194304 EDIT: also, when run under Rosetta hw.cachelinesize is halved: hw.cachelinesize: 64 hw.l1icachesize: 131072 hw.l1dcachesize: 65536 hw.l2cachesize: 4194304

Compared to the i9-9880H in my 16" MacBook Pro:

    hw.cachelinesize: 64
    hw.l1icachesize: 32768
    hw.l1dcachesize: 32768
    hw.l2cachesize: 262144
    hw.l3cachesize: 16777216
The M1 doubles the line size, doubles the L1 data cache (i.e. same number of lines), quadruples the L1 instruction cache (i.e. double the lines), and has a 16x larger L2 cache, but no L3 cache.

Re: Memory access on the Apple M1 processor

#36
post #20

Earlier quoted context omitted.

This seems to be a recurring theme with the M1, and one that, in a sense, actually baffles me even more than the alternative. There is no "magic" at play here, it's just lots and lots of raw muscle. They just seem to have a freakishly successful strategy for choosing what aspects of the processor to throw that muscle at. Why is that strategy simultaneously remarkably efficient and remarkably high-performance? What en…

I see two main things behind it: 1. they are the only ones who have 5nm chips because they paid a lot to TSMC for that right 2. they gave up on expandable memory, which lets them solder it right next to the cpu, which likely makes it easier to ship with really high clocks. and/or they just spent the money it takes to get binned lpddr4 at that speed. So a good cpu design, just like AMD and Intel have, but one generati…

In other words: money. Throwing money at the (right) problems made them better than others.

"But doesn't Intel have a lot of money, too?"

Sure, but Intel has also been running around like a headless chicken this past decade (pretty much literally, since Otellini left) combined with them getting very complacent because they had "no real competition."

Re: Memory access on the Apple M1 processor

#37

Earlier quoted context omitted.

>> My understanding, based on the article, is that a normal processor, we would have expected arr[idx] + arr[idx+1] and arr[idx] to take the same amount of time. That depends. If the two accesses are on the same cache line, then yes. But since idx is random that will not happen sometimes. He never says how big array[] is in elements or what size each element is. I thought DRAM also had the ability to stream out conse…

> There's not enough info to figure out what's going on. If you only look at the article this is true. However, the source code is freely available: https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/...

[deleted]

Re: Memory access on the Apple M1 processor

#38

Earlier quoted context omitted.

>> My understanding, based on the article, is that a normal processor, we would have expected arr[idx] + arr[idx+1] and arr[idx] to take the same amount of time. That depends. If the two accesses are on the same cache line, then yes. But since idx is random that will not happen sometimes. He never says how big array[] is in elements or what size each element is. I thought DRAM also had the ability to stream out conse…

> There's not enough info to figure out what's going on. If you only look at the article this is true. However, the source code is freely available: https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/...

I ran the benchmark on my system

It's a 6 years old system, fastest times are in the 25ns range

- 2-wise+ is 5% slower than 2-wise

- 3-wise is 46% slower than 2-wise

- 3-wise is 39% slower than 2-wise+

on the M1

- 2-wise+ is 40% slower than 2-wise

- 3-wise is 46% slower than 2-wise

- 3-wise is 4% slower than 2-wise+

Re: Memory access on the Apple M1 processor

#39
post #20
post #2

Great practical information. Nice to see people who know what they are talking about putting data out there. I hope eventually these persistent HN memes about M1 memory will die: that it's "on-die" (it's not), that it's the only CPU using LPDDR4X-4267 (it's not), or that it's faster because the memory is 2mm closer to the CPU (not that either). It's faster because it has more microarchitectural resources. It can load…

This seems to be a recurring theme with the M1, and one that, in a sense, actually baffles me even more than the alternative. There is no "magic" at play here, it's just lots and lots of raw muscle. They just seem to have a freakishly successful strategy for choosing what aspects of the processor to throw that muscle at. Why is that strategy simultaneously remarkably efficient and remarkably high-performance? What en…

> What enabled/led them to make those choices where others haven't?

Others have to some extent — AMD is certainly not out of the game — so I'd treat this more as the question of how they've been able to go more aggressively down that path. One of the really obvious answers is that they control the whole stack — not just the hardware and OS but also the compilers and high-level frameworks used in many demanding contexts.

If you're Intel or Qualcomm, you have a wider range of things to support _and_ less revenue per device to support it, and you are likely to have to coordinate improvements with other companies who may have different priorities. Apple can profile things which their users do and direct attention to the right team. A company like Intel might profile something and see that they can make some changes to the CPU but the biggest gains would require work by a system vendor, a compiler improvement, Windows/Linux kernel change, etc. — they contribute a large amount of code to many open source projects but even that takes time to ship and be used.

Re: Memory access on the Apple M1 processor

#40
post #29

Ok, summary: This article lays out three scenarios: 1) accessing two random elements 2) accessing 3 random elements 3) accessing two pairs of adjacent elements (same as (1) but also the elements after each random element) It then does some trivial math to use the loaded data. A naive model might only consider memory accesses and might assume accessing an adjacent element is free. On the Mac m1 core, this is not the c…

I don't really understand the comparison because it seems like scenario 3 (2+) is doing more XORs and twice the accesses to array over the same amount of iterations.

We have to assume these are byte arrays, yes? Or at least some size that's smaller than the cache line. You would still pay for the extra unaligned fetches. I don't think this is a valid scenario at all, M1 or not.

Anyone want to run these tests on an Intel machine and let us know if the authors "naive model" test hold there?

Post reply on HN