Crystalで書いたコードのコールグラフを Valgrind + KCachegrind で見てみるよ

## はじめに

Crystalでどのメソッドがどのメソッドから呼ばれているか知りたいことなどありませんか？
Rubyは動的言語でREPLを使った内観に優れていますが、Crystalではオブジェクトの内観が難しいと感じることがあります。

そういった難しさに対処するために、静的言語向けの解析ツールに慣れていきたいですね。

今日は[Valgrind](https://valgrind.org/)を使ってコールグラフを書いてみます。人生でValgrindを使うのは3回目ぐらいなので記事がテキトーなのはご容赦ください。

<img src="https://valgrind.org/images/st-george-dragon.png">

ValgrindはLinux用のデバッグツールで、その名前は北欧神話におけるヴァルハラ[^1]への入り口の名に由来しています。この記事は下の記事を参考に書かれました。

https://caddi.tech/archives/2251

とにかくカッコよくて面白い KCachegrind の画面。crystalの文字が見えるだろうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/e7290abd-b75b-852d-d323-88dfc05816ff.png)

## 用意したコード

それでは今回利用する簡単なコードを用意しました。
`piyo0` -> `piyo1` -> `piyo2` -> `piyo3` -> `piyo4` -> `piyo5` -> `piyo6` -> `piyo7` -> `piyo8` -> `piyo9` -> `piyo10` の順番でメソッドが呼ばれていきます。

```crystal:piyo.cr
class Tori
  def initialize(@x = 0)
  end

  def piyo
    @x = 0
    piyo1
  end

  def piyo1
    @x = 1
    piyo2
  end

  def piyo2
    @x = 2
    piyo3
  end

  def piyo3
    @x = 3
    piyo4
  end

  def piyo4
    @x = 4
    piyo5
  end

  def piyo5
    @x = 5
    piyo6
  end

  def piyo6
    @x = 6
    piyo7
  end

  def piyo7
    @x = 7
    piyo8
  end

  def piyo8
    @x = 8
    piyo9
  end

  def piyo9
    @x = 9
    piyo10
  end

  def piyo10
    @x = 10
  end
end

t = Tori.new

# `piyo0` -> `piyo1` -> `piyo2` -> `piyo3` -> `piyo4` -> `piyo5` -> `piyo6` -> `piyo7` -> `piyo8` -> `piyo9` -> `piyo10`
t.piyo
```

ではビルドしてみましょう。今回はパフォーマンスを調べたいわけではないのでデバッグビルドしておきます。


```sh
crystal build --debug piyo.cr
```

Valgrindで解析します。

```sh
valgrind --tool=callgrind ./piyo # = は必須
```

[KCachegrinbd](https://kcachegrind.github.io/html/Home.html)を起動します。

```sh
kcachegrind callgrind.out.9792 # 番号はCallgrindを実行したプロセスのID
```

こんな感じのかっこいい画面が出てくると思います。

![Screenshot from 2023-12-07 20-13-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/283365de-f57d-4f0b-0673-d037ed6291d8.png)

すでに、この時点で画面がめちゃくちゃ面白いのです。面白いのですが、勉強中でわかっていない点が多いのでスルーします。さて、`piyo` 系のメソッドは実質何もやっていないメソッドなので実行時間も極端に短く、検索して見つけた方が早いと思います。

![Screenshot from 2023-12-07 20-15-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/ed140bc3-4f4c-c049-855d-c45b0e1fda24.png)

いたいた。

これで、piyoを選択すると、ジャーン！！

![Screenshot from 2023-12-07 20-18-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/13ee628d-ff4c-80f2-27be-a719974c2b2c.png)

めっちゃわかりやすい!!

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/d8246da2-2ca7-6427-e9ee-20bb2da563ad.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/25cef0e1-f043-c41e-6f8b-945b777dbb95.png)


piyo系のメソッドが10まで順番に呼ばれているのを見ることができます。



非常に面白いですね。

今日ははじめてなのでこのぐらいにしておきます。

ValgrindとKCachegrindやばいですね。こ、これが北欧神話か……

この記事は以上です。


### Valgrindの仕組み

英語版のWikipediaの[Valgrind](https://en.wikipedia.org/wiki/Valgrind)の項目を日本語に翻訳したが、かなりメチャクチャなツールだということがわかる。作者の [Julian Seward](https://en.wikipedia.org/wiki/Julian_Seward) さんすごすぎ……。

> Valgrindは本質的に、動的再コンパイルを含むジャストインタイムコンパイル技術を使用する仮想マシンです。元のプログラムから直接ホストプロセッサ上で実行されることはありません。代わりに、Valgrindは最初にプログラムを「中間表現（IR）」と呼ばれる一時的でより単純な形式に変換します。これはプロセッサに依存しない、静的な単一割り当て形式に基づく形式です。変換後、ツール（後述）はIR上で任意の変換を行うことができ、その後ValgrindはIRを再びマシンコードに変換してホストプロセッサが実行できるようにします。Valgrindはバイナリコードを再コンパイルして、同じアーキテクチャのホストおよびターゲット（またはシミュレートされた）CPU上で実行します。また、Valgrind内で実行中のターゲットプログラムをデバッグするためのGDBスタブを含み、「モニターコマンド」を使用してさまざまな情報についてValgrindツールに問い合わせることができます。

### ヴァルハラとはなにか

[^1]: >北欧神話における主神オーディンの宮殿。ヴァルハラはグラズヘイムにあり、ワルキューレによって選別された戦士の魂（エインヘリャル）が集められる。レーラズ（英語版）（ユグドラシルの1本）の影が落ちるこの宮殿には、540の扉、槍の壁、楯の屋根、鎧に覆われた長椅子があり[1]、狼と鷲がうろついているという。これは、戦場の暗喩である。館の中では戦と饗宴が行われ、ラグナロクに備える。また、この館には雄鶏のグリンカムビ（黄金の鶏冠）が住んでいるとされている。 [Wikipediaより](https://ja.wikipedia.org/wiki/%E3%83%B4%E3%82%A1%E3%83%AB%E3%83%8F%E3%83%A9)