以前投稿したブログにてApple謹製のアーカイブ機能フレームワークAppleArchiveの性能について比較する旨の内容を記述していた。本ブログはアーカイブ処理を介してApple M1チップとIntel チップのCPU性能を比較する。
Apple Archive - Apple 謹製のアーカイブフレームワーク
アーカイブ処理はCPU性能が反映されやすい。Apple謹製フレームワークを利用しているのでそれぞれのOSに対するCPU性能は引き出されている。
文末にて性能差が出る理由について記述する。
アーカイブ処理とは
macOSで言うと圧縮に相当する。元のデータよりもサイズを減らす。複数だったり階層化されたデータを1つのファイル(圧縮ファイルを)にすることで持ち運びしやすくするために使用される。CPU性能が大きく反映される処理の1つとなっている。
1) 前提条件
2台の2020年製MacBookPro 13inchを使用してCPUの性能比較を実施する。一台はApple M1チップ、一方はIntel Core i7である。以後それぞれ、Apple M1、Intel Core i7の名称を使用する。
CPU名称 | 周波数 | 価格 |
---|---|---|
Apple M1 | 3.2GHz(非公開) | 約19万円 |
Intel Core i7 | 4.1GHz | 約29万円 |
Intel Core i7は13inchのサイズで選べる最上位CPUとなっている。
もともとはA12Zチップ(iPad Pro)と、Intelチップとの比較だったが、手元にIntelチップとApple M1チップそれぞれを搭載した2020発売のMacBookProが手元にあるのでより公平な比較といえる。
1-1) 搭載メモリ
搭載メモリはApple M1は16GB、Intel Core i7は32GBだがベンチマークとなるアーカイブ処理は、大きなファイルを圧縮してコンパクトな形にするため一定サイズのメモリが確保できればメモリ容量に関わる影響は少ないはずである。
1-2) ストレージ(SSD)
SSD容量は共に1TBで公開仕様上は同じらしい(Apple M1、Intel Core i7で同性能)。
1-3) 転送速度
ストレージやメモリ容量よりもCPUよりもメモリCPU間の転送速度、SSDの読み込み書き込み性能が比較に影響する可能性は高いがこちらはCPU特性の一部として扱う。
2) 検証方法
AppleArchiveを使用するため検証用アプリを用意する。
Apple Archive はmacOS11 から利用できるApple謹製のフレームワークの1つでアーカイブ機能のためのフレームワークとなっている。
検証アプリは圧縮対象のファイルをドラッグするとアーカイブを実行し、完了までの時間を計測する。
計測するのは約700MBの音声ファイル(aiff-c)を使用。圧縮形式はAppleがオープンソースとして公開したlzfseを使用する。圧縮率よりも速度を重視した圧縮形式となっている。
lzfse/lzfse: LZFSE compression library and command line tool
3) 検証用アプリについて
検証用アプリのコードを示す。ドラッグ&ドロップできる環境前提のコードとなっている。制約は 2021年1月現在Apple Archiveは実機しか動作しないこともあって動作はmacOS11 以降なのは注意して欲しい。
import SwiftUI | |
import Combine | |
import AppleArchive | |
import System | |
enum ArchiveBenchResult { | |
case failureError(error: Error) | |
case notExistsSourceFile | |
case notOpenReadFileStream | |
case notOpenWriteFileStream | |
case notOpenCompressionStream | |
case success(timeinterval: TimeInterval) | |
func description() -> String { | |
switch self { | |
case .failureError(let error): return "エラー: " + error.localizedDescription | |
case .notExistsSourceFile: return "アーカイブ元ファイルが見つかりません" | |
case .notOpenReadFileStream: return "ReadFileStreamの作成に失敗しました" | |
case .notOpenWriteFileStream: return "WriteFileStreamの作成に失敗しました" | |
case .notOpenCompressionStream: return "CompressionStreamの作成に失敗しました" | |
case .success(let timeinterval): return "\(timeinterval)" | |
} | |
} | |
} | |
// for macOS app project, not working iPhone simulator | |
struct ContentView: View { | |
static let archivedFileURL = FileManager.default.temporaryDirectory.appendingPathComponent("archiveBenchmark.lzfse") | |
@State var informationString = "下部の矩形にファイルをドロップしてください。" | |
@State var resultString = "" | |
@State private var dragOver = false | |
func postResult(_ result: ArchiveBenchResult) -> Void { DispatchQueue.main.async { self.resultString = result.description() } } | |
var body: some View { | |
HStack { | |
Spacer() | |
VStack { | |
Spacer() | |
Text(self.informationString) | |
Rectangle() | |
.frame(width: 200, height: 150) | |
.foregroundColor(.gray) | |
.onDrop(of: ["public.file-url"], isTargeted: $dragOver) { providers -> Bool in | |
providers.first?.loadDataRepresentation(forTypeIdentifier: "public.file-url", completionHandler: { (data, error) in | |
if let data = data, let path = NSString(data: data, encoding: 4), let sourceFileURL = URL(string: path as String) { | |
DispatchQueue.main.async { | |
self.informationString = sourceFileURL.path | |
} | |
guard FileManager.default.fileExists(atPath: sourceFileURL.path) else { | |
self.postResult(.notExistsSourceFile) | |
return | |
} | |
if FileManager.default.fileExists(atPath: Self.archivedFileURL.path) { | |
do { | |
try FileManager.default.removeItem(atPath: Self.archivedFileURL.path) | |
} catch (let error) { | |
self.postResult(.failureError(error: error)) | |
return | |
} | |
} | |
let sourceFilePath = FilePath(sourceFileURL.path) | |
guard let readFileStream = ArchiveByteStream.fileStream(path: sourceFilePath, mode: .readOnly, options: [ ], permissions: FilePermissions(rawValue: 0o644)) else { | |
self.postResult(.notOpenReadFileStream) | |
return | |
} | |
defer { try? readFileStream.close() } | |
let archiveFilePath = FilePath(Self.archivedFileURL.path) | |
guard let writeFileStream = ArchiveByteStream.fileStream(path: archiveFilePath, mode: .writeOnly, options: [ .create ], permissions: FilePermissions(rawValue: 0o644)) else { | |
self.postResult(.notOpenWriteFileStream) | |
return | |
} | |
defer { try? writeFileStream.close() } | |
guard let compressStream = ArchiveByteStream.compressionStream( using: .lzfse, writingTo: writeFileStream) else { | |
self.postResult(.notOpenCompressionStream) | |
return | |
} | |
defer { try? compressStream.close() } | |
do { | |
let now = NSDate() | |
_ = try ArchiveByteStream.process(readingFrom: readFileStream, writingTo: compressStream) | |
_ = try? FileManager.default.removeItem(atPath: Self.archivedFileURL.path) | |
self.postResult(.success(timeinterval: abs(now.timeIntervalSinceNow))) | |
} catch (let error) { | |
self.postResult(.failureError(error: error)) | |
} | |
} | |
}) | |
return true | |
} | |
HStack { | |
Text("計測結果(秒):") | |
TextField("計測結果が反映されます", text: self.$resultString) | |
Spacer() | |
} | |
Spacer() | |
} | |
Spacer() | |
} | |
} | |
} |
3-1) コードの使用方法
macOS11 以降でXcode(開発ツール)で、
新規プロジェクト - Multiplatformを選択 - ContentView.swift を置き換え - macOSを指定して実行
以上で試すことができる。
コンパクトにまとめるため(100行未満)いくつか処理を省いている。具体的にはAppleArchiveの処理はmainthread以外から呼ばれることを前提としており、SwiftUIのドラッグ処理がmainthread以外で呼び出される仕様に基づいてコード量を節約しているのでコードの移植の際は注意してほしい。
4) 検証結果
3で紹介したコードをApple M1、Intel Core i7それぞれ開発ツール(Xcode)でビルド、macOS appとして起動し検証用音声ファイルを指定して完了時間を検測した。
以下に動作結果を示す。アーカイブ処理の完了時間を示しているのでグラフが短い方が処理速度が早い。
Apple M1がIntel Core i7に比べて約2.19倍早く処理を完了している。2.19倍の結果は他ベンチマークアプリでのCPU比較と差がないものとなっている。
シングルスレッドでの性能差でも1.6倍の差が出ている上にマルチスレッドの場合はさらに性能差が開いている。
CPU | Apple M1 | Intel Core i7 | 性能差 |
---|---|---|---|
マルチスレッド性能 | 1.48秒 | 3.24秒 | 2.19版 |
シングルスレッド性能 | 7.16秒 | 11.54秒 | 1.6倍 |
5) 性能差が出る理由
単体の性能でも上なのにマルチスレッドでさららに性能が引き離されてしまう理由は何故なのか?
検証用ベンチマークには特徴があって数秒でアーカイブ処理が終わってしまう。
そのため短時間でも性能が発揮されるCPU割り当てができるCPUがより有利となる。
Apple M1を保持するAppleは保持しているOS(macOS)を介して適切なチューニング(CPU割り当て)が実施されているため(Apple M1は単体性能も高く)マルチスレッド性能も高くできているものと推測できる。
検証アプリで利用したApple謹製のフレームワークであるApple ArchiveはよりOSによる適切なチューニングが施されており結果が顕著となったものと思われる。
6) まとめ
使い始めて一ヶ月程度になるが、Apple M1自体の性能はIntelチップの同構成に比べて久しく高い。アプリ開発者などにとっては十分な長所のため細かい短所が許されてしまっているところがある。
6-1) 長所
画面サイズが13inchのMacに限って言えば、CPUだけでなくGPU性能も上回っておりMacBookPro 16inchやiMacのようなOSの機敏さを得られるのでIntel版MacBook Air /MacBook Pro 13inchの買い替えであれば高性能と静音性の恩恵を十分に得られる。
6-2) 短所
一方でディスプレイ周りのトラブル(接続ディスプレイ数が限定など)、Thunderbold3(USB-C)ポートが2ポートなど、外部デバイスとの連携に不安が残っている。
画面サイズが13inchのMacはiPad Proとも競合している。タッチ操作やPencil が主体のアプリを使うのであればいまさらタッチパッド主体の操作に戻ることもないし、iPadの性能が不満という話も周りでは聞かない。
2021年1月においては、Apple M1チップを喜ぶユーザーは4K映像制作製作者や、開発ツールが対応しているiPhoneアプリ開発者ぐらいしか恩恵はない。
6-3) 体験してみたい"少し未来"の性能
それでもノートPCはおろか今後のパーソナルコンピューターの指標となるApple M1に触ってみることは少し未来を覗くことができるだろう。20世紀末にパーソナルなコンピューターを示したAppleが21世紀初頭にパーソナルコンピューターの方向を示し直すタイミングを共に体験したい方にはお勧めしたい。