Ruby Install Ruby on Apple Silicon

jasl · November 28, 2020 · Last by lidashuang replied at December 10, 2020 · 6564 hits
Topic has been selected as the excellent topic by the admin.

发布会当天就订了港版 M1 Mac Mini 16G,其实上周就送到手里了,不过因为这周二开了 WOW 9.0 所以赶工工作加肝游戏就一直没去玩他

很多人问我 M1 Mac Mini 上跑 Ruby 效果咋样,抽空试了一下,记录一个流水账

第一观感

  • 扩展性很差,eGPU 不支持,双显示器只有 Mac Mini 支持并且一定要一个接到 HDMI,另一个接 USBC
    • 亲测 HDMI 接口挑线,手头的飞利浦的 HDMI 线点不亮屏幕
  • 听到很多人反馈蓝牙有问题,频繁无故断开
  • 听到很多人反馈一周内有零星死机
  • Bug Sir 在 1080P 显示器上的视觉体验已经糟糕到不忍直视了
  • 折腾的时候 UI 的小毛病不少,在 x86 MBP 上完全没有遇到过
  • 网上各种评测讲的什么这么用再那么用用了好久好久一摸机器还是冷的,我不知道他们怎么搞的,我自己升级一下系统(预装 11.0,升级到 11.0.1),外壳就温热了,要知道 Mac Mini 的散热片和风扇比 MBP 不知道高到哪里去了
  • 程序员需要的各种作案工具基本上都还没有移植,虽然几乎所有的在 Rosetta 模式下都可以完美运行

M1 macOS 对于开发者的现状

  • 内置了 Ruby 2.6.3、Python 2.7、Python 3.8.2、PHP 7.3.22、Perl 5.18 5.28 5.30 (为啥要带这么多个版本?)
    • 当初说 macOS 11 要移除所有脚本语言解释器的,看样子还是怂了
    • Python 2.7 已经 EOL 了,苹果这次良心了一把,不知道拯救了多少老程序
    • PHP 和 Python 2.7 运行时会附带一行 WARNING: PHP is not recommended\nPHP is included in macOS for compatibility with legacy software.\nFuture versions of macOS will not include PHP. Ruby、Python 3 和 Perl 没有
  • OpenJDK 还没有移植完成,据说 JDK 16 会带 M1 的支持,目前 Java 相关的只能 Rosetta 了,据说运行完美
  • Go 还没有移植完成,1.16 会带 M1 支持,明年初的事情了,目前也是 Rosetta,据说也是运行完美
  • Python3 虽然自带且版本时髦,但 目前(发帖的时间) 还没法自行编译,numpy 也还跑不起来
  • NodeJS 15.3.0 已经支持 M1 了
  • Rust 目前对 M1 是 tier2 支持,是可以运行的,官方也还在跟踪 Apple Silicon 相关的问题,好消息是 rustup 刚宣布支持 M1 macOS 了
  • GCC 不支持 M1,而且一时半会出不来,最快要明年年中
  • OpenSSL 因为支持 iOS 所以其实也是支持 M1 的,但是缺少 M1 的 target(arm64-darwin20),所以编译不了,但有 patch 可用
  • Ruby(推测 Python 也会)很多(直接或者间接)依赖了外部 C 库(比如 sassc)不能用是因为 macOS 的 arm64 的 ffi 调用协定不同于 linux 的 aarch64,这个已经有补丁了,但是仍未合并,ffi gem 会做 workaround,但目前也没有合并
  • Homebrew 的安装脚本阻止原生 ARM 模式的安装,推荐在 Rosetta 下使用
    • 其实 Homebrew 用到的 gem 的 M1 兼容问题都已经解决了
    • 一个重要原因是 Homebrew 团队在犹豫是不是要修改默认的安装路径和其他的一些杂事(Rosetta 和 Native 共存需要谨慎处理,否则会产生冲突)
    • 目前还没有提供 M1 环境的 CI 服务,所以没有环境供自动化测试...
    • 最大的问题在于上述语言、编译器、关键依赖还没移植,导致无包可用
    • 详情可以关注 https://github.com/Homebrew/brew/issues/7857
  • Docker 目前不支持,长期来看也是最麻烦的
    • 参见 https://www.docker.com/blog/apple-silicon-m1-chips-and-docker/
    • Docker images 是有架构之分的,Doker 由于底层是虚拟机,所以 Rosetta 并不能对 Docker image 起作用,兼容后很可能只能使用 aarch64 的 image
    • 这对于在 mac 开发机上打包镜像给生产使用的人来说就是彻底灾难了
    • Parallels Desktop 明确提到在做能模拟运行 x86 的虚拟机(发布时间不明),那么或许可以切换 Docker 使用的虚拟机到 PD 来支持运行 x86 架构 image,花钱消灾也是好主意
  • 很多库其实可以编译,但是因为不能识别自己所处的环境而无法编译
    • 有意思的各家对于 ARM macOS 的 target 到底叫什么意见还不统一
    • llvm 的 target 叫 arm64-apple-darwin20.1.0
    • ruby 叫 arm64-darwin20
    • rust 叫 aarch64-apple-darwin
    • node 叫 darwin-arm64
    • 苹果自己的命名叫 arm64,M1/A14 是 ARMV8.4-A 的基础上增加了 8.5 和 8.6 部分指令的缝合怪
  • 根据 Homebrew 的报告,PostgreSQL 最新版完美适配 M1,MySQL 可以用但有小问题

