M2 MacBook のローカルとコンテナ実行を比較する

## はじめに

M2 Mac ではローカルとコンテナでどれだけパフォーマンスに差が出るか Livebook で確認してみました

Intel Mac の場合はこちら

https://qiita.com/RyoWakabayashi/private/32850e088f69de74291e

Intel Mac と M2 Mac の比較はこちら

https://qiita.com/RyoWakabayashi/private/ce6ac9b9245f1fb7a296

## 実行する処理

Nx の様々なバックエンドによる行列の加算処理を計測の対象とします

`Benchee.run` によって、IPS（Instructions Per Second 1秒間に何回処理を実行できたか）を計測します

```elixir
bench = fn backend ->
  tensor =
    {200, 200}
    |> Nx.iota(type: :f64, backend: backend)

  Nx.add(tensor, tensor)
end
```

```elixir
Benchee.run(%{
  "binary" => fn -> bench.(Nx.BinaryBackend) end,
  "exla" => fn -> bench.(EXLA.Backend) end,
  "torchx" => fn -> bench.(Torchx.Backend) end,
  "evision" => fn -> bench.(Evision.Backend) end
})
```

詳細な内容は以下の記事を参照してください

https://qiita.com/RyoWakabayashi/items/45edc8ddbccba139a5ba

`Nx.BinaryBackend` を使っている場合は単純に Elixir で 40,000 回足し算を行っています

`Evision.Backend` なら OpenCV 、 `EXLA.Backend` なら XLA を使った行列演算を実行しています

## TorchX が arm64 の Linux にインストールできない

TorchX は Mac の場合にしか arm64 アーキテクチャに対応していません

https://github.com/elixir-nx/nx/blob/main/torchx/CMakeLists.txt#L38-L51

> ```make
> if(NOT APPLE)
>     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -shared")
>     set_target_properties(torchx PROPERTIES INSTALL_RPATH "\$ORIGIN/${LIBTORCH_BASE}")
> else()
>     # Although the compiler complains about not using these,
>     # things only work with them set
>     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -undefined dynamic_lookup")
>     check_c_compiler_flag("-arch arm64" ARM64_SUPPORTED)
>     if(ARM64_SUPPORTED)
>         set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMAC_ARM64")
>     endif()
>     # set(CMAKE_SHARED_LINKER_FLAGS "-bundle -flat_namespace -undefined suppress")
>     set_target_properties(torchx PROPERTIES INSTALL_RPATH "@loader_path/${LIBTORCH_BASE}")
> endif()
> ```

これにより、 Livebook のコンテナ上で TorchX をインストールしようとすると、以下のようなエラーが発生します

```
/usr/bin/ld: /home/livebook/.cache/mix/installs/elixir-1.15.2-erts-14.0.2/a3046f2697bbfc375e1ce3e0a9da02d7/deps/torchx/cache/libtorch-1.12.1-cpu/lib/libtorch.so: error adding symbols: file in wrong format
collect2: error: ld returned 1 exit status
gmake[3]: *** [CMakeFiles/torchx.dir/build.make:107: torchx.so] Error 1
gmake[3]: Leaving directory '/home/livebook/.cache/mix/installs/elixir-1.15.2-erts-14.0.2/a3046f2697bbfc375e1ce3e0a9da02d7/_build/dev/lib/torchx/cmake'
gmake[2]: *** [CMakeFiles/Makefile2:95: CMakeFiles/torchx.dir/all] Error 2
gmake[2]: Leaving directory '/home/livebook/.cache/mix/installs/elixir-1.15.2-erts-14.0.2/a3046f2697bbfc375e1ce3e0a9da02d7/_build/dev/lib/torchx/cmake'
gmake[1]: *** [Makefile:103: all] Error 2
gmake[1]: Leaving directory '/home/livebook/.cache/mix/installs/elixir-1.15.2-erts-14.0.2/a3046f2697bbfc375e1ce3e0a9da02d7/_build/dev/lib/torchx/cmake'
make: *** [Makefile:29: /home/livebook/.cache/mix/installs/elixir-1.15.2-erts-14.0.2/a3046f2697bbfc375e1ce3e0a9da02d7/_build/dev/lib/torchx/priv/torchx.so] Error 2
could not compile dependency :torchx, "mix compile" failed. Errors may have been logged above. You can recompile this dependency with "mix deps.compile torchx --force", update it with "mix deps.update torchx" or clean it with "mix deps.clean torchx"
```

`TorchX.Backend` はコンテナ上では使用しないものとします

## ローカル

実行環境は以下の通りです

- MacBook Pro 13 inch, 2022
  - macOS Ventura 13.5
  - CPU Apple M2
    8 コア（パフォーマンス: 4、効率性: 4）
  - メモリ 24 GB
- Elixir 1.15.2
- Erlang 26.0.2
- Livebook 0.10.0

Elixir と Erlang は asdf でインストールし、 Livebook は GitHub からタグ指定でクローンしてきたコードをローカルビルドしています

実行結果は以下のようになりました

| バックエンド |  IPS    |
|:-----------|--------:|
| binary     |     154 |
| evision    |   5,800 |
| exla       |  11,870 |
| torchx     |   8,600 |

## コンテナ

コンテナには Rancher Desktop を使います

また、イメージは以下のリポジトリーのものを使いました

https://github.com/RyoWakabayashi/elixir-learning

Livebook のコンテナイメージはマルチプラットフォームイメージなので、自動的に arm64 のアーキテクチャでコンテナが起動します

https://docs.docker.com/build/building/multi-platform/

アーキテクチャは起動したコンテナ内で確認できます

```bash
$ docker exec -it livebook /bin/bash
root@179553aa7b45:/data# uname -m
aarch64
```

- Rancher Desktop 1.9.1
  - CPU割当て 6
  - メモリ割当て 10 GB
- Debian 11
- Elixir 1.15.4
- Erlang 26.0.2
- Livebook 0.10.0

実行結果は以下の通りです

| バックエンド |  IPS   |
|:-----------|-------:|
| binary     |    131 |
| evision    |  1,360 |
| exla       |  3,320 |

ローカルと比べて明らかに遅くなりましたね

## 比較

M2 Mac のローカルとコンテナの比較表は以下のようになります

| バックエンド | ローカル　IPS | コンテナ IPS | ローカル / コンテナ |
|:-----------|------------:|------------:|-----------------:|
| binary 　  |         154 |         131 |             1.18 |
| evision 　 |       5,800 |       1,360 |             4.26 |
| exla     　|      11,870 |       3,320 |             3.58 |
| torchx  　 |       8,600 |           - |                - |

ちなみに、 Intel Mac の場合は以下のようになっていました

| バックエンド | ローカル　IPS | コンテナ IPS | ローカル / コンテナ |
|:-----------|------------:|------------:|-----------------:|
| binary  　 |          79 |          41 |             1.93 |
| evision  　|       2,580 |         392 |             6.58 |
| exla     　|       8,260 |         771 |            10.71 |
| torchx   　|       5,810 |         862 |             6.74 |

比較すると、 M2 Mac の方がコンテナでもあまり性能が落ちていません

## まとめ

Livebook はマルチプラットフォームイメージなので、特に何もしなくても arm64 アーキテクチャでコンテナを起動することができました

また、 Intel Mac と比べてコンテナ上での性能の下げ幅が小さくなっていました

それでも 4 倍程度差が出るので、やはり重い処理はローカルで実行した方が良いでしょう

ただし、 TorchX がコンテナでインストールできないという問題があります