SwiftでAppleのデバイス情報を取得する方法

# Getting Apple Device Information on Swift
SwiftのコードでApple製品のデバイスの情報を取得する方法をメモしておく。

下記の内容は以下のSwift Packageを実装する際に使用している:

- [DeviceHardware](https://github.com/Shakshi3104/DeviceHardware)
- [CoreWafer](https://github.com/Shakshi3104/CoreWafer/tree/main)


## 機種ID (Model Identifier)を取得する [iOS, macOS]
iOS

```swift
var size: Int = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: Int(size))
sysctlbyname("hw.machine", &machine, &size, nil, 0)
let code: String = String(cString:machine)
print(code) // -> iPhone13,2
```

Mac

```swift
var size: Int = 0
sysctlbyname("hw.model", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: Int(size))
sysctlbyname("hw.model", &machine, &size, nil, 0)
let code: String = String(cString:machine)
print(code) // -> MacBookAir10,1
```

## CPUの型番を取得する [macOS]

```swift
var size: Int = 0
sysctlbyname("machdep.cpu.brand_string", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: Int(size))
sysctlbyname("machdep.cpu.brand_string", &machine, &size, nil, 0)
let cpuInfo: String = String(cString:machine)
print(cpuInfo) // -> Intel(R) Core(TM) i5-5250 CPU @ 1.60GHz
```

## CPUの物理コア数を取得する [iOS, macOS]

```swift
var core: Int32 = 0
var size = MemoryLayout<Int32>.size
sysctlbyname("hw.physicalcpu", &core, &size, nil, 0)
print(core) // -> 2
```

## CPUのコア数を取得する [iOS, macOS]
Macの場合は論理コア数が返ってくる(`"hw.ncpu"`と同じ値)。iOSの場合は上記と同じ数字が返ってくる。

```swift
let core = ProcessInfo.processInfo.processorCount
print(core) // -> 4
```

## CPUのクロック周波数を取得する [macOS (Intel)]
単位はHzで返ってくる。

Apple Silicon Macの場合、`sysctlbyname`でクロック周波数を取得できない。

```swift
var freq: Int64 = 0
var size = MemoryLayout<Int64>.size
    
sysctlbyname("hw.cpufrequency", &freq, &size, nil, 0)
print(freq) // -> 1600000000
```

## 高性能コアと高効率コアのコア数を取得する [iOS, macOS (Apple Silicon)]

A10以降のiOSデバイスやApple Silicon Macは、big.LITTLEのSoCであるため、高性能コアと高効率コアが存在する。

### 高性能コア
```swift
var cores: Int64 = 0
var size = MemoryLayout<Int64>.size

if sysctlbyname("hw.perflevel0.physicalcpu", &cores, &size, nil, 0) != 0 {
    return nil
}
print(cores) // -> 8
```

### 高効率コア
```swift
var cores: Int64 = 0
var size = MemoryLayout<Int64>.size

if sysctlbyname("hw.perflevel1.physicalcpu", &cores, &size, nil, 0) != 0 {
    return nil
}
print(cores) // -> 4 
```

## GPUの型番を取得する [iOS, macOS]
Metalが使用するデフォルトのGPUを取得する。iGPUとdGPUが搭載されているMacBookなどの場合は、dGPUがデフォルトである。

```swift
import Metal

guard let device = MTLCreateSystemDefaultDevice() else {
    fatalError( "Failed to get the system's default Metal device." )
}
    
print(device.name) // -> Intel(R) Iris Plus Graphics 655
```

## RAMの容量を取得する [iOS, macOS]
単位はB (バイト)で返ってくる。また、UInt64で返ってくるのでIntとして使う場合はキャストする。

```swift
let ram = ProcessInfo.processInfo.physicalMemory
print(ram) // -> 2071019520
```


## 参考
- [【Swift】iOSデバイスのモデル名を取得するだけのFrameworkを作った](https://qiita.com/MYamate_jp/items/9f26ad6f78f347ebd629)
- [Gathering system information in swift with sysctl](https://www.cocoawithlove.com/blog/2016/03/08/swift-wrapper-for-sysctl.html)
- [Accessing macOS System Information](https://wiki.freepascal.org/Accessing_macOS_System_Information)
- [Getting the Default GPU - Apple Developer Documentation](https://developer.apple.com/documentation/metal/getting_the_default_gpu)

## sysctl
`sysctlbyname`はC言語の関数で、システムの情報を取得できるものである。

```c
int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
```

戻り値は、成功したときに`0`、そうでないときは`-1`である。

ターミナル上で`sysctl -A`を実行すると(おそらく)取得できる値の一覧を見ることができる。また、`man 3 sysctl`でマニュアルを見ることもできる。

[sysctlbyname (3) manページ](https://nxmnpg.lemoda.net/ja/3/sysctlbyname#7)