安装 Ruby

安装 rbenv

我其实一直用 rvm 的,但是由于 rvm 在 macOS 上依赖 Hombrew,所以这里必须使用 rbenv 了。

需要使用安装脚本安装(而不是推荐的 Homebrew 安装)

curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash

然后添加环境变量到 ~/.zshrc

export PATH="$PATH:$HOME/.rbenv/bin:$HOME/.rbenv/shims"
eval "$(rbenv init -)"

最后可以跑一下

curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash

看看有没有问题,有的话根据提示修一下

重开 shell

Hack ruby-build

rbenv 实际是使用 ruby-build 这个 Ruby 的官方编译脚本来编译 Ruby 的, 我们之所以要 hack 是因为 Ruby 依赖 OpenSSL,需要在安装过程中编译 OpenSSL 之前把补丁打上去。

参考 https://github.com/rbenv/ruby-build/issues/1456#issuecomment-670051168 即可,FFI 的问题因为已经解决了,所以只需要这个评论的 OpenSSL 部分

ruby-build 的位置在 ~/.rbenv/plugins/ruby-build/bin/ruby-build

安装 autoconf

如果是安装 3.0.0-dev 版本的话,还需要 autoconf,由于 Homebrew 暂不可用的缘故,需要自己动手,丰衣足食了

  • curl http://mirror.team-cymru.com/gnu/autoconf/autoconf-latest.tar.gz --output autoconf-latest.tar.gz
  • tar zxvf autoconf-latest.tar.gz
  • cd autoconf-latest
  • ./configure --prefix=$HOME/opt
  • make
  • make install

我不喜欢让自己编译的程序污染系统目录如 /usr,所以我在自己的 Home 下创建了 opt 目录,存放自己编译的程序,这里还需要把 ~/opt/bin 这个 PATH 添加到 .zshrc 去,追加 export PATH="$PATH:$HOME/opt/bin" 即可

编译、安装 Ruby

万事俱备后 rbenv install 3.0.0-dev 即可,装好可以 rbenv global 3.0.0-dev 切换 ruby 相关命令到刚装好的版本去

arm64-darwin20 Ruby 的性能表现

注意,Apple M1 是 TDP 不超过 28w 的低功耗场景的 CPU

我们使用 Ruby 3x3 的测试项目 https://github.com/mame/optcarrot 来试试看 (该项目在 Ruby 2.0 时 FPS 为 20 左右,3x3 的目标即是做到 FPS 60)

不开 JIT 的情况

jasl@localhost:~/Workspaces/Ruby/optcarrot on master$ ruby -v -Ilib -r./tools/shim bin/optcarrot --benchmark examples/Lan_Master.nes
ruby 3.0.0dev (2020-12-02T18:47:10Z master 51268be7fe) [arm64-darwin20]
fps: 62.54343294150454
checksum: 59662

Ruby 3x3 超额完成任务!

开了 JIT

jasl@localhost:~/Workspaces/Ruby/optcarrot on master$ ruby -v -Ilib -r./tools/shim bin/optcarrot --benchmark examples/Lan_Master.nes --opt
ruby 3.0.0dev (2020-12-02T18:47:10Z master 51268be7fe) [arm64-darwin20]
fps: 131.9125859620421
checksum: 59662

对比我的 2019 MBP 16 寸顶配 2.3 GHz 8-Core Intel Core i9,这是一款 TDP 45w 的 CPU

不开 JIT 的情况

jasl@localhost:~/Workspaces/Ruby/optcarrot on master$ ruby -v
ruby 3.0.0dev (2020-12-02T18:47:10Z master 51268be7fe) [x86_64-darwin20]
jasl@localhost:~/Workspaces/Ruby/optcarrot on master$ ruby -v -Ilib -r./tools/shim bin/optcarrot --benchmark examples/Lan_Master.nes
ruby 3.0.0dev (2020-12-02T18:47:10Z master 51268be7fe) [x86_64-darwin20]
fps: 46.387448578077674
checksum: 59662

Ruby 3x3 挑战失败

开了 JIT

