引っ越しの手続きを行ったかどうかがわからなくて、メールボックスを検索したけどメールマガジンが多過ぎて埋もれている。マイページを見に行ったら見つからなかったので申し込んでなさそう。
赤ちゃんを抱くときはメニューのインベントリに余裕があると軽くなる、ということを聞く。物を持ったまま判定だと移動速度が落ちるのでそのほうが有利。
DJをやっていました。
さすがに京都からDDJ-400を運搬するのは大変なので、会場にある機材を使わせてもらうことにしました。CDJという機材があって、なんかLANケーブルを使うとパソコンと接続できるらしいぞ?? ぐらいの知識で臨んだところ、初めて触るボタンやツマミが多すぎて何が起こるのか分からずかつてない感じでした。
前日に開催されたIMAP++ #8では本当に初めてCDJを触り、接続方法と音量調整の方法、どこに再生ボタンがあるのか、を音出しのときにレクチャーしてもらったあと、一番手だったのでなめらかに本番が始まってなかなか大変でした。次に流す曲をプレビューするにはどこをどう操作したらいいの? という状態*1でしたが音を途切れさせなかったのでよいということにします。機材に対する解像度が低いのでは??
pastak生誕祭では昨日触ったばっかり、ということでもうちょっとうまくプレイできていたと思います。ツマミを触るよりも身体を揺らしたり腕を振ったりするシーンが多かった印象です。とにかくCDJの操作は勘でやって、オーディエンスを煽るのに注力していました。
テーマはいつも通りの「いいね欄」でお送りしました。今回はわりと緩急ある感じだったのではないかと思います。ちゃんとメタデータを整備したほうがいい気がするけど素材の味ということにします。
感想をピックアップしていきます。
音が凶暴すぎてなにが「かわいい」だよ #pastak生誕祭
— うなすけ (@yu_suke1994) 2022年9月19日
あたまわるわる音楽は身体に良い #pastak生誕祭
— がくふぁ (@gurafa) 2022年9月19日
頭悪いZzzきたな #pastak生誕祭
— そらは (@sora_h) 2022年9月19日
フロントメモリーのRemixにも大喜び #pastak生誕祭
— かるぱねるら (@karupanerura) 2022年9月19日
うたがわさん煽り上手でヤバい #pastak生誕祭
— mzc (@mazco_dx) 2022年9月19日
CDJ初めてです詐欺か?? #pastak生誕祭
— マジカルペンネくん🍝 (@pastak) 2022年9月19日
主役 #pastak生誕祭 pic.twitter.com/AkF7I3tldm
— そらは (@sora_h) 2022年9月19日
痩せた4 #pastak生誕祭
— うなすけ (@yu_suke1994) 2022年9月19日
にゃんこ酒場の公開収録に始まり、終始いい音を聞きながら身体を揺らして、ポストカードのコンプを狙うという謎の空間になっていておもしろかったです。京都でもやってほしいです(そのほうが近いため)。
*1:ボタンを押したらヘッドホンから聞ける音が変わる
RubyKaigi 2022にオフライン参加しました。参加するのは2016年の会*1以来で、これで2回目です。
トークを聞いたときのメモはScrapboxに残していました。
2016年の会に参加したときは全然理解が伴っていなくて、なんだかすごい話が行われていることぐらいは分かるけど……みたいな感じだったのが、もうちょっと噛み砕けるようになっていたと思います。RubyKaigiは、他の参加したことがあるカンファレンスに比べると、言語処理系のディープな話が多いという印象です。最終日のYJITのキーノートはさすがに何度かついて行けなくなったのであとで見返したい……。
mameさんによるTRICKの解説は、どのコードも異常な機能と奇抜な見た目が両立されていて真似できなさすぎる!! と驚嘆するばかりでした。地球を回すコードがリメイクされていて、あのコードベースを改造できるの?? という驚きがありました。
Rubyコミッタが集まって話すトークでは、将来・夢・議論・it
がいいのでは? といったさまざまな話が聞けておもしろかったです。
RubyがWASMで動く、というのが一番インパクトがあったかもしれません。Rubyコードに document.getElementById
みたいなメソッド呼び出しが出てきておもしろい感じがするけどたしかに動いていてすごいです。
最終日の夜にはDJイベントがあり、大きな音を聞いて身体を揺らしたり、インターネットでしか見ていない人と話したりしました。あと、なぜか盆踊りを踊っていました。
完全に完成した#RubyKaigi #ruby_music_mixin pic.twitter.com/jNhySzGrJ9
— yuiseki (@yuiseki_) 2022年9月10日
飲みまくっていたら最後の方の記憶がないけど、3000円払った記録がマネーフォワードに残っていておもしろかったです。帰巣本能が強い気がします。
最終日の夜に、人手があると助かる、ということでネットワーク機器の後片付けに参加していました。ちょっと雑用をやるぐらいかな? と思っていたけど、案外やることがあって、夕方までかかってなんとか箱詰めができました。ねじりっこの切り方を知ることができたのでよかったです。
day 4 #rubykaigiNOC #rubykaigi pic.twitter.com/Slza0O9JoB
— そらは (@sora_h) 2022年9月11日
荷物整理終わった #rubykaigiNOC #rubykaigi pic.twitter.com/j1noLwgUHM
— そらは (@sora_h) 2022年9月11日
当日の連絡用にSlackコネクトでチャンネルに招待してもらったのですが、変なdisplay name*2を使うと目立った感じになってしまうので気をつけてください。
自分は普段Rubyを書いていない*3のですが、Rubyコミュニティの知り合いが周りにいるとか、久しぶりのオフラインカンファレンスなので行きたい、ということで参加していました。改めて、Rubyという言語が愛されているということが強く伝わってきました。どのトークも興味深く、偉業ともいえる高速化を成し遂げていてすごかったです。
会場までのバスが用意されていてなめらかに来場できたり、お弁当があって昼食に困らなかったりして、大変よかったです。地方で開催されるイベントだと交通の便やレストランの様子などが読みづらいので、イベント側で用意してもらえるのは助かります。
楽しい企画や便利グッズなども用意されていて、久しぶりにオフラインカンファレンスを楽しめたような気がします。運営の皆様、スポンサー企業の皆様、トークをされた皆様、参加者の皆様ありがとうございました。来年は松本で開催されるようなのでそれも行きたいですね。
最終スコアは167,491点で、7位でした。あともう1手ぐらい打てれば上位入賞できたかもしれません。
今回の本選の問題は、育成型放置ゲーム「ISU CONQUEST」の高速化でした。ブラウザから動作確認するとUnity製のゲームが動いていておもしろかったです。
今回の本選ではサーバーが5台与えられました。
users.id % 3 == 0
用)users.id % 3 == 1
用)users.id % 3 == 2
用)リポジトリはこちらです。
予選のときと同じ分析基盤を使うためにアプリケーションコードを直してまわりました。具体的には context.Context
を引き回すなどです。ひと通り導入できるまで時間がかかってしまっているのは今後の課題ですね。
ここでプロファイラやトレーシングの様子を見ると、明らかにDBがボトルネックになっており、とくに POST /login
や POST /user
が重たすぎる、ということが分かりました。まずはそれらのエンドポイントから改善していくことにしました。
プレゼント付与処理 (Handler.obtainPresent
関数) やログインボーナス受け取り処理 (obtainLoginBonus
関数) でN+1クエリが発行されていたので解消しました。受け取り済かどうかの判定をテーブルからSELECTしてきてあとで使うぐらいなので、ここはサクッとできました。
N+1を解きほぐしたあとはbulk insertするようにしました。INSERTするものがない (スライスの長さが0) ときに NamedExecContext
を呼び出すとエラーになるので気をつけましょう (1敗)。
このあたりで10749点を記録しました。
user_present_all_received_history
テーブルに複合インデックスを貼る (12:05)プレゼント付与時の以下のクエリが重たく、EXPLAINしたらインデックスが足りなかったので足しました。
SELECT * FROM user_present_all_received_history WHERE user_id=? AND present_all_id IN (?)
このあたりで20264点を記録しました。インデックスを足すだけで1万点ぐらい上がってて景気がいいですね。
アイテム付与処理は、付与対象のアイテムの item_type
カラムの値で分岐しつつ、別々のテーブルにクエリを都度発行するという実装になっていました。ここを解きほぐさないと先に進めなさそうでしたが、見るからに手をつけたくない雰囲気をかもし出していました。まあ、手をつけないといけないんですが……。
以下のような作戦でロジックの解きほぐしとクエリの効率化を進めました。
ItemObtainer
struct)元々の関数と同じような返り値を保持するならスライスの順序を保持する必要があるのか? と思いましたが、よく見ると返り値を捨てていたので気にする必要はありませんでした。
このあたりで43862点を記録していました。
interpolateParams=true
を足す (13:50)SQLのプレースホルダ置換を有効にするアレです。スコアが10000点ぐらい上がってウケました。
このあたりで54594点を記録していました。プレースホルダ置換は、ISUCONにおいては常に有効にすることにして初手で入れてしまってもいいのかもしれません。
users.id
ごとにDBを分割する (15:28)MySQLのCPU使用率がずっと高いままだったので、ユーザーデータごとにDBを分割するようにしました。
このあたりで119577点を記録していました。
アプリケーションのCPU使用率も上がりつつあったので、残っていたサーバーにアプリケーションを分割するようにしました。採番ロジックをアプリケーション側に寄せていたので、サーバーの番号をIDに埋め込めるように書き換えました。
このあたりで134670点を記録していました。
users.id
の値を含める (17:23)確率的にベンチマークの最初の整合性チェックが落ちる、という現象に頭を悩まされていました。たまにベンチマークが通るので、最初は気にしていなかったのですが、どんどん顕在するようになって焦ります。採番ロジックのバグや、ベンチマーカーのバグを疑いましたが、どうもそれらは違いそうです。
実は、先述したDB分割のさいにバグを埋め込んでいました。セッションキーを取得するときに、セッションキーを発行した先のユーザー用のDBを見ることができておらず、ベンチマーカーが意図したレスポンスを返せずに整合性チェックに通らなくなっていました。原因になかなか気づけなかったのですが、id:nonylene さんがトレーシングの様子と見比べながら原因を突き止めてくれました。今回のMVPだと思います。
最初は users.id
ではなくセッションキーの頭文字に応じてDBを振り分ければよいかと思いましたが、セッションキーを再発行する処理でうまくいかない (セッションキーを全て無効化できない) ため、発行するセッションキーに users.id
の値を含めてなんとかしました。競技終了が見えてきたタイミングでしたがなんとか修正できたのでよかったです。しかしヒヤヒヤした……。
これ以上破壊的変更を加える余裕はなさそう、ということで分析グッズを無効化したり、echoのアクセスログを止めたりしました。それと並行して、ガチャのマスターデータのキャッシュ実装が途中までできていたので、バグを直しつつ投入して何度かベンチマークを走らせてみましたが (「これ以上破壊的変更を加える余裕はなさそう」とは何だったのか??)、18万点ぐらい出たものの再起動試験に通らないことが分かったので導入を断念しました。
ISUCONは2016年 (ISUCON 6のとき) から毎年参加していて、本選に出るのはこれで4回目でした。それなりに手は打てて、順位表の上から数えるほうが早いぐらいのスコアを残せるようになったのはよかったと思います。アプリケーションコードとトレーシングやプロファイラの出力を見ながら作戦を考えて (考えてもらい)、順に試す、というサイクルがうまく回っているのだと思います。今回は失格/failになったチームが多かったようで、我々もセッションキーの不具合に気づかないままだったら……と思うとヒヤヒヤします。
一方で、上位入賞を狙うにはもうちょっと手数や実装の精密さが足りていなかったとも思いました。とくに今回はDB分割まわりで競技終了ギリギリまで悩むことになるバグを埋め込んでしまったのが悔やまれます。以下はもうちょっと余裕があれば導入できたかもしれない作戦です。
キャッシュ以外は感想戦で試してみているけど、20万点は超えたものの30万点には届かないので更なるブレイクスルーが必要そう……。このあたりは上位入賞チームの作戦を聞いてみたいです。
今回も予選・本選ともにおもしろい題材の問題で、競技に取り組んでいてすごく楽しかったです。運営の皆様ありがとうございました。次こそは優勝したいですね。
……というものを書いたので、どうぞご利用ください。
(() => { const highlight = (element) => { element.querySelectorAll("img").forEach((img) => { // alt属性が指定されていたら緑の線、指定されていないなら赤線で囲まれる img.style.outline = img.getAttribute('alt') !== null ? "1px solid green" : "2px solid red" }) } highlight(document.body) const observer = new MutationObserver((ms) => { ms.forEach((m) => { m.addedNodes.forEach((node) => { if (!(node instanceof HTMLElement)) { return } highlight(node) }) }) }) observer.observe(document.body, { childList: true, subtree: true }) })()
2022/8/24 11:25 追記: 普通のページでは実行した瞬間にハイライトされるほうが明らかに便利なので、そのように修正しました。
MutationObserver
を使っているので、いちどブックマークレットを実行すれば、同じページ内で要素が動的に増えてもハイライトされます。シングルページアプリケーションの動作確認にも使えます。
こういう機能を持ったブラウザ拡張があったらいい気がする。というか既にあるのでは?? 知ってる方がいれば教えてください。
id:nanto_vi さんにCSSを使って検査する方法について教えてもらいました。「alt
属性が指定されていない」という条件であればCSSセレクタで表現できるので、こっちのほうがリーズナブルでよさそうですね。
img[alt] { border: 1px solid green; } img:not([alt]) { border: 2px solid red; }
個人サークルで参加するのは初めてで、なにも持っていないのでひと通り買った。
値段や休憩しているかどうかなどを書くのに便利だと思う。それはそれとしてPOPも作ったほうがよさそう。
ホワイトボードノートを置くのに使う。見本誌も展示したいので2つ買ってもよかったかもしれない。
見本にベタッと貼って目印を付ける用。まあ普段の生活にあっても困らないと思う。
お金をそのまま置くのは気が引けるので買った。持ち運びまくると金庫の中で小銭がグシャグシャになる。
自分自身が顔と名前がなかなか一致しないタイプだし、とくに初対面の人が多くなると思うので、名前が分かったほうがいいと思って買った。買ったけどとくに使ってない。
引っ越しのときにエコバックを捨てたので、大きめのかばんが欲しくなっていた。ちょうどいいので普段づかいにもなりそうなものを探して買った。思ったよりは小さかったけど荷物はなんとか入った。もっと大きくてもよいかもしれない……。
布は東急ハンズで見つけられなかったので、あの布屋というところで買った。サイズ指定とか分からないので面倒だったけど、最初から目的が決まっている布なら話は早い。
感染対策。
表題のような活動をやった。今あるTODOコメントを全部抜き出して、Scrapboxのページに並べた上でコメントしていく。すでに解決しているもの・今のうちに対応を考えておくべきもの・まだ前提が揃っていないもの などいろいろあると思うけど、現状どうなっているのかを眺めて議論できるのがいいと思う。
gitを使っているなら、以下のようなコマンドで簡単にTODOコメントを列挙できる。ファイル名だけでなく行番号も入っているほうが見やすいと思ったので含めてみている。
$ git grep -niE '\btodo\b'
これぐらいのコマンドで眺められるので、ちょっと手があいたときにやってみるとよさそう。fixme
xxx
hack
みたいな語でgrepしても面白いかも?
スペイン語には todo という単語があるので、引っかかった場合はうまく除外してください。ローカライズ文言に含まれていたので手でちまちま除外していた……。