🐇

2023年の思い出コーナー

2023/12/30に公開

総評

... どうしても年末は多忙になるんで、これ(思い出コーナー)も年度末に移した方が良いんじゃないかという気はする。

まぁ仕事が忙しいのは良いことなんだけど、去年みたいな自責の大事故と違って今年は外部環境からじわじわと忙しくなってきていて、こういうのをコントロールするのは気をつけることすらできなくて結構つらい。

今年のヒット賞

WasmLinuxはかなりのヒットで、こういう当たり方を狙ってきていたので今後もこのペースで行ければ。いやまぁ解説記事でお茶を濁すのを止めたというのが正確なところか。。

https://zenn.dev/okuoku/articles/73c36d078790f4

面白いところは全然これからなので、来年のこの欄も多分このネタなんじゃないかな。。というわけで来年以降はもうこの欄は無しで良い気がする。

そもそも、ヒット賞の重要な前提はX(旧Twitter)が機能していることなので、Xの現状を考えると来年はそれどころじゃないかもしれない。冷静に考えると、単に面白いってだけのネタが大手サイトを経由せずに何千ビューも稼ぐなんておかしいもんな。 ... 実際、個人サイトがビューを集めるためには 俺ニュース(閉鎖してから今年で20年になる)に載ったりする必要があった とかもうみんな忘れてる(or 生まれてない)と思うけど。。

ただ、ヒットを狙う事自体はかなり本業の方に活きているというか、過去に数多の企画をプレゼンやデモで葬ってきた自分だけど、最近は割とウケが良くなってきた実感がある。ウケる って表現があんまり良くなくて 共感される ことが重要なんだとは思う。なので "共感されるためのコストを払う" ように変えたのがヒットを生み出す秘訣な気がしている。

WasmLinuxの場合は "よく分からないが何だかすごそう" と感じられるように、意図的にかなり勢いのある構成にしている。LinuxをVisual Studioでコンパイルして動かすとか正常な人間なら考えないわけで、そういうポイントを記事の先頭に寄せて、後段に真面目な技術記事を繋げている。WebRTCとか各スクラップのような別のネタは純粋な技術記事にしているけど、そういうのはブックマーク1桁付けば良い方だし。まぁ今後も、ヒットを狙う記事と純粋な技術記事の両方をやって行ければ。

プロジェクト進捗

手ごたえは有りつつエンドプロダクトまでがどれも遠い。。

Schemeインタプリタ

去年分析していた Ribbit https://github.com/udem-dlteam/ribbit/ のデザインをパクってRibbonというSchemeインタプリタを作ってみた。(来年記事化したい)

内部の記述がポータビリティに拘った 冗長なものになっていて:

https://github.com/okuoku/ribbon/blob/3fdbcf683fb44289c614d5f5aebabccdff32a58d/c-proto/c-proto.c#L1203-L1212

  • リファレンスカウントGC + Python風の全てのGCオブジェクトをリンクリストで管理する方式のCycle GC
  • 全てのCレベルローカル変数はLink/Unlinkで明示的にマークする必要がある
  • 例外をthrowする可能性のある手続きは RNFUNC_CALL で全てwrapする
  • RNFUNC_CALL が例外状態で帰ってきた場合は RNFUNC_END マクロが挿入するラベルに goto することで例外を上の関数に返す

これで任意のメモリ管理戦略や例外戦略をサポートできるように考えている。例えばC++的なスマートポインタと例外を使うならLink/Unlinkや RNFUNC_CALL は何もしない実装に置き換えられる。

一見めっちゃ遅そうだが Gaucheのような高速なインタプリタの数倍程度の遅さで済んでいる 。テストの制御とかゲームのスクリプティングならこれくらいで十分なのでちゃんと整理してライブラリにしたい。

... もっとも、実用するためには read が遅すぎるという致命的な問題がある。今のS式リーダーはそれ自身をSchemeで書いていて、 普通に処理系を立ち上げるだけで1分くらい掛かる 。せめてtokenizerくらいはネイティブコードで書かないと実用に耐えないかもしれない。手元では中間言語への変換に他のScheme処理系を使うというインチキをしている。

このようなインチキが可能なのはRibbonのランタイム -- 標準ライブラリや中間言語コンパイラ -- は自前のScheme移植ライブラリであるyuni https://github.com/okuoku/yuni/ で書かれているため。yuniは現状メンテナンスされているScheme処理系の大半で動くので適当な処理系さえ用意できれば簡単に無からbootstrapできる。大抵のScheme処理系では、bootstrapのために使える他所の処理系は0つ〜1つが標準的なので、この辺りもRibbonのユニークな特徴と言える気がする。

