kanejaku.org

縁日 2022/05/11

11 May 2022

カタカタといつものようにキーボードを叩いていると外から笛の音が聞こえてきた。ドンドンと太鼓の音もする。換気のために開けていた窓を全開にして外を覗き込むと神輿を引く人々がみえた。

掲示板に大祭の案内が掲示されていたのを思い出す。少しづつ下町の夏が戻ってきている。

地元の子であろう元気な男子が「俺ポテトにするー」とはしゃぎながら駆け抜けていった。

Perfetto via Rust - 2022/04/28

28 Apr 2022

Perfetto は Android platform で使われている tracing フレームワーク。Android platform 以外でも単独でアプリケーションに組み込んで使うことも想定して作られていて、例えば Chrome が使っている。この Perfetto を Rust で書いたアプリケーションから使ってみようと試している。

現状のプロトタイプ実装で HTTP/1.1 のリクエストを投げてレスポンスを解釈する async タスクを以下のように書くと:

async fn h1_get_task(host: String, port: u16) -> anyhow::Result<()> {
    let track = Track::with_name(&host);
    trace_event!(CATEGORY_BENCHMARK, "Request", track, EventType::SliceBegin);

    let mut client = Client::connect(host.clone(), port, track).await?;
    client.send_request().await?;
    let response = client.recv_response().await?;

    trace_event!(
        CATEGORY_BENCHMARK,
        "Request",
        track,
        EventType::SliceEnd,
        |event| {
            trace_event_set_string!("host", &host);
            trace_event_set_string!("status", response.status().as_ptr());
        }
    );

    Ok(())
}

struct Client { /* ... */ }

impl Client {
    async fn connect(host: String, port: u16, track: Track) -> Result<Self> {
        let _s = trace_event_span!(CATEGORY_BENCHMARK, "Connect", track);
        // ...
    }
    async fn send_request(&mut self) -> Result<()> {
        let _s = trace_event_span!(CATEGORY_BENCHMARK, "Send", self.track);
        // ...
    }
    async fn recv_response(&mut self) -> Result<Response> {
        let _s = trace_event_span!(CATEGORY_BENCHMARK, "Recv", self.track);
        loop {
            match self.state {
                State::ReadingHeaders => self.read_headers().await?,
                State::ReadingBody => self.read_body().await?,
                State::Done => break,
            }
        }
        // ...
    }
    async fn read_headers(&mut self) -> Result<()> {
        let _s = trace_event_span!(CATEGORY_BENCHMARK, "ReadHeaders", self.track);
        // ...
    }
    async fn read_body(&mut self) -> Result<()> {
        let _s = trace_event_span!(CATEGORY_BENCHMARK, "ReadBody", self.track);
        // ...
    }
}

こんな感じのトレースが得られる。

trace_event!trace_event_span! が C++ の TRACE_EVENT()に相当する。スコープを扱うのに _s に代入しているのはいびつだけれど、これは Attribute macros で対処できる目途が立っている。

Perfetto には track という概念がある。分散環境を意識した用語でいえば span と同等のもの。 Android での tracing を主な用途とする Perfetto では TRACE_EVENT() で記録される event はデフォルトでスレッドと1:1に対応する track に紐づけられる。

一方 Async Rust では .await の前後でスレッドが異なるエコシステム (tokio) で trace を記録したいことがほとんど。 C++ と同じ感じで track を省略して書くと UI が span を期待通りに表示してくれない。プロトタイプでは明示的に track を要求するようにしている。似た様な問題意識を持つ tracing crate はこのあたりを隠蔽しようと悪戦苦闘している様子だが見込みは薄そう。

Event を引数付きで記録したい場合は event にメタデータを付与するコールバックを渡す。TRACE_EVENT() のように記録したいパラメータを inline で渡せるマクロを提供できるかもしれないが、自分はマクロに詳しくなりたいわけではないので深掘りしていない。

実用には至っていない。困っている点を二つ羅列しておく。

  • 動的に決まる key-value ペア (HTTP response headers とか) を trace event として記録する方法が分からない。Perfetto はオーバーヘッドを減らすべく key を internalize する。Internalize するときに使われるのは key のアドレスのようだ。つまり key は静的にアロケートされているか、動的に確保されたときは同じアドレスが使われていてはいけない。スタックに一時的に key を保存するようなナイーブなやり方だとこの前提を崩してしまい、期待した動きにならない。
  • TRACE_EVENT()perfetto::TracedValue を引数に受け取る lambda を受け付けるように読めるが、マクロを使わずに TraceForCategory() を直に叩くとコンパイルに失敗する。これは単純に自分の C++ 力が足りないだけ。