jasl@localhost:~/Workspaces/Ruby/optcarrot on master$ ruby -v -Ilib -r./tools/shim bin/optcarrot --benchmark examples/Lan_Master.nes --opt
ruby 3.0.0dev (2020-12-02T18:47:10Z master 51268be7fe) [x86_64-darwin20]
fps: 144.38348249123476
checksum: 59662

再对比 Dell Precision 7530 移动工作站,Xeon E-2186M 6 核至强、12M 高速缓存、2.90GHz 高达 4.60GHz Turbo、45 W、博锐,这款笔记本的特点就是有三倍 MBP 厚!散热和供电相比 MBP 更充分,根据评测 CPU 的 TDP 可以提升到 65W

不开 JIT 的情况

jasl@jasl-precision-7530:~/Workspaces/Ruby/optcarrot on master$ ruby -v -Ilib -r./tools/shim bin/optcarrot --benchmark examples/Lan_Master.nes
ruby 3.0.0dev (2020-12-02T17:42:02Z master 9e73177d53) [x86_64-linux]
fps: 47.55813269580448
checksum: 59662

开了 JIT

jasl@jasl-precision-7530:~/Workspaces/Ruby/optcarrot on master$ ruby -v -Ilib -r./tools/shim bin/optcarrot --benchmark examples/Lan_Master.nes --opt
ruby 3.0.0dev (2020-12-02T17:42:02Z master 9e73177d53) [x86_64-linux]
fps: 146.70990328870877
checksum: 59662

总结

由于 Apple M1 的资料太少,我只有一个浅显的结论,Apple M1 的设计对于解释型语言非常友好(但是是怎么做到的呢?)

个人感觉如果有 M1x,那么单核性能应该也就是这样差不多的水平了,首先 macOS 的 CPU 调度算法下能效核心和性能核心不能同时启用,所以理解成这是一个 4 核 CPU 似乎也没问题,这样下来核心数就跟 Intel、AMD 有差距了,此外外围太弱,PCIe 通道数量、MMIO bar 大小(树莓派和 M1 不支持 eGPU 的原因就是这个太小)、USB/雷电 接口数量、多显示器支持、内存大小等等...

不知道 Intel、AMD 和其他 ARM CPU 厂商会不会借鉴一些 M1 的设计理念,如果会的话,是不是解释型语言的性能表现普遍会有改善?

TODO:队长希望我测测 Sinatra 的表现,没送到嘴边的测试程序就懒得跑了。。。我要继续肝魔兽。。。

运行 Rails 的 tips

手头的应用没依赖什么特殊的 C 扩展 gem,有这么几点注意一下就可以完美运行起来了

  • nokogiri 可以加 --use-system-libraries 来安装
  • Gemfile 里加 gem "ffi", github: "felipecsl/ffi", submodules: true 官方发新版前,暂时用这个 fork
  • 使用 nodenv 编译 NodeJS 15.3.0
jasl in M1 芯片 Mac 可以开发 Rails 吗? mention this topic. 28 Nov 09:35

之前说 Ruby 3 JIT 性能不好的一个主要问题是 x64 上 L1i 命中很低。感觉上来说 M1 同时加大了 L1i 的大小和分页大小,可能 JIT 的提升会更大一点,但实际上好像带来的提升很小,甚至没有。一种可能是因为 RISC 生成的指令数量也比较多两者抵消了,还有一种可能就是这点大小增加效果不明显。

但反过来来看这个堆 ALU 单元,堆发射数量带来的单核 IPC 提升堆解释型语言的提升还是比较明显的。

但最好还是跑个 Sinatra 的测试,因为 Sinatra L1i 命中问题比 optcarrot JIT 严重很多,需要研究看看这个问题在 M1 上是表现得差不多还是变得更严重了。

huacnlee mark as excellent topic. 28 Nov 11:37

ruby 的对象模型怎么样,php 重组对象模型后提升很高,可以从这个角度优化吗?

Reply to pynix

回答不了,超肛了。。。

更新了一下,顺便测试了了跑 Rails,没遇到什么大问题,干活差不多够用了。

不考虑我比较穷这一点以外,感觉挺香的。

你好!我想请问一下我在 M1 上安装不上 pq (gem install pg -v '1.1.4' --source 'https://rubygems.org/') 一直报这些: Building native extensions. This could take a while... ERROR: Error installing pg: ERROR: Failed to build gem native extension.

current directory: /Library/Ruby/Gems/2.6.0/gems/pg-1.1.4/ext /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby -I /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0 -r ./siteconf20201203-96144-15ovz55.rb extconf.rb /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/universal-darwin20/rbconfig.rb:229: warning: Insecure world writable dir /usr/local/Cellar in PATH, mode 040777 checking for pg_config... no No pg_config... trying anyway. If building fails, please try again with --with-pg-config=/path/to/pg_config checking for libpq-fe.h... no Can't find the 'libpq-fe.h header *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options.

Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/$(RUBY_BASE_NAME) --with-pg --without-pg --enable-windows-cross --disable-windows-cross --with-pg-config --without-pg-config --with-pg_config --without-pg_config --with-pg-dir --without-pg-dir --with-pg-include --without-pg-include=${pg-dir}/include --with-pg-lib --without-pg-lib=${pg-dir}/lib