RibbonはRibbit同様ヒープに "Rib" と呼ばれる3つ組のセルを使用していることを特徴とする。Lispで伝統的な2つ組のセルである cons セルに比べて分岐のような構造をより簡単に記述でき、中間言語をconsセルで表現するよりもシンプルにできる(この辺はRibbitの元論文 http://www.iro.umontreal.ca/~feeley/papers/YvonFeeleyVMIL21.pdf に詳しい)。よって、Ribで始まる単語を名称に選んでいる。

ビルドトレース

ビルドトレースはめっちゃコストも時間も掛けてるのに全然成果が無い。。これはソフトウェアをソースコードからバイナリに変換するにあたっての 変換グラフを抽出する 技術で、要するに

  1. ビルド時のコマンドライン・環境変数の抽出
  2. コンパイラやリンカ、各種ツールのコマンドラインから入出力ファイルの抽出

を行うためのインフラを整備し、抽出されたグラフを活用する事業と言える。

世間にはBuild server protocol https://build-server-protocol.github.io/ とか compile_commands.json のように、ソースコードに与えられたパラメタを扱うプロトコルは多く存在するものの、ソースからバイナリまでを一気通貫で扱うものは少く、まだまだ研究が必要な分野となっている。

これとにかく金掛かるので営業上は流行りものにアラインさせておく必要があって、今年取り組んだのは 逆コンパイラのトレーニング 、つまり、 C → (コンパイラ) → LLVM-IR → マシン語 → (逆コンパイラ) → LLVM-IR として前後のLLVM-IRを比較することで逆コンパイラの性能評価をできないか考えていた。ビルドトレースをビルドシステムに組込むことで、巾広いプロジェクトで評価データを収集できるようになる。ただ、そもそもLLVM-IRが出てくる逆コンパイラが市場にあまり良いものがなく、成果が無かった。もうちょっと良い中間ステップを考えないといけない。

実はWasmLinuxはこの枠で始めたもので、例えば、ツールチェーンを一旦CMakeのスクリプトでwrapしていたりといったビルドトレースを想定した仕込みが最初から入っている。マシン語の代わりにWebAssemblyを使うことで逆コンパイラ側の実装難易度を下げられるのではないだろうか。

WasmLinux

Busyboxで ls できる程度にはユーザーランド側の実装も進んでいる。つまり、Musl libcが移植できていて、Cで書かれたLinuxアプリをコンパイルして動かせる段階になっている。

が、 ifconfig -a するとカーネルパニックするとかまだまだバグがあり解決できていない。

まぁBusyboxを動かすというところまでは達成できたので、最終的にはESP-IDFのようなマイコン開発環境を動かすところを狙っていきたい。 ...もっともESP-IDFはPythonとかが動かないといけないのでかなりハードルが高い。

先の記事で書いたように、WasmLinux自体にはあまり大きな価値は無く、実用上は既存のCPUをエミュレーションした方が良い。それでもWasmLinuxを追求するのは、WebAssemblyで 普通の アプリケーションを動かすとどうなるかを精度よく見積るためと言える。WASIにせよ何にせよ、既存のWebAssembly上のアプリケーションフレームワークはC/C++プログラムに何らかの移植を強いているが、WasmLinuxは可能な限りアプリをそのまま動かしたらどうなるのかを観察できる。

直近の開発で大きな目標は:

  1. ブラウザ等wasm2c以外の処理系をサポートする 。いわゆるセルフホストを実現するためには適当なWebAssemblyインタプリタをサポートする必要がある。が、現状のWasmLinuxはwasm2cにかなりべったりな実装になっているので、切り出し方が難しい。特に setjmp / longjmp のためにWasmモジュールを変換してやる必要があるので、それをどうやって実現するかが問題になる。 -- 今後記事にする予定だけど、現状のWasmLinuxは setjmp / longjmp をかなり不正なテクニックで実装していて、更に vforkexecve のフローも setjmp / longjmp で再現している。
  2. 外部とのやりとりのサポート 。既にUSB/IPを組み込んでいるので、適当なUSB/IPホストと組み合わせることで特に問題なく外部と繋るんではないかと思っている。面倒だけど。LKLでUSB/IPが使えることは4年前に実験してある
  3. 動的ライブラリのサポート 。いわゆるダイナミックリンカを完全に自前で実装する必要がありちょっとお辛いものがある。今のところ、Windowsのようなインポートライブラリを生成する方式を考えている。
  4. C++のサポート 。例えばコンストラクタの呼出しとかTLSをサポートする必要があり、ユーザランドのリンク周りにも工夫が必要になる。

一応、 プロなのでどれもやればできるんだけどやる時間を捻出するのが難しい。。

Bluetooth LE 活用おもちゃ

Bluetooth LE(BLE)はAndroidやiOSのデバイスには必ず備わっているので、おもちゃの通信機能として活用できる可能性がある。というわけで今年もBLE通信しながらそこそこ歩いた[1]

https://twitter.com/priokuoku/status/1740287618129219668

(今年は遂に 徒歩で千葉県一周を達成 した)

で、歩いた結論としては 乾電池駆動でBLE常時接続という企画は厳しい 感じ。iOSにせよAndroidにせよ、省電力との兼ね合いからか接続の受け入れが渋く "何となく上手くいかない[2]" ケースがあまりにも多い。

BLE自体には可能性は有ると思うんだけど、市場の採用状況もなかなか渋い。例えば、たまごっちの新作であるたまごっちUni https://tamagotchi-official.com/jp/series/uni/実績のある中華マイコンのESP32を採用 してWi-Fiによる 単体 インターネット通信を実装している。実は過去にたまごっち みーつ https://tamagotch.channel.or.jp/tamagotchi/ としてBLEによる通信を電話を母艦とする形で実現していたものの、様々な事情で諦めたようだ。(もっとも、このBLE通信は過去作(4U)のNFCや赤外線通信等を代替する程度の機能性で、UniのようにWi-Fi経由のファームウェアアップデートを行うようなことは無かった)

しかし、Wi-FiとBLEでは消費電力が1桁違い、セットアップの面でもBLEの方が安全性が高い(Wi-Fi単体通信ではアクセスポイントの認証情報をおもちゃ側に持たせる必要がある)ので、できればBLEにこだわりたい。。

というわけで、 技術的な制約は全て企画に押しつける 形で企画を整理した。

https://twitter.com/dotmjt/status/1740851727262535947

  • 互換性: おもちゃには 歩数計、コンパス のセンサおよび画面、BLE通信機能がある。これらは電話にも付いているので 実は、おもちゃが無くても電話のアプリで全く同じ遊び[3]ができる
  • 共有: おもちゃは 友達や家族と貸し借り/交換して遊ぶ 。ただし、物理的に貸し借りしなくてもアプリ内でやりとりできる(が、アプリ間はBLEで通信させる等近接を保証させる方が面白いかもしれない)
  • 習慣: 毎週で 合計N分以上、おもちゃの近くでアプリを開いてもらう 仕組みを用意する -- アプリがforegroundな状況下でのBLE通信にはほぼ制約が無いため、このタイミングでファームウェアアップデート等の大容量通信を行う

モノの貸し借りには割と本質的な面白さがあると思っていて、それを直感的に実現する方法が物理的なおもちゃなのではないかと考えている。BluetoothはPAN(Personal Area Network)として半径数メートル程度の距離しか通信できないのを逆手に取り、おもちゃを保持している人を近くにある電話で識別できる。そうする事で、貸し借りにUIが不要 -- 物理デバイスの手渡しがUIとして機能する -- という状況にできる。

ゲームとしての内容がなかなか難しい。おもちゃの中に妖精が住んでいて、一緒に出掛けたりするとそれが記録に残って ...的な物が良いとは思うんだけど中々面白くできない。貸し借りが前提に組込まれている点は新しいが、それをゲーム的に面白いメカニクスに纏めきれていない。

たまごっちをスマホアプリで済ませないことには一定の目的がある ように思う。つまり、たまごっちが偉大なのは、育成ゲームというフレームワークが独立したウェアラブルデバイスに最適であるということを見出した点に有るんだろう。同様に、スマホアプリで実現できないことを考えに考え抜いて何か形にできないもんかなと。。

ブラウザP2P

今年は、ローカルデバイスがTCPポートを公開できればブラウザとsecure context内でやりとりできることを実証した。

https://zenn.dev/okuoku/articles/978347df73117f

まぁ現実のユースケースでは外部のシグナリングサーバーを使うケースが多いとは思うけど、ローカルデバイスの制御とかに使えそうなのは大きい気がしている。たとえば、ウチにあるCanonのインクジェットプリンタだと、 SSL通信のためにはユーザーにルート証明書をインストールさせるというとんでもねぇ実装 になっており、WebRTCを使ったP2Pではこれを避けられる(数字の比較とかの代替セキュリティ手順を実装できる)と考えられる。

↓ プリンタのWebUIがこういう表記になっている:

(もっとも、記事でも挙げたように大企業が提供するWebUIだったら Plexのようにユーザー自宅内のIPアドレスを返却するDNSを用意し、その名前に対するワイルドカード証明書を発行する 方が安全だろう)

手元のプロジェクトで言うと、 WasmLinuxをブラウザ上で動かしたとして、そこで面白いことをするにはローカルのネットワークやデバイスと繋る必要がある ので、その部分のブリッジにこの技術を採用したい。つまり、WasmLinuxカーネルは適当なHTTPSサイトにホスティングしつつ、ローカルで動かしたNode.jsスクリプトと直接話してローカルデバイスを制御してもらう。スクリプトの安全性は。。 npm に公開鍵ごと投稿するみたいな方式で何とか。。

来年

来年はもう本業の方がバカ忙しいのが確定しているので、新しいことに手を出すよりは手元のネタを進捗させることに集中した方が良いかなと。。

というわけで来年は滑空というか安定飛行の年にしたいところ。

脚注
  1. この辺はZennの記事にしていない。これは主にリーガルレビューの都合で、来年以降は体制を変えてこの辺の企画検討も記事にしたい。 ↩︎

  2. 例えばAndroidで多くのスマートロックアプリが電源管理からの除外を要求しているように、Androidは外部要求による接続をあまり積極的に扱わない。スマートロックはユーザーの年齢層が高いからどうでも良いけど、おもちゃで追加設定が必要な仕様は厳しいものがある。 ↩︎

  3. 物理的なおもちゃの特典は何らか用意しても良いかもしれないが、とにかく遊び自体には必須ではないようにする。 プレイ人口を稼ぐ必要があるため、アプリ自体を広告として作用させる 必要がある。 ↩︎

Discussion