仕様を読む - 2022/03/02

2 Mar 2022

一月の下旬に流行りものをもらって床に臥せったあと復帰して忙しく過ごしていたらもう三月になっていた。

このところ仕様を読む機会が増えた。

QUIC 関連の RFC は長いこと議論した後に最近標準化が完了したというのもあって読み進めるのにあまり苦労しなかった。一方 living standard を謳う後者は読むたびに「うーん」という感想を抱くことが多く雑念が入りがちであった。


これらの仕様は複雑に思えるという意見を見聞きした。曰くプロトコルやアプリケーションはもっとシンプルに作れるのではないか。牧歌的な古き良き時代と同じコンテキストであればそれはまっとうな批評だと思う。けれどウェブとインターネットは進化しあらゆる人が依存する本当の意味でのインフラとなった。昔の価値観を持ってナイーブな批判をするのは思慮が足りない。Jana Iyengar の言葉を借りれば Thse are as simple as the modern internet demands, which is not very simple in absolute terms といったところ。

HTTP/1.1 を喋る

16 Jan 2022

世の中ほぼ HTTP/2 以降に移行しただろうし、自分で試した感じ問題なさそうと自前の HTTP/2 サーバでこのサイトを運用し始めて数週間経過した。しばらくログを眺めていて気付いた。ほとんどの検索エンジンやフィードを巡回する bot はいまだ HTTP/1.1 しか喋らない。

googlebot は HTTP/2 に対応します、という記事が出たのは2020年だった。進捗は芳しくないよう。少なくともこのサイトの巡回においてはまだ HTTP/1.1 を使っているようだ。

検索はともかくフィードは機能させたいので HTTP/1.1 も理解するようにサーバに手を入れた。雑な実装なので上手く動いていないかもしれない。

5 PM - 2022/01/14

14 Jan 2022

ベランダから望むトーキョー開発。

2022年 正月休み

4 Jan 2022

去年に引き続き今年も東京で新年を迎えた。来年は実家へ帰省したいなあ。

今回の年越しは地域密着でいこうと、近所のお蕎麦屋さんに年越しそばをお願いしておいた。そばを受け取ったあと餅を和菓子屋さんで買い求めた。自宅でそばを茹でる。

一升餅。

おせちはお取り寄せ。雑煮とぜんざいを食べる。

年末に Intel NUC を買ってコードを書くのに使っている。Ubuntu 21.10 は UI がこなれていて不満がない。Windows を使う頻度が減った。

積読を消化するべく Web配信の技術 に手をつけ HTTP キャッシュへの理解を進める。Practical MonitoringLinux Observability with BPF にも目を通したがこれらは今の所冷やかし止まり。

2021年の振り返り

31 Dec 2021

年始の抱負には沿わない一年だったが振り返ると悪くないで年あった。

趣味コーディング

今年の 2 月あたりまでスーパーファミコンのサウンドチップ SPC 700 のエミュレータを書いていた。React で UI を書き、作業用 BGM を流す PWA にするところまで作った。夏のある夕暮れ時に上野公園を散歩しながら Smiles and Tears を作ったアプリで聞いたときは思い出補正も相まって結構感動してしまった。

春先から夏まで HTTP/2 サーバを書いていた。一通り動くところまで書いた後しばらく放置していた。時間がある年末に実用できるまで持っていこうと再度書き直している。年内に一区切りつけたかったのだけど間に合わなかった。

そのほかツールを細々と整備している。自分用の辞書アプリを Actix から tokio を使った質素な自前の HTTP/1.1 サーバへと移行した。Actix はコンパイルにやたらと時間がかかっていて(たぶんmiddlewareを自作していたから)、ちょっとした改修が億劫になっていた。この移行で修正が気楽にできるようになり満足している。今年はサーバを Rust async で二つ書いたので作例から一歩踏み込んだ理解が得られたと思う。

昔書いた NES エミュレータに音源を可視化する機能をつけてツイートしたところ、プチバズりする経験もした。

Write Code Every Day を実践した年でもある。数年前にも一度やった気がする。やって良かったかと振り返ると、良くなかった。頭を使う作業よりも自明な変更を優先しがちになる。難しいこと考えたり理解したりする時間が減ってしまい成長を阻害していた感覚がある。来年は毎日コードを書くのにはこだわらないようにしよう。

総じて普段使いの自作ツールの完成度を上げれて良い感じの一年であった。

読書

読み終えたと言えそうな本のリストだけ。積読が溜まる一方でどうにかしたい。簡単な感想も書こうと思っていたが力尽きてしまった。

クリエイティブ