To see why this extension failed to compile, please check the mkmf.log which can be found here:

/Library/Ruby/Gems/2.6.0/extensions/universal-darwin-20/2.6.0/pg-1.1.4/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /Library/Ruby/Gems/2.6.0/gems/pg-1.1.4 for inspection. Results logged to /Library/Ruby/Gems/2.6.0/extensions/universal-darwin-20/2.6.0/pg-1.1.4/gem_make.out

周末我来试试安装 PG 好啦~

不过你得记得 pg gem 需要动态链接 postgresql 的 so 文件(没记错的话),所以你必须 arm pg 配 arm ruby

arm pg 是 work 的,我用 homebrew 安装的

Reply to lidashuang

这样??arch -x86_64 brew install pg???

Reply to jasl

我用的是 rbenv 版本管理工具安装的 ruby2.6.5,然后再命令前面添加 arch -x86_64 这种好像是属于通过 Rosetta 转编译的!

这样就是 Rosetta 转译了,涉及到动态链接的,x86 和 arm 不能混用

测试过了,可以安装,PG 编译需要的依赖太多, 我就用 Homebrew 来弄了,按官网教程手动安装后,再 brew install postgresql

Rails 这边就直接 bundle 就可以了

你可以这样试试

Reply to jasl

arch -x86_64 brew install postgresql 的时候会报这个错误: Warning: You are using macOS 11.0. We do not provide support for this released but not yet supported version. You will encounter build failures with some formulae. Please create pull requests instead of asking for help on Homebrew's GitHub, Twitter or any other official channels. You are responsible for resolving any issues you experience while you are running this released but not yet supported version.

Error: postgresql dependencies not built for the x86_64 CPU architecture: pkg-config was built for arm64 [email protected] was built for arm64 readline was built for arm64

Error: postgresql dependencies not built for the x86_64 CPU architecture: pkg-config was built for arm64 [email protected] was built for arm64 readline was built for arm64

这个错误已经说的很清楚了,你系统里的 pkg-configopenssl 都是 arm64 架构的,你用 arch -x86_64 brew install postgresql 指定装 x86 架构的,显然是不可能的,pg 支持 m1,所以你直接 brew install postgresql 就可以了

Reply to jasl

是我的问题,我安装 Homebrew 的时候没把目录放到 opt/Homebrew,导致他无论怎么跑都不是 arm

Reply to jasl

Homebrew12 月 1 更新了一个 2.6.0 好像专门针对 M1 的,

从你的错误提示看,只有 postgresql 你装的时候指定要 x86 的了,下边依赖都是 arm64 的,那直接去掉 arch -x86_64 就应该可以了,如果你之前装一些 brew 的软件包混杂了两种架构的,编译时遇到错误,就用正确架构重装即可

这个跟安装路径无关,会不会编译成 x86 只看你是不是带了 arch -x86_64 或者是给终端设置用 Rosetta 运行的属性(这个是很多网站介绍的技巧),如果都没有做的话,默认就会是 arm64

此外 2.6.0 也没有正式支持 M1(所以我才说要手动安装 Homebrew,因为你直接用官网的安装命令在 arm64 模式下会直接报错停止安装),之所以提议改到 opt/Homebrew 是因为过去 Homebrew 的默认路径是 /usr/local 考虑 Rosetta 会至少长期存在若干年,两种不同架构的 brew 并存是大概率的,于是就得给 ARM 版的 brew 找个新位置避免冲突,其实就是解决你现在遇到的问题,就是不同 arch 的 brew 软件包不能混用

更具体的 M1 的支持进展可以看我帖子里引用的 https://github.com/Homebrew/brew/issues/7857 ,虽然 Homebrew 在 M1 Mac 上完全可以正常使用,但是官方故意宣称不支持的原因在里面有讲,关键原因还是官方不能保证有足够多的软件包在 M1 macOS 上正常编译和使用顺利,他们才刚刚配置起 M1 的 CI 环境来逐步验证所谓的核心软件包

能不能做个 rspec 性能比较,m1 芯片的单核这么厉害,运行 rspec 能比以前的 macbook pro 快多少?

Reply to leijun

给我一个样本?我来帮你跑跑看

理论上 rails 的 rspec 测试,瓶颈在 IO 更多一些

23 Floor has deleted
lanzhiheng in 生活中的苹果 mention this topic. 24 Dec 21:30
25 Floor has deleted
You need to Sign in before reply, if you don't have an account, please Sign up first.