Comparing SSD performance between T2 and M1 Macs with Stibium

Macs currently available offer two potent controllers for their internal SSDs: the T2, available in Intel models, and M1 SoC in the first Apple Silicon Macs. In the face of disparate benchmarks between systems, I’ve decided to explore their performance using my own code. Here are the first results, using my free app Stibium.

Aim

What I’m interested in is whether a user running apps on an M1 Mac can expect to see performance improvements in apps writing to and reading from their internal SSD. Engineering benchmarks are all very well, but most users simply want an answer to the question as to whether they will see speed improvements. A useful analogue is raw performance of an engine benchtested to give what we used to refer to as brake horsepower, against a road test of the vehicle. Road tests are less rigorous and subject to more vagaries, but they tell you whether all that power accomplishes anything on the road.

Tool

My free utility Stibium is my platform for testing file read and write performance. Rather than use low-level access to the internal SSD, I’ve deliberately used the sort of simple code which might be employed in a regular app. Currently, Stibium doesn’t perform more than one test at a time: you can set it to write a single file of specified size, and to read any file. It then reports the number of bytes transferred, and the time interval taken.

It does this using File Handles, whose interface has changed as of macOS 10.15.4, so uses code which should work well on macOS Sierra to 10.15.3, and on 10.15.4 and later. It’s a Universal Binary, so runs native on Apple Silicon Macs. Here’s my Swift code for the critical sections:

Write:
let theFHandle = try FileHandle.init(forWritingTo: url)
if #available(OSX 10.15.4, *) {
theStart = Date()
try theFHandle.write(contentsOf: data)
try theFHandle.synchronize()
theEnd = Date()
try theFHandle.close()
} else {
theStart = Date()
theFHandle.write(data)
theFHandle.synchronizeFile()
theEnd = Date()
theFHandle.closeFile() }
let theDuration = theEnd.timeIntervalSince(theStart)
theTime = theDuration.magnitude

Read:
let theFHandle = try FileHandle.init(forReadingFrom: url)
if #available(OSX 10.15.4, *) {
try theFHandle.seek(toOffset: fromOffset)
theStart = Date()
let theData = try theFHandle.read(upToCount: amount)
try theFHandle.synchronize()
theEnd = Date()
let theSize = theData?.count ?? 0
if theSize < amount {
theEnd = theStart }
try theFHandle.close()
} else {
theFHandle.seek(toFileOffset: fromOffset)
theStart = Date()
let theData = theFHandle.readData(ofLength: amount)
theFHandle.synchronizeFile()
theEnd = Date()
let theSize = theData.count
if theSize < amount {
theEnd = theStart }
theFHandle.closeFile() }
let theDuration = theEnd.timeIntervalSince(theStart)

You can download a copy of Stibium, which has been notarized but lacks any documentation apart from this article, from here: stibium10b2

Initial testing

Writing and reading test files one at a time appears to produce fairly reliable timings unless the same file is read repeatedly. When I have written out a sequence of five or more test files of different sizes, then read them back in, there’s no evidence that they’re simply being cached. Transfer rates are normally of the order of 3 GB/s, and fairly consistent between runs on the same system.

First measurements of gross transfer rates

For the first formal measurements, I set both Macs – my production iMac Pro with a T2 chip and 1 TB internal SSD, and my M1 Mac mini with a 500 GB internal SSD – running after a restart, with the Finder and Stibium as the only apps running. The iMac Pro has all sorts of additional background processes, including Adobe CC. Test runs were performed in between automatic backups, when no other disk activity was expected.

For each run I wrote a series of test files of 20 different sizes, starting with 50 KB and rising to 2 GB, the maximum which can be written using that code (Stibium uses different code to write test files larger than that). Having written each file in sequence, I then read them in the same sequence, so there were 19 file writes and reads between each test file being written and read back. I then pasted the time differences into DataGraph for analysis.

Analysis

Conventionally, when benchmarking storage, multiple test runs are performed in rapid succession using files of the same size. My measurements were different, so I used linear regression to assess the relationship between file size (X) and time taken (Y). I also calculated the transfer rate for each size of test file, which is the conventional measure.

StibiumT2

The relationship between size transferred and time taken is largely linear for both Macs. Using the T2 controller (above), read performance (red) was better at file sizes below 600 MB, but write performance (blue) was more consistent across the whole range of test sizes.

StibiumM1

On the M1 Mac, there appeared to be a read performance optimum around 800 MB to 1 GB, but other measurements were close to the regression lines, and there was less difference between read and write performance.

Results

These are preliminary results from an initial test, and great care is needed in their interpretation.

Regressions for the T2 system give overall transfer rates of 3.8 (read) and 3.5 (write) GB/s. Peak read performance occurred between 60-400 MB files, and was around 5 GB/s. Peak write performance was above 200 MB file size, and was around 3.0 GB/s.

Regressions for the M1 system give overall transfer rates of 2.7 (read) and 2.9 (write) GB/s. Peak read performance occurred between 500 KB and 1 MB where it reached 6.5 GB/s, and above 800 MB, where it reached 4.7 GB/s. Peak write performance was at file sizes of greater than 20 MB, where it reached 3.9 GB/s.

This suggests that the two systems have quite different performance characteristics. Although the regression lines suggest better overall performance for the T2 system, with file sizes larger than 20 MB, writing on the M1 was consistently faster, at more than 3.5 GB/s. With file sizes larger than 400 MB, read rates on the T2 system fell to 2.6 GB/s, but remained above 3.5 GB/s on the M1.

It might have been possible to estimate latencies from the intercepts of linear regression, but those are inconveniently all negative! However, when using files smaller than 500 KB, transfer times were little affected by file size, suggesting they were close to latency. For the T2, these were 3 x 10-5 seconds for read, and as low as 2 x 10-5 seconds for write. For the M1, these were 2.8 x 10-5 seconds for read, and 4 x 10-4 seconds for write.

Summary

The approach used in Stibium appears to return transfer rates which are not dissimilar to those reported by other benchmarking apps. These initial results suggest that – at this relatively high level – there are significant differences in the performance of internal SSD storage in Intel Macs equipped with a T2 chip, and M1 Macs. These differences aren’t simple, and neither is obviously a better performer than the other.

I’m going to continue to develop Stibium and explore the results it produces. I welcome your constructive comments.

Footnote: Why Stibium?

The word contains the letters STorage BenchMarks in the correct order. Stibium is the highly toxic element antimony, which has the chemical symbol Sb derived from the word root. More specifically, stibium refers to the mineral stibnite, which was used by ancient Egyptian women to paint their eyelids black, hence the distinctive icon. And no, I don’t have any intention of making my app icons square with rounded corners, but providing us with distinctive forms, which have always helped distinguish apps in the Dock from one another.