模倣ではない何かをやりたい。オリジナルのドット絵を描きたい。DAWを使って曲を作りたい。昨年末にそんな思いを持っていたのだけれど自分には難しそうだ。

自分は出るか出ないか分からないもの(=オリジナリティのある何か)への時間の投資よりも、期待値が一定数あるもの(=誰がやっても似た様な物になる何か)に時間を割きがちなのを改めて認識した。幻想を追うのをやめて個性だと受け止める。

ブログ

春先から更新できず。元々文章を書くのは得意ではない上に、仕事で文章を書く頻度が増えたのでブログを書く意欲が湧かなかった。気が向いたら書く、ぐらいを維持していきたい。

仕事

熱心に働いた。会社の評価はふつうとのこと。

年初めに違うチームへ移動した。ちょっとした移動なので所属に変化はなく、関わるプロジェクトがネットワーク寄りになった感じ。

Early Hints の実装が主な仕事だった。design → implementation → experiment と通しで主導できたのは楽しかった。外部の開発者とのミーティングやメールでのやり取りが増え、新たに学ぶことが多かった。Cloudflare のブログエントリが出るときは冷や汗をかく折衝をしたのもいい思い出になっている。この時は PM のみなさんに大変お世話になった。なお、このページでも試験的に Early Hints を送って css とフォントを preload している(はず、動いていれば)。クライアント側もサーバ側も書いて動作を確認できたのはちょっぴり嬉しい。

