IRBとRelineのHEADを使いつつ現在のブランチ名とcommit hashを表示する

IRBとRelineはHEADで使いたいので、特定ディレクトリのものを使用して実行している。

ASDF_RUBY_VERSION=3.3.0-dev ruby -I /Users/mi/ghq/github.com/ruby/reline/lib -I /Users/mi/ghq/github.com/ruby/irb/lib /Users/mi/ghq/github.com/ruby/irb/exe/irb`

これだけだとレビューするときに「今どのブランチで実行してるんだっけ?」と思うことがあるので、ブランチ名とcommit hashも表示するようにした。

ブランチ名は git rev-parse --abbrev-ref HEAD で、commit hashは git show --format='%h' --no-patch で表示できる。

function irbm() {
  echo "IRB    branch: $(cd /Users/mi/ghq/github.com/ruby/irb && git rev-parse --abbrev-ref HEAD), HEAD: $(cd /Users/mi/ghq/github.com/ruby/irb && git show --format='%h' --no-patch)"
  echo Reline branch: $(cd /Users/mi/ghq/github.com/ruby/reline && git rev-parse --abbrev-ref HEAD), HEAD: $(cd /Users/mi/ghq/github.com/ruby/reline && git show --format='%h' --no-patch)
  ASDF_RUBY_VERSION=3.3.0-dev ruby -I /Users/mi/ghq/github.com/ruby/reline/lib -I /Users/mi/ghq/github.com/ruby/irb/lib /Users/mi/ghq/github.com/ruby/irb/exe/irb
}

alias irbm='irbm'

実行するとこのように表示される。

❯ \irbm
IRB    branch: master, HEAD: c2e7002
Reline branch: master, HEAD: ffe81c8
irb(main):001:0>

RubyKaigi 2023で "UTF-8 is coming to mruby/c" というタイトルで話しました

スライドタイトルは「サンタが街にやってくる」つまり「Santa Claus Is Coming to Town」のもじりでした。

UTF-8がルンルンでmruby/cにやってくる様子を思い浮かべながら決めました。

スライド

きっかけ

発表内でも触れましたが、はすみさんにRubyWorldConference2022でmruby/cのUTF-8対応をしませんかと誘われたのがきっかけです。

文字コード好きなひとが来場する情報を事前にTwitterでキャッチしていたので、PicoRubyのUTF-8対応という釣り糸を垂らしたら、うまいこと引っかかりました。 質問タイムのときにちょうどその人が質問してくれて、「ちなみにUTF-8に興味ありません?」と聞いたら「めっちゃあります」とのことで、「じゃあ後ほど打ち合わせしましょう」と公衆の面前で言質をとった次第です。   mruby/cのUTF-8対応は進めてよい、とすでに開発者会議で決まっています(PicoRubyコンパイラ側は私の一存でなんでもできる)から、あとはやるだけです。

shimane.monstar-lab.com

言質をとられるシーンがYouTubeに残っています。

youtu.be

2022年にUTF-8を0から実装できる、しかも人々に使われる言語で…というのはとても魅力的で、ワクワクしました。

この時点ではmrubyとmruby/cの違いもわかっていませんでしたが、はすみさんに質問できるなら実装できないことはないだろうと思っていました。

プロポーザル

2022年末ごろに私はIRBとRelineのメンテナになりました。そうすると不思議なことにRubyKaigiへの焦がれるような執着がスッと消えました。RubyKaigiへのモチベーションがなくなったわけではないけれど、絶対にプロポーザルを出さなければ…という自分の中のプレッシャーからは解放されました。

また、前回のRubyKaigiからあまり日がなかったこともありプロポーザルを出すかどうかは直前まで悩んでいました。メンテナ活動も始めていて、プロポーザルとして出せるような大玉を持っていなかったというのもあります。mruby/cのUTF-8対応も未着手でした。今年は出さなくてもいいかな、と思っていました。Asakusa.rbの新年会までは。

1月24日にAsakusa.rbの新年会があり、そこでIRBの話をたくさんしておいしい羊をたくさん食べてとても楽しい時間を過ごせました。翌日、RubyKaigiのプロポーザルを出そうというやる気が湧いてきました。IRB, Relineで話せるようなネタはないのでmruby/cのUTF-8対応ができそうか下調べを開始していけそうだったのでプロポーザルにまとめてSubmitしました。その時点での実装は0で去年に引き続きまた見切り発車ですが、UTF-8のことは調べれば分かるのとmrubyが参考になりそうなことは知っていたのでまあ形にはなるだろうとの見込みで行きました。

その後しばらく実装を進めておらず、3月にプロポーザル通過の連絡が来て実装をはじめました。今思えば2月にもう少し作業しておけばよかったです。

実装

ただしく実装できた部分は発表の中で話したので、ここでは発表で話さなかった部分を書きます。

Stringの各メソッドでUTF-8に対応させるという方針は決めていたので粛々と実装とテストを書いていました。C言語とmruby/cについては素人なので、ChatGPTにいろいろ質問しながら進めました。ポインタ演算やポインタをprintfする方法など基本的なことを質問したり、関数をまるごと渡して要約してもらったりしました。ChatGPTにはとても助けられました。ChatGPT 4のサポートをしてくれた所属先の永和システムマネジメントに感謝しています。

ほかにはmemcpy, memmoveをすることでどうバイト列を操作するか分からなくて手書きで方眼紙にバイト列とアドレスを書いてどうやってバイト列が移動するのか理解したりしていました。ビット演算も不慣れで、16進数と2進数の変換を脳内で行う練習をしたりしました。こういうのは実際に手を動かすことで理解が深まると思います。

いろいろ困ったこともおきました。\0 を文字列終端の判定にしていたら、Ruby側から途中で \0 を含む文字列が渡されたときに途中までしか見なくなってしまうとか。こう書くと当たり前ですが、Cに不慣れでよくわかっていませんでした。

        s1 = "ABC\x00\x0d\x0e\x0f"
        assert_equal 7, s1.size # => 3

String#inspectの修正には少し悩まされました。mruby/cのテスティングフレームワーク自身がmruby/cのinspectを使っているため、expectedとactualで全く同じ結果が出力されていますがこれはテストに失敗しています。コード読んで直しました。

    1) StringTest#string_inspect_case (:assert_equal)
      description : String#inspect
      expected    : ""\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"" [String]
      actual      : ""\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"" [String]
      # /work/mrubyc/test/string_test.rb:951

あとはmruby/cのStringのテストがいろいろ不足していたため、テストを追加するPRをいくつか出しました。mrubyc contoributors 4位になりました (12 commits) https://github.com/mrubyc/mrubyc/graphs/contributors

実装過程は気づいたことや思ったことのメモを取っていました。中途半端なところで中断しても「次はここからやるんだな」ということがひと目で分かって便利でした。また、たまに見返すことで自分がやってきたことを振り返ることができました。この記事を書くのにもかなり役立っています。

RubyKaigiの準備が前日になっても全然終わっていない悪夢を3回くらい見ました。LTとKeebKaigiにはプロポーザルを出さないことを決めました。

発表

人がたくさんいてかなり緊張しました。OpenStudioはお立ち台と1列目が近く、1列目に見知った顔を何人か見かけました。同僚のふーがさんと目があって、声をかけてもらえて少し緊張がほぐれました。

発表は28分で時間的にはちょうど良かったと思います。話し終わった後に「楽しそうに話していてよかった」とフィードバックをもらえてよかったです。文字コードの面白さ、結局すべてはバイト列であるということが少しでも伝わったら幸いです。

ふりかえり

しかしスライド作成がギリギリになったこと、実装が完了できなかったことは残念でした。みなさんにお届けできる状態で発表したいです。また練習不足も感じました。去年よりは早めに手を付けられたものの、やはり実装完了している状態でプロポーザル出すのがスケジュール的にはよいなと感じました。またスライドの英語の説明、図表の少なさ、情報密度などに課題を感じています。特にRubyKaigiは「わからないことによるワクワク感」があっていいカンファレンスだと感じます。もっと情報密度を高めて、わからなくても楽しいと感じるような発表をしたいと感じました。

今後やりたいこと

  • UTF-8対応の残りの実装
  • Unicode Standardを読む
  • mruby/cを実機にデプロイ
  • mruby/cのテスティングフレームワークでassertionが落ちた行が分からないのを修正

IRBとRelineのバージョンを変更してIRBを起動するスクリプトを書いた

IRBのバージョンは簡単に変更できるけど、Relineのバージョン変えてIRB起動するのが面倒だったのでスクリプトを書いてみた。 手元でしか使わないのでARGVで文字列渡すだけの簡素な作り。

bundler/inline は便利だなぁ。

コードにもコメントしてあるけど、ARGV.clear しないとIRBの lib/irb/magic-file.rb で ARGV[0]File.open しようとして落ちるので ARGV.clear している。

使用例

ruby irb_reline_versions_changer.rb 1.4.1 0.3.0
#!/usr/bin/env ruby

require 'bundler/inline'

IRB_VERSION = ARGV[0]
RELINE_VERSION = ARGV[1]

# NOTE: IRBのMagicFileでARGVをファイルとしてOpenしようとして落ちるためARGVを削除する
ARGV.clear

gemfile do
  source 'https://rubygems.org'
  gem 'irb', IRB_VERSION
  gem 'reline', RELINE_VERSION
end

require 'irb'
require 'reline'

puts "irb: #{IRB::VERSION}"
puts "reline: #{Reline::VERSION}"

IRB.start(__FILE__)

福岡Rubyist会議03に参加した

福岡Rubyist会議03

regional.rubykaigi.org

キーノートスピーカーの2名が公開されたときに、これは絶対に行きたい!!と思って参加を決めた。参加してとても良かった。

sorahさんの発表はRubyKaigiがどんなものを使って、どんなスケジュール感で作られているのかが分かり面白かった。自宅ISPとは…? コンパネがRails consoleだったとか生々しい裏話が聞けて面白かった。あと話の節々からsorahさんのカバー範囲の広さが伺えて刺激を受けた。

YouTube眺めてるときにRubyistの話がもっと聞ければいいのにな〜と以前から思っておりこれを機に配信するRubyistが増えてくれないだろうかと思った。ピンマイク欲しくなった。普段の打ち合わせとか、オンラインの登壇で音質よくしたい気持ちが高まった。

iPadのカメラを使って配信できるとは思ってもいなかったので新しい視点だった。iPadだと気軽だし対応アプリも多そうだし良さそう。

Rubyのリリース大変そうというのが分かって良かった。デプロイボタンを押せばポンとリリースされるものではなく、何人かが数時間かけて対応していく大変な作業だった...いつもありがとうございます。

私がESP32にmruby/cを入れようとしてハマったところがなぜハマったのか分かって勉強になった。project.mkがないと言われていたがESP32側がmake非対応になっていたらしい。

発表後にyuuuさんに「私はマイコンに興味があるが、何から勉強したらいいか分からない。どんなレイヤに何があるのかがちんぷんかんぷんで、基礎知識を知りたい。組み込みの基礎知識を得るにはどうすればいいと思うか?」と聞いたところ「エンベデッドシステムスペシャリスト試験の教科書がよくまとまってる」と教えてもらい、とても参考になった。ネットで検索しても電子工作の基礎情報は出てくるもののマイコンの世界についてはなかなか見つけられなかったので聞けて良かった。

るびまはznzさんの発表をきっかけに本当にみんなが動き出している。すごいことだと思う。みんな実は内なる思いがあって、それがznzさんの話が起爆剤になって動き出したように見える。動き出したものはじゃんじゃん前に進んでいて、みんなすごいなーと思う。

るびまに必要だったのは「るびまがまた発行されてほしい」という気持ちを持っている人がたくさんいることをお互いが気づくことだったのかもしれない

Ruby M17N の設計と実装」はRubyの多言語対応がどのようになされたか、概念からAPIまで一気通貫できる最高のドキュメントなのでおすすめです。

tompngさんの発表はとにかく楽しいし理解が及ばないしで、とても楽しかった。トークの構成でも技術的な内容でも素晴らしいキーノートだったと思う。これを現地で聞けて良かった。

話の内容は高度で角谷さんがツイートしていたとおり「ふくろうの描き方」のように感じた。しかし描いたふくろうを手直しできるようにするための工夫を行っているとか、描く本人も完成するか分からないと思いながら気合で作り上げるとかそんな泥臭い話を聞けて、あまりに摩訶不思議で魔法のように見えていたTRICKコードが同じ人間の手によるものなのだと感じた。職人技だ〜

クロージング

恩送りをしよう、アウトプットを世界に届けよう。

登壇者のみなさん、スタッフのみなさん、最高の会を開いてくださりありがとうございました!

福岡観光とか

  • 鯖のさしみが美味しかった
  • 資さんうどん、めちゃめちゃ良かった。たっぷりのごぼ天に甘く味付けされた牛肉…甘い味付けよ…!!地元の味を思い出すかのような少し甘めの味がしんみり来たし美味しくて、地下鉄+歩きで行くにはちょっと遠かったけど食べられて良かった。また福岡に行ったらうどん食べたいなぁ。
  • 会場の八女茶がホットもアイスもとても美味しかった。茶葉買って帰れば良かった。
  • 翌日に行った大濠公園がとても心落ち着く場所だった。地下鉄からもアクセスがよかった。凪いだ池と飛び交う鳥たち、散歩する犬に心が和んだ。
  • 茶店にあまり行けなかったので、今度福岡に行くことがあればいろいろな喫茶店に行きたい。

IRB会議

緊急IRB会議がお昼の寿司の部・夜のうどんの部の2回開催された。今のIRB/Relineをとりまく状況とか、困っていること、今後の方針など話せてとても良かった。やはりリアルタイムで話すのは早くて帯域が広くていいな。自分じゃ権限がなくてできなかったことがその場でシュッと依頼できていろいろ前に進んだりもした。物理的な距離があり、なかなか集まれないメンバーなのでいい機会だった。

寿司の部ではチームとか方針の話を主にして、うどんの部ではコードに踏み込んだ話をがっつりできた。PRの解説を本人に図付きで解説してもらうのとても分かりやすくてありがたい。

その他 \1\2 の謎とか、メソッドチェーンの補完が重すぎるとか、Reline::Terminfoの話とか、JRuby分からないとか、readlineどうしようねみたいな話とかいろいろ。 Relineコードリーディング部やりたい。

あと、うどんの部でmrubyのコードの読み方がわからなかったところを聞けて詰まっていたところの解消ができてよかった。

分からなかったのはここ。

extern const char mrb_utf8len_table[];
const char mrb_utf8len_table[] = {
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0
};

mrb_int
mrb_utf8len(const char* p, const char* e)
{
  mrb_int len = mrb_utf8len_table[(unsigned char)p[0] >> 3];

github.com

UTF-8の1文字のバイト長を取得する部分で、mrb_utf8len_table がバイト長を返していそうなのは分かるがなんでこれでいいのか分からず詰まっていた。そのことを質問したところ、UTF-8の文字の1バイト目を3つ右シフトして5ビットにして、5ビットの値をindexにして mrb_utf8len_table に渡しているんじゃないかと教えてもらった。

AND演算すればいいのでは?とも聞いたところ、このほうが命令数が少なくなるからこうしているのではと教えてもらって自分にはない観点が得られた。CPUにやさしいコードだった。

コード見て話しながら、これは3つ右シフトしたら5ビットだから0~31でテーブルに32個あるんじゃないですかねえとかここでマッチングかけてるというのがシュッとでてくる人たち、ビット演算や2進数の扱いに慣れてて自分も精進せねばと思った。私は空中で計算ができないのでiPadに書いて認識があってるか他の人たちに確認した。

Ruby 3.2 リリースパーティー presented by アンドパッドに参加した

Ruby 3.2 リリースパーティー presented by アンドパッドに参加しました。とても楽しい時間で、新しいRubyのたくさんの機能が楽しみになりました。

andpad.connpass.com

WASM

irb.wasmのReline対応がアツい!PRを見てもどうトライすればその修正になるのか、何でそうすれば動くのかわかりません。元気に動いていてかっこいいです。

デモでの表示崩れが気になってデバッグしてました。端末(ブラウザ)が表示できる幅を79文字以下にすると折返しがうまく描画できなくなっていたので、画面の大きさ取得がうまくいってなさそうとわかりました。

Relineでいうとこのあたりです。

github.com

irb.wasmではこのあたりでIO.winsizeを上書きしているようです。

github.com

横幅を79文字になるようにしてirb.wasmをリロードしてもやはり折返しがうまくいっていなかったので、ブラウザの端末幅を取得できていないのかも?と思いました。 あと縦幅も19行以下?にすると補完を出したときの強制スクロールがうまくなさそうでした。これも固定行で扱っているからなのかもしれません。

WASM について何からどう触っていいか自分はよくわかっていないと感じました。なにかしら触ってみたいけど何からやればいいのか〜な状態なので、ちょっと遊んでみたいです。ビンゴゲームとか郵便ゲームとか楽しそうです。TryRuby的な入力を受け付けて実行する簡単なものを書いてみるといいのかなとも考えています。

debugger

debuggerどんどん便利になっていてすごいです。

irb/debuggerにビジュアライズしたイメージを出すにはRelineでSixel対応が必要そうな気がしました。

以前Sixel対応の話をどこかで聞いたときは、何に使えるんだろう?と思っていたのですが、debuggerとの連携で需要があるのかもしれません。あるいは、作ってみてから用途を考えるでもいいのかもしれません。

そのほか

ReDOS対応、バックトレースの対応、型の話などじっくり聞けてよかったです。当事者から語ってもらえる場がとてもありがたいです。

終わった後少し参加者とお話して、Relineのレビューについて直接フィードバックをもらったり、キーボードの話をしたりとRubyistとの交流もできてとても楽しかったです。フィードバックが嬉しくてやっていきエネルギーが高まりました。自分もどんどんフィードバックしていきたいです。 今年はRubyKaigiやRWCがあったものの、関東で大きい集まりができる機会はあまりなかった気がして新鮮でした。話し足りませんでした。

やっていき

最近 IRB と Reline の committer になりました。 Reline は @hasumikin と同時に、IRB は @hasumikin @st0012 と同時に committer になりました。ちなみに Ruby の committer ではないです。

Ruby 3.2 の明るい話を聞きながら、自分が来年こういう場にいたらどんな話を持っていけるだろうかと思いました。とりあえず、楽しくメンテナンスを続けることが第一の目標です。あわよくば新機能も考えていきたい。そんな感じで今後ともよろしくお願いします。

Ruby ビルド時の parse.tmp.y:12.10-14: require bison 3.0, but have 2.3 を解決する

macOS に入っている bison のバージョンが 2.3 のため Ruby 3.2 がビルドできなくなっていた。

❯ asdf install ruby 3.2.0-dev
Downloading ruby-build...
Cloning into '/Users/mi/.asdf/plugins/ruby/ruby-build-source'...
remote: Enumerating objects: 13397, done.
remote: Counting objects: 100% (2096/2096), done.
remote: Compressing objects: 100% (374/374), done.
remote: Total 13397 (delta 1876), reused 1828 (delta 1704), pack-reused 11301
Receiving objects: 100% (13397/13397), 2.70 MiB | 2.33 MiB/s, done.
Resolving deltas: 100% (9114/9114), done.
Already on 'master'
To follow progress, use 'tail -f /var/folders/7g/c0g_krhn7zg7q4jzpntm6ylw0000gn/T/ruby-build.20221214004540.19944.log' or pass --verbose
Downloading openssl-3.0.7.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/83049d042a260e696f62406ac5c08bf706fd84383f945cf21bd61e9ed95c396e
Installing openssl-3.0.7...
Installed openssl-3.0.7 to /Users/mi/.asdf/installs/ruby/3.2.0-dev

Cloning https://github.com/ruby/ruby.git...
Installing ruby-master...
ruby-build: using readline from homebrew
ruby-build: using gmp from homebrew

BUILD FAILED (macOS 12.4 using ruby-build 20221206)

Inspect or clean up the working tree at /var/folders/7g/c0g_krhn7zg7q4jzpntm6ylw0000gn/T/ruby-build.20221214004540.19944.xS24dl
Results logged to /var/folders/7g/c0g_krhn7zg7q4jzpntm6ylw0000gn/T/ruby-build.20221214004540.19944.log

Last 10 log lines:
generating parse.c
copying lex.c
compiling proc.c
compiling process.c
making ractor.rbinc
compiling random.c
compiling range.c
parse.tmp.y:12.10-14: require bison 3.0, but have 2.3
make: *** [parse.c] Error 63
make: *** Waiting for unfinished jobs....


❯ bison -V
bison (GNU Bison) 2.3
Written by Robert Corbett and Richard Stallman.

Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Ruby 3.2 からは bison 3.0 以上が必要になるため、インストールしてPATHを通す。

homebrew を使っている場合は、

brew install bison

で bison をインストールする。

インストール時に以下のように通すべきPATHが書いてあるためここにPATHを通す。

以下の例は Intel mac で、M1 mac だとおそらくパスが異なる。

If you need to have bison first in your PATH, run:
  echo 'export PATH="/usr/local/opt/bison/bin:$PATH"' >> ~/.zshrc

.zshrc に PATH を書いて、シェルを再起動するか source ~/.zshrc する。

# bison
export PATH="/usr/local/opt/bison/bin:$PATH"

bison -V でバージョンが変わっていたらOK

❯ bison -V
bison (GNU Bison) 3.8.2
Written by Robert Corbett and Richard Stallman.

Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


❯ asdf install ruby 3.2.0-dev
Downloading ruby-build...
Cloning into '/Users/mi/.asdf/plugins/ruby/ruby-build-source'...
remote: Enumerating objects: 13397, done.
remote: Counting objects: 100% (2084/2084), done.
remote: Compressing objects: 100% (392/392), done.
remote: Total 13397 (delta 1864), reused 1798 (delta 1674), pack-reused 11313
Receiving objects: 100% (13397/13397), 2.70 MiB | 4.38 MiB/s, done.
Resolving deltas: 100% (9114/9114), done.
Already on 'master'
To follow progress, use 'tail -f /var/folders/7g/c0g_krhn7zg7q4jzpntm6ylw0000gn/T/ruby-build.20221214010049.68309.log' or pass --verbose
Downloading openssl-3.0.7.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/83049d042a260e696f62406ac5c08bf706fd84383f945cf21bd61e9ed95c396e
Installing openssl-3.0.7...
Installed openssl-3.0.7 to /Users/mi/.asdf/installs/ruby/3.2.0-dev

Cloning https://github.com/ruby/ruby.git...
Installing ruby-master...
ruby-build: using readline from homebrew
ruby-build: using gmp from homebrew
Installed ruby-master to /Users/mi/.asdf/installs/ruby/3.2.0-dev

perfでCRubyのプロファイリングができる環境を作る

みなさん、こんにちは。ima1zumi です。

これは Ruby Advent Calendar 2022 6日目の記事です。

本日は macOS で perf が動く仮想環境を作って CRuby のプロファイリングできる環境構築をしていきます。

目次

macOS で perf は使えない

私は普段 macOS で開発しているのですが、perf は Linux 用の計測ツールなので macOS では利用できません。

macOS には Instrument という計測ツールがありますが、情報が少なく調査に難儀するためここでは利用者の多い perf を使います。

というわけで Ubuntu の環境を作っていきますが、 Docker for mac は perf が使えません。そのため、 Virtualbox & Vagrant仮想マシンが動く環境を作ります。Linux 環境の方は「perf をインストールする」まで飛ばしてください。

github.com

Virtualbox & VagrantUbuntu が動く環境を作る

Virtualbox をインストール

brew install --cask vitrualbox または Downloads – Oracle VM VirtualBoxVirtualbox をインストールし、セットアップウィザードを実行します。

Vagrant をインストール

brew install vagrant または Install | Vagrant | HashiCorp DeveloperVagrant をインストールし、セットアップウィザードを実行します。

Box ファイルを入手

次に仮想マシンのベースとなる Box ファイルを入手します。任意のディレクトリで、

vagrant box add ubuntu/jammy64

を実行し、Box ファイルをインストールします。

以下のサイトで様々な Box ファイルが配布されています。

入手した Box ファイルは vagrant box list で確認できます。

❯ vagrant box list
ubuntu/bionic64 (virtualbox, 20220530.0.0)
ubuntu/bionic64 (virtualbox, 20220810.0.0)
ubuntu/jammy64  (virtualbox, 20220810.0.0)
ubuntu/jammy64  (virtualbox, 20221201.0.0)

Vagrantfile を作成

Vagrantfile は仮想マシンの設定ファイルで、メモリやOSなどをどう使うか指定することができます。

Vagrant を起動したいディレクトリで vagrant init ubuntu/jammy64 を実行します。実行後に Vagrantfile ができていればOKです。今回はデフォルトのまま起動します。

Vagrant を起動

vagrant up仮想マシンを起動します。起動後、vagrant status で状態を確認できます。

❯ vagrant status
Current machine states:

default                   running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.

Vagrant に接続

vagrant sshVagrant に接続します。以下のように、Ubuntu にログインできていれば OK です。

❯ vagrant ssh
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-56-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon Dec  5 13:18:02 UTC 2022

  System load:  0.16455078125     Processes:               108
  Usage of /:   3.6% of 38.70GB   Users logged in:         0
  Memory usage: 20%               IPv4 address for enp0s3: 10.0.2.15
  Swap usage:   0%


0 updates can be applied immediately.


vagrant@ubuntu-jammy:~$

perf をインストール

ここでは apt でインストールします。 perf が含まれる linux-tools は Kernel のバージョンに依存するため、以下のコマンドでインストールします。

sudo apt install linux-tools-`uname -r`

Ruby をビルドする

プロファイリングをする際にビルドオプションを変えたりコードに変更を加えたくなるので、手でビルドできるようにします。

依存ライブラリのインストール

ビルドのために

git ruby autoconf bison gcc(or clang, etc) make

が必須です。gcc は clang など他のコンパイラでもOKです。

この環境には Ruby がインストールされていなかったため、Ruby をインストールします。

sudo apt install ruby

次に、拡張ライブラリのためのライブラリをインストールします。必要なライブラリはビルドする Ruby のバージョンによって変わります。rbenv の Wiki に詳しくまとまっています。

Home · rbenv/ruby-build Wiki

ここでは以下のライブラリをインストールします。

sudo apt install autoconf bison patch build-essential rustc libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libgmp-dev libncurses5-dev libffi-dev libgdbm6 libgdbm-dev libdb-dev uuid-dev

Ruby をビルド

作業用ディレクトリを作ってビルドしていきます。まず RubyソースコードGitHub からクローンします。

mkdir workdir
cd workdir
git clone https://github.com/ruby/ruby.git

github.com

Ruby がクローンできたら ruby ディレクトリに移動して autogen.sh を実行して build ディレクトリを作成します。

cd ruby
./autogen.sh
cd ..
mkdir build
cd build

configure を実行します。configure には色々なコンパイルオプションを渡すことができますが、一旦これでビルドします。

../ruby/configure --prefix=$PWD/../install --enable-shared

make./ruby を生成します。 -j オプションは仮想環境のメモリに余裕がないとコンパイルに失敗しがちだったため、メモリをあまり割り当てていない場合はつけないほうが良さそうです。

make

make install でインストールディレクトリを作成します。

make install

./ruby -v が実行できれば OK です。

./ruby -v
ruby 3.2.0dev (2022-12-06T11:24:02Z master 14074567ea) [x86_64-linux]

perf を実行する

さて、 String#split のプロファイリングをしてみます。性能データを採取するには perf report コマンドを使います。バックトレース情報も含めて採取したいため --cal-graph dwarf をつけます。

String#split の実行時間が短すぎるとうまく採取できず、長すぎると実行結果のファイルが大きくなりすぎるため適当に String#split を実行してその結果を採取します。

sudo perf record --call-graph dwarf -g ~/workdir/install/bin/ruby -e '("あ,い,う,え,お"*100000).split(",")'

実行結果はデフォルトで perf.data ファイルに出力され、 perf report で確認できます。CPU使用率が表示されています。

sudo perf report

Ruby のメソッドに相当する CRuby の関数は rb_ で始まることが多いです。String#split に対応するCRubyの関数は rb_str_split で、その中で rb_str_split_m を実行しています。

rb_str_split_m の中の関数にどれくらいCPUを使用しているか見てみます。見たい行にカーソルをあわせて + キーを押します。

このように詳細が見られます。

また、採取した perf.data を使って flamegraph を出力することもできます。計測において可視化はとても強力なので、ぜひ使ってみてください。

github.com

参考