[Ruby] Google Chart で FiberScheduler のFiberタスク切り替えを可視化する

Google Chart の [Timeline chart](https://developers.google.com/chart/interactive/docs/gallery/timeline)を使って可視化した。
雑に可視化まで完成したのでそこまでメモる。


## データの取り方

以下のようにTracePointを使って、`fiber_switch`のタイミングを取得した。

```rb
t_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
records = [{fiber_id: "dummy", tooltip: "dummy", start: 0, end: 0}]

trace = TracePoint.new(:fiber_switch) do |tp|
  records << {
    fiber_id: Fiber.current.object_id.to_s,
    tooltip: Fiber.current.inspect.gsub("<", "").gsub(">", ""),
    start: records[-1][:end],
    end: Process.clock_gettime(Process::CLOCK_MONOTONIC) - t_start,
  }
end


# 以下、FiberSchdulerを使った非同期処理
Fiber.set_scheduler = Scheduler.new
# ....
```

ここから、ERBを使って、以下のHTMLを生成した。

## HTML

```html
<html>
  <head>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript">
      google.charts.load('current', {'packages':['timeline']});
      google.charts.setOnLoadCallback(drawChart);

      function drawChart() {
        var container = document.getElementById('timeline-tooltip');
        var chart = new google.visualization.Timeline(container);
        var dataTable = new google.visualization.DataTable();

        dataTable.addColumn({ type: 'string', id: 'Fiber ID' });
        dataTable.addColumn({ type: 'string', id: 'dummy bar label' });
        dataTable.addColumn({ type: 'string', role: 'tooltip' });
        dataTable.addColumn({ type: 'number', id: 'Start' });
        dataTable.addColumn({ type: 'number', id: 'End' });
        dataTable.addRows(
          [["dummy", "", "dummy", 0, 0], ["100", "", "#Fiber:0x0000000104933bb8 samples/address.rb:36 (resumed)", 0, 2.7999999929306796e-05], ["120", "", "#Fiber:0x00000001049334d8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 2.7999999929306796e-05, 4.0000000012696546e-05], ["140", "", "#Fiber:0x0000000104932c90 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/async_scheduler-0.1.1/lib/async_scheduler/scheduler.rb:228 (resumed)", 4.0000000012696546e-05, 8.09999999091815e-05], ["120", "", "#Fiber:0x00000001049334d8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 8.09999999091815e-05, 8.900000000267028e-05], ["160", "", "#Fiber:0x0000000104931890 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/async_scheduler-0.1.1/lib/async_scheduler/scheduler.rb:228 (resumed)", 8.900000000267028e-05, 0.00010999999994965037], ["120", "", "#Fiber:0x00000001049334d8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.00010999999994965037, 0.00011399999993955134], ["180", "", "#Fiber:0x0000000104931048 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/async_scheduler-0.1.1/lib/async_scheduler/scheduler.rb:228 (resumed)", 0.00011399999993955134, 0.00014799999996739643], ["120", "", "#Fiber:0x00000001049334d8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.00014799999996739643, 0.00015499999994972313], ["200", "", "#Fiber:0x0000000104993540 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/async_scheduler-0.1.1/lib/async_scheduler/scheduler.rb:228 (resumed)", 0.00015499999994972313, 0.0002559999999220963], ["120", "", "#Fiber:0x00000001049334d8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.0002559999999220963, 0.0002599999999119973], ["100", "", "#Fiber:0x0000000104933bb8 samples/address.rb:36 (resumed)", 0.0002599999999119973, 0.0006419999999707215], ["60", "", "#Fiber:0x00000001048ac6b8 (resumed)", 0.0006419999999707215, 0.0006509999999479987], ["260", "", "#Fiber:0x000000010498a378 samples/address.rb:40 (resumed)", 0.0006509999999479987, 0.0006609999999227512], ["280", "", "#Fiber:0x000000010498a008 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.0006609999999227512, 0.0006700000000137152], ["260", "", "#Fiber:0x000000010498a378 samples/address.rb:40 (resumed)", 0.0006700000000137152, 0.0007580000000189102], ["60", "", "#Fiber:0x00000001048ac6b8 (resumed)", 0.0007580000000189102, 0.0007630000000062864], ["340", "", "#Fiber:0x0000000104988190 samples/address.rb:44 (resumed)", 0.0007630000000062864, 0.0007759999999734646], ["360", "", "#Fiber:0x0000000104983de8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.0007759999999734646, 0.0007839999999532665], ["340", "", "#Fiber:0x0000000104988190 samples/address.rb:44 (resumed)", 0.0007839999999532665, 0.0008589999999912834], ["60", "", "#Fiber:0x00000001048ac6b8 (resumed)", 0.0008589999999912834, 0.0008629999999811844], ["100", "", "#Fiber:0x0000000104933bb8 samples/address.rb:36 (resumed)", 0.0008629999999811844, 0.011481000000003405], ["120", "", "#Fiber:0x00000001049334d8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.011481000000003405, 0.011484999999993306], ["100", "", "#Fiber:0x0000000104933bb8 samples/address.rb:36 (resumed)", 0.011484999999993306, 0.0117289999999457], ["60", "", "#Fiber:0x00000001048ac6b8 (resumed)", 0.0117289999999457, 0.0117329999999356], ["340", "", "#Fiber:0x0000000104988190 samples/address.rb:44 (resumed)", 0.0117329999999356, 0.011736999999925501], ["360", "", "#Fiber:0x0000000104983de8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.011736999999925501, 0.011739999999917927], ["340", "", "#Fiber:0x0000000104988190 samples/address.rb:44 (resumed)", 0.011739999999917927, 0.011853999999971165], ["60", "", "#Fiber:0x00000001048ac6b8 (resumed)", 0.011853999999971165, 0.011857999999961066], ["260", "", "#Fiber:0x000000010498a378 samples/address.rb:40 (resumed)", 0.011857999999961066, 0.011870999999928245], ["280", "", "#Fiber:0x000000010498a008 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.011870999999928245, 0.011872999999923195], ["260", "", "#Fiber:0x000000010498a378 samples/address.rb:40 (resumed)", 0.011872999999923195, 0.011983999999984007], ["60", "", "#Fiber:0x00000001048ac6b8 (resumed)", 0.011983999999984007, 0.011986999999976433], ["100", "", "#Fiber:0x0000000104933bb8 samples/address.rb:36 (resumed)", 0.011986999999976433, 0.025032000000010157], ["120", "", "#Fiber:0x00000001049334d8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.025032000000010157, 0.025036999999997533], ["100", "", "#Fiber:0x0000000104933bb8 samples/address.rb:36 (resumed)", 0.025036999999997533, 0.025276999999960026], ["60", "", "#Fiber:0x00000001048ac6b8 (resumed)", 0.025276999999960026, 0.02529299999991963], ["340", "", "#Fiber:0x0000000104988190 samples/address.rb:44 (resumed)", 0.02529299999991963, 0.025299000000018168], ["360", "", "#Fiber:0x0000000104983de8 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.025299000000018168, 0.025302000000010594], ["340", "", "#Fiber:0x0000000104988190 samples/address.rb:44 (resumed)", 0.025302000000010594, 0.026165999999989253], ["60", "", "#Fiber:0x00000001048ac6b8 (resumed)", 0.026165999999989253, 0.026177999999958956], ["260", "", "#Fiber:0x000000010498a378 samples/address.rb:40 (resumed)", 0.026177999999958956, 0.026181999999948857], ["280", "", "#Fiber:0x000000010498a008 /Users/xxx/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/resolv_fiber-0.1.0/lib/resolv_fiber.rb:42 (resumed)", 0.026181999999948857, 0.026183999999943808], ["260", "", "#Fiber:0x000000010498a378 samples/address.rb:40 (resumed)", 0.026183999999943808, 0.02623299999993378], ["60", "", "#Fiber:0x00000001048ac6b8 (resumed)", 0.02623299999993378, 0.02624399999990601]]
          // [ '80', null, 'tooltip1', 12, 13],
          // [ '260', null, 'tooltip2', 14,  18 ],
          // [ '340', null, 'tooltip3', 18,  24 ],
        );

        chart.draw(dataTable);
      }
    </script>
  </head>
  <body>
    <div id="timeline-tooltip" ></div>
    <div id="timeline-tooltip" style="height: 1500px;"></div>
  </body>
</html>

```

## ブラウザで見る

以下の通り

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/cc4f6c7c-fe90-35f2-ce42-8ee9458f1380.png)


TODO: 改善していく。