要約

普段使っているターミナルエミュレータ kitty にPullRequestを送り、無事にマージされた。


きっかけ

kittyにはグラフィックスプロトコルという、ターミナル上に画像を描画する仕組みがある。これを、ブラウザの描画結果をターミナルへ流し込む用途に使えないか試していた。

アクティビティモニタでSSDへの書き込みが増えていることに気づいた。macOSのfs_usageで観察すると、kitty が受け取った画像データをディスクキャッシュへpwriteで書き込んでいることを確認した。

kitty ... REG ... /Users/<user>/Library/Caches/kitty/disk-cache-...
kitty ... pwrite F=26 B=0x9ef7b4

0x9ef7b4は約10MB。フレームは頻繁に更新され、すぐ次のフレームで上書きされる。

ディスクキャッシュの挙動としては正常だが、この用途では書き込みを避けたい。しかし、グラフィックスプロトコルにはディスクキャッシュを回避する方法がなかった。

Issue を立てる

Issue #10090 を立てた。

メンテナーから、まず次のような返信があった。

Dont transmit full frames in the first place, use the animation support to transmit frame delta, see how awrit does it for example, which is a browser that uses the kitty graphics protocol.

awritはkittyのグラフィックスプロトコルで動くブラウザで、アニメーション機能を使って差分更新を行っている。そこでawritを実際に動かし、同じく手元でfs_usageを使って計測した。

writes: 52
total: 337.63 MiB in 1s
rate:  337.63 MiB/s
max:   6.49 MiB

推奨された方法でも、1秒間に300MiBを超える書き込みが発生していた。

つまり、転送パターンとしては差分更新を使っていても、kitty側のディスクキャッシュへの書き込みは回避できていなかった。そこで、計測結果を添えて問題の説明した。

(反省点として、このIssueは自分の書き方が悪く、メンテナーとの間ですれ違いが起きていた。最初からもっと簡潔に、問題と再現結果を分けて書くべきだった。)

PR を出す

自分の意図を明確にするため、Pull Requestを出して確認してもらうことにした。

初回コミットでは、新しいプロトコルキーN=1を導入し、「この画像はメモリにだけ置き、ディスクキャッシュには書かないでほしい」と直接指定するbooleanとして実装した。

フィードバック

  1. booleanではなくusage-hints bitmaskにする

    Nは単一のbooleanではなく、usage hintsを表すbitmaskとして定義する。現時点ではbit 0、つまりN=1transient hintとして扱う。将来ほかのusage hintを追加できるようにするため、最初から拡張可能な形式にしておく。

  2. プロトコルは実装ではなく意図を伝える

    N=1は「ディスクキャッシュを書いてはいけない」という命令ではなく、「この画像データは短命に使われる想定である」というクライアントから端末へのhintである。端末はこのhintをもとに、短命データとして優先的にevictionしたり、ディスクキャッシュへの永続化を省略したりできる。ただし、具体的にどう最適化するかは端末の実装に委ねられ、プロトコルでは規定しない。

  3. 合成後にもtransienthintを伝播させる

    アニメーションフレームなどを合成する場合、関与するフレームのいずれかがtransientなら、合成結果もtransientとみなす。合成結果はtransientな入力データに依存しているため、その性質を失わせずに伝播させる必要がある。

修正後にマージされた

フィードバックに沿ってNをbitmaskに変更した。そして、最初のusage hintとして transient(値 1)を定義した。

プロトコル文も、「ディスクキャッシュを書かない」という実装の指定ではなく、「クライアントから端末へ画像の用途を伝えるヒント」として書き直した。あわせて、フレーム合成時の伝播ルールも実装に反映した。

N    bitmask    0    Usage hints from the client to the terminal
                     about the intended use of the image.

最終的に、PR #10092 は master にマージされた。

PR #10092 が master にマージされた様子
PR #10092 が master にマージされた様子

感想

初めてのOSSコントリビューションで、コードそのものよりも設計面で学ぶことが多かった。普段使っているツールに対して、自分の困りごとを起点に貢献できたのは嬉しい。