後半は WebTransport の ship に向けた作業のお手伝いをやっていた。主にやっていたのは Web Platform Tests というブラウザ共通のテストのインフラの整備。合意形成に時間をとられる感じであった(#85, #96)。無駄に WPT のインフラに詳しくなった。

組織再編による棚から牡丹餅感はあるものの //net の owner になれたは素直に嬉しかった。

Early Hints 以外の今年書いたコードは細々としたものが多い。来年は自明じゃないコードを書けると良いなあ。

ほぼ100%リモートワークで働いた。会社には2-3回行ったくらい。リモートワークは慣れると生産性高く仕事できる気がする。でも会社がまともに開いたらやっぱり会社で働くのがいい、と思うかもしれない。来年どう思うか。

趣味の延長である Chromium Mojom Language Server を VSCode Marketplace に置けるようになったと聞き及んだので公開した。

主業務以外だと採用関連も少しお手伝いしている。インターン向けの採用委員会があり、そこで細々とした活動をしている。時間をとられて大変ではあるものの、学ぶことが多く良い経験をさせてもらっている。

英語

単純な技術話題を読んだり書いたり聞いたりするのはもう困らない感覚がある。

Hacker News や Reddit とかにありがちな情緒を含んだ表現を使われると分からなくなるけれど DeepL にかければ理解できる。新聞やニュースを英語で理解したい欲求は自分にはそんなに無いので英語での入力には問題を感じなくなってきた。

話すのと書くのはまだ足りてないので引き続き頑張る。

運動

去年よりさらに運動量が増えた。朝の散歩を一部ジョギングに変えたのと、Fit Boxing 2 を春先に買ったのでそれを日課としてやっている。距離換算で 7600 km は我ながら動きすぎだなと思った。

来年の抱負

なし。年末に抱負を書いても毎回未達なので抱負を立てるより日々の充足を追うことにする。

OkHttp の HTTP/2 並列性 - 2021/05/02

2 May 2021

Message Passing #12 で OkHttp がどうやって HTTP/2 の上にブロッキング API を作っているのか、という疑問が書いてあった。興味が出たので Android も Kotlin も分からないけれど少し調べてみた。

最初はコードを読んでいたのだけど途中でしっかりした説明があることに気づいた。ここに知りたいことは書いてあった。

基本はもりたさんが想像した通りのようだ。ソケットからの読み込みには専用のスレッドを使う。この Read 用のスレッドはアプリケーションのコードを実行しない。アプリケーションのコードはどこでブロックするか分からないから。フレームを Read した後は、アプリケーションレイヤのコードを走らせたり、Ping に対する応答などをしなきゃいけない。Read 用の専用スレッドではこれらの処理を扱えないので Runnable をキューに突っ込んで executor threads に実行してもらうようにする。

ブロッキング API は Http2Stream と Http2Writer によって実装されている。Http2Stream は wait/notify を使ってソケットから対応する HTTP/2 stream のデータが届くまでブロックする。 Http2Writer は単純にソケットに書けるまでブロックする。

凝ったことはしていなくて素直な実装であった。


最近の趣味プロジェクトとして HTTP/2 サーバを自作している。

自作 HTTP/2 サーバも OkHttp と似たアプローチを取っている: ソケットからの読み込みは専用のタスク (tokio を使っているのでスレッドではなくタスク)を使う。このタスクは HTTP/2 フレーム単位での読み込み処理のみを行う。読み込んだフレームは他のタスクへ channel 経由で渡され、ファイル IO やソケットへの書き込みは別のタスクが行う。

この自作 HTTP/2 サーバ、単純なリクエスト (navigation + subresources) をさばけるぐらいまでは動いているのだけど、Flow Control にバグがあるらしく、たまに Stall してしまう。この週末はそのバグを直そうとしていた。いくつか問題を見つけて修正したがまだ Stall するケースが残っている。

OkHttp のドキュメントには「Write が Read をブロックしてはいけない、さもなくばデッドロックが生じるかもしれない」との注意書きがある。自作 HTTP/2 サーバがデッドロックするのはこの状況に陥っているからかもしれない、と思い始めた。今の実装は TCP バッファがあふれてて Write がブロックする状況を考慮していない。

こんな風に息抜きのつもりのちょっとした寄り道がヒントをくれたりするのは楽しい。

2021/04/13

13 Apr 2021

I’ve been working hard in the past four weeks: I interviewed twice a week and wrote feedback for every interview. I became a member of a committee which makes decisions about who we hire as interns. I made progress on my own project.

I worked hard because these were fun. I enjoyed working. Really.

I feel I should try not to work so much. I was suffering from burnout last December. It’s the time to apply what I learnt from the experience.

Message Passing 11 感想 - 2021/03/26

26 Mar 2021

Design Docs の話。自分が思ったことは言い尽くされていた。

この一か月くらい合意形成のために一連の文章を書いており、個人的に関心のある話題だった。公かつ現在進行形だし、ということで思いついたことをつらつらと書いてみる。

前提として、ブラウザに Web 標準にかかわる機能を追加するには公で議論する必要がある。Explaner や Design Docs といった体裁の差はあれ、意図を文章に書き下すのは必須になる。この時点でこの手の文章を書くべきかどうか、を議論する選択肢はなくなった。悲しい。個人的には書かなくて済むならそうしたいところ。

Chromium のテンプレートには意図的に従っていない。これは強制されなければ好きなように書けばいいのでは、と思っていたから。当初は Standardization やら Considerations やらのセクションは無く、専門家から突っ込みを受けて追加した。ここは、はまじさんがいっていた、デザインの根幹にかかわる指摘を専門家から受けた事例かな、と思う。実際有難かったし、テンプレートには意味があるなあと思うところでもあった。現時点では Metrics のセクションもない。LCP を改善できるかも、とは書いているが具体的な比較手段を言及する必要がある。現状が許されているのは、件の文章は Intent to Prototype として書かれたもので、とりあえずやってみよう、という段階だから。

なぜそれをやるのか、は意識して書こうとしたのだけど、いろいろと修正していったら焦点がぼやけてしまった。なにをやらないのか、が無いのもその帰着。合意をとるのを重視したのが出ている部分だと思う。

Design のセクションの有用性は半々かなという印象を持っている。このセクションは Proof of Concept なコードをまず書いて、ある程度動く見通しを立ててから文章に落とし込んでいる部分が多い。ただ、alternatives を列挙しているトピックについてはパッチを書く前に合意をとるのに役立ったし、事前にフィードバックをもらうことで解決した問題もあった。

1 つ具体例を挙げる。ネットワークからの信頼できない情報を処理するのに、当初は権限の強いプロセスを使うことを想定していた。これはセキュリティ的に懸念があり頭を悩ませていた部分だった。お茶を濁すような文章を書いていたら、緩和策として分離された別のプロセスで処理する既存の機能を流用できることを教えてもらった。意図を文章で書くことで得られた次善案だった。

Design セクションの後半は TODO: あとで考える が多い。これはもりたさんのいう、決まってないところは無理に書かず、インクリメンタルにアップデートする、という考え方を実践してるのかもしれない。前段で問題のスコープに関して同意をとれていれば詳細について TODO を多用してもだいたい許されるように思う。裏を返せば前半に TODO が少ないのは実装が既に終わっているから。実装し終わった後に TODO を消して実装に合うように記述を修正している。

最後にこのエントリを書いている時点での進捗と進め方について。今はあるトピックについて Work in Progress なパッチを育てている。並行して、今後の大まかな方針について意識を合わせるためのドキュメントを書いている。ここでもコードが先行し、文章が後追い、という感じ。数か月後に振り返ってみて、どう帰着したか見てみると面白いかもしれない。


自分の書いたドキュメントは我ながら稚拙だなあと思う一方、一定の役割を果たしているのならそれでいいか、と割り切って書いている。