#isucon #isucon10 予選参加記: 決勝行けましたの巻

最終スコア 2335 で本戦出場です。スコアそのものは不完全燃焼感が否めないけどクッソ嬉しい。

isucon.net

github.com

レポジトリはこれ。チーム名は「ヌルポインターマリアユニバース」*1、メンバーは漏れと id:wtatsuru id:Pasta-K。やったことはこの repo みてくれ (master ブランチの内容がスコアのあれです)

チームメンバーのエントリはこれら:

wtatsuru.hatenadiary.com


ビール2L飲んだけど記憶が生きてるうちの個人的反省箇条書き:

  • なぞって検索のN+1を完全に2クエリ (O(1)) にできたのはよかった
  • 17時くらいに疲れてすこしダレてしまった
    • 疲れたのはしゃあない
  • 全体的にログや fixture のデータ数を眺めた上での優先度判断ができた (俺が) のはよかった
    • LIKE 検索してるやつそんなないっすねという話
    • 初期データ 30000 件もないっすねという話
  • MySQL の設定素朴すぎるのに気づけたのは良かった
    • クエリキャッシュ有効化できた
      • id:wtatsuru さんにスレーブ立てたりしてもらったけど、スレーブでクエリキャッシュ有効化や InnoDB buffer pool 拡大してなくないすか?? っていうのに終了 30 分前くらいに気づけたのもよかった
        • この気づきで 100 点以上稼いでいる
  • 反省点
    • 椅子・物件の CSV インポートのバルクインサート結局できなかった
      • sqlx 仕事でも使ってるはずなのにエラーメッセージから真意を読み解けなくて時間切れだった、異常な悲しさがある
      • 異常な悲しさはあるんだけど、最終的にこれのスコアへの影響はしょぼかったのではという雰囲気もあって結果オーライ感はある……
        • 5 秒のタイムアウトをぶっちぎってしまうとスコアゼロ、確率的に? ぶっちぎってしまいますね、というところで、結局ぶっちぎらなかったっぽい
  • 作業タイムの 15 分スプリント、そこそこ機能した気がするけど途中でダレてしまった
    • 自分が根詰まると根詰まってしまう (はい)
  • id:wtatsuru さんに下回り的なタスクはだいたい丸投げできることは最初から自明だった *2 と思うけど、まあ実際そこに乗っかることでワークした面はあったと思う
    • お前が MySQL のレプリ組めや!! ってなっていたとしたら MySQL レプリケーション やり方 でググるところからスタートだったと思う……
    • 継続的に会話できたことで、やればどう考えてもスコアが上がる (けどその実装をシュッとやるには手慣れが必要) 担当 (id:wtatsuru) + 飛び道具で優勝狙い担当 (漏れ + id:Pasta-K)、をちゃんと配分しつつやっていけたのはよかった
  • ログをぼーっと眺めて傾向をエスパーするテクニックは役に立った
    • features で LIKE が発生してるのは気になるけど、そんなにリクエストされてないので後回しでよくないですか、みたいな

いろいろ話題はあるけどパッと思い出せるのはこれくらいです、随時追記はしそう

*1:サークル名ジェネレータ http://www.doujinbu.com/cng/ を適当に回していて、ヌルポインター、しかもマリア (→ MariaDB への連想) というポイントで即決

*2:なぜならプロだから

最近よく見る 1000 円くらいの HDMI キャプチャーカードについてのメモ

今北産業

  • HDMI キャプチャーボード的なやつって最低でも 1 万円くらいはするよね、みたいな常識を破壊された。個人的には完全にお値段以上
  • ある程度制限や難はあるものの、それを受け入れられるなら驚くほど普通に使えてしまっている
    • 音声入力の挙動に難があるのが一番大きそう

このあたりの話題。

pc.watch.impress.co.jp

note.com

似たようなのを 2 台 AliExpress で買って持っている。似たようなのというだけであって、サウンドハウスのそれや Amazon で売られてる似たような商品に以下の話題が当てはまるとは限らないし、この note のエントリで言及されているデバイスについても然り、という感じです。値段がほとんど一緒でスペックがめっちゃ近いように見える、という事実だけがある。以下は自分の手元に届いた物体についての感想。

文脈

これっぽいやつ AliExpress で送料込み 1000 円くらいやん!!!ということに数ヶ月前に気づいていたけど、いまやサウンドハウスで同じくらいの価格で買えるようになってしまった*1。自分が持っているものとはおそらくガワだけが違って、もっとも重要な部分を司るチップは同じものを使っているはず、たぶん……。このころは ATEM mini やその他ちゃんとした HDMI キャプチャーボードの在庫が本当に全部尽きていたこともあり、これを見つけたときにはめちゃくちゃ驚いた記憶がある。

で、届いてからたまに使っている。Splatoon をやるときにプレイ動画を YouTube Live に限定公開で配信して、あとから反省会をするのに使うとか、身内でリーグマッチ (フレンドといっしょにバトルするやつ) をやるときに思い出コンテンツとして残して共有しているとか、広角のアクションカメラをつないでオンライン飲み会の Web カメラ代わりにしてみる、という程度だけど、HDMI キャプチャとしては普通に全力で活用できているといえるのではないか。

数ヶ月 OBS などから触っている限り、だいたいこういう感じである:

映像

  • 1080p30 / 720p60 が限界
    • 1080p60 はできない
  • 画質はそんな悪くないと思う (個人の感想)。1000 円という価格を考えると全く文句はない
    • 720p60 で Splatoon みたいに動きが激しいゲームの動画をキャプチャしても、めちゃくちゃになるということはなく、普通に視聴できるレベルだと思う
      • 言われてみるとたしかに画質良いわけではないっすね、くらいの感じなのではないか???
    • ナイスカメラをつないで Zoom などの Web カメラ代わりにします!!!みたいなユースケースだと、ビデオ通話的なアレの動画ビットレートはそれなりに絞られてるわけなので、このキャプチャーボードが画質のボトルネックになることはなかなかないだろうと思う
  • 一眼カメラなりを繋ぐときは 60fps で録画する設定に切り替えないと認識されないということがあった
    • 具体的にはオリンパスの OM-D E-M5 Mark III でこの現象に遭遇した。上でアクションカメラと書いたのはソニーHDR-AS300 だけど、これはどの記録モードであろうと映像が認識できた。何が違うのかよくわからん
  • macOS + Zoom だと「HDを有効にする」設定をオンにしないとアスペクト比がおかしくなることがある気がする
    • (4:3 に縮められてしまう)
    • これも何が悪いのかはよくわかってない
  • 遅延はそれなり
    • 手元だと Splatoon をキャプボ越しにやるのは相当無理がありそう (ラグで酔いそうになる)、というレベル

ラグはデータで示せるなと思ったので適当に測ってみた。

www.youtube.com

これの元動画から適当に一コマ撮ってみたところこういう感じであった。だいたい 100ms 前後くらいのレイテンシがありそう、という感じ。

f:id:polamjag:20200910131711j:plain

こういう感じッス

www.youtube.com

これは 720p60 でキャプチャし、OBS から 1080p60 として YouTube Live に配信したやつのアーカイブ *2。後述するがこのデバイスのオーディオ入力部分は狂ってるので別のデバイスでキャプチャしている。

最初に言及した note のエントリでも、音声が強制的にモノラルになるという話で、実際 WindowsmacOS で使うとそういうふうに見えるし聞こえる。が、これはメインのチップの実装が狂ってるのでそう聞こえている、という話のようである。

USB のデバイス情報を見つつググってみたところ、MacroSilicon という会社の MS2109 というチップが HDMI 信号を UVC に変換するのを司っているようだ。

www.cnx-software.com

f:id:polamjag:20200910020230p:plainf:id:polamjag:20200910020234p:plain
macOS でシュッと見れる範囲のデバイス情報たち

が、そのチップの音声に関する実装がおかしくて、48kHz なステレオを、片方のチャンネルのビットをひっくり返した上で 96kHz モノラルにガッチャンコした形で送ってきていて (???)、USB Audio Class としてのデバイスも 96kHz モノラルであると主張している、という妙ちくりんな感じになっている。Linux にはつい最近 quirk (特別対応) が入っており、最新に近いカーネルであれば正しく 48kHz ステレオ入力として扱えそうな感じ。その他の OS は……まあ……

ホンマかいなという気持ちで、macOS で適当なカメラを繋いだうえで音声だけ 96kHz で録音してみるとこんな感じであった。たしかにどう見てもそういう感じのスペクトログラムになっている (ログスケールになってたりして見にくいけど、24kHz 部分を中心とした線対称のようになっている)。

f:id:polamjag:20200910015919p:plain

ほとんどの動画配信サイトやビデオ通話では、たいてい音声のサンプリングレートの上限はせいぜい 48kHz とかになっているだろうし、エンコードされる際に人間の可聴域に合わせてばっさりローパスフィルタをかけられてしまうことも多いと思うので、実質的な挙動としてはステレオのうち片方のチャンネルだけが使われるモノラルであると言える。左右のチャンネルがミックスダウンされたモノラルではないことに留意する必要はありそう。Linux 以外の環境だと頑張るとステレオの信号がゲットできそう、という世界観。

というわけで、音声入力には難がある。あるのだけど、自分の手元には USB オーディオインターフェイスがいくつか転がっていたのであまり困らなかった…………。Web カメラ代わりにしたいパターンだと、マイクはたいていイヤホンとかについてるやつを使うであろうから意外とあまり困らないのではないかという気もする。ゲーム実況とかをしたいときは頑張ってほしい!!

github.com

GitHubMS2109 で検索してみたところ、Windows 上でこのデバイスのオーディオ入力をキャプチャして、別デバイスに正しいステレオ音声を出力することができそうなユーティリティを作っている人がいた (試してない)。世界は広い。macOS でも Audio Unit のプラグインみたいな形でなら自分でも頑張れば実装できるのではないかという気もする。


閑話休題、IPMI もどきのパーツとして使うとか、普段はディスプレイなしで運用してる自宅サーバのコンソールをちょっとノーパソに表示するのに使う、というのをやっている人たちがいておもしろい。たしかにサーバのコンソール出すのにノートパソコンの画面を使えればどれだけ楽だろうと思ったことはあるけど、これは思いつかなかった……。

akkiesoft.hatenablog.jp


というわけで、トータルではめっちゃ安くていい買い物だった、そして絶妙におかしな挙動で心をくすぐってくるのがむしろ愛おしくすらある、という感じです。2 台買ったのは、別に挙動が怪しかったからとかいうわけではなく、カメラを複数台使うライブ配信とかをこれでやれればおもろいかなと思ったからなんだけど、買って満足してしまっていて良くないですね、こちらからは以上です。

f:id:polamjag:20200910021045j:plain


追記

最近良く見る 1000 円くらいの HDMI キャプチャーカードについてのメモ - polamjaggy

これスマホでも使える。ホストケーブルで接続してUVCアプリ入れると普通にキャプチャー可能。

2020/09/10 20:07
b.hatena.ne.jp

たしかにこういうことをやっている人がいるのを Twitter でも見た気がしていたんですが忘れていました。そのときは iOS + iPadOS どっぷりなので関係ないんだよなと思った気もするけど、よくよく考えると Android スマホも OTP ケーブルも手元にあるやんけという事に気づいたので、Play Store で適当なアプリを入れて試してみたところ、面白くないくらいスッと認識されて普通に使えてしまった。

f:id:polamjag:20200910204431j:plain

*1:コロナ禍に入ってからサウンドハウスで関係ない買い物を一度したけど、深夜に注文確定したのがその日のうちに世田谷区に届いてめっちゃビビった。お急ぎ便か???

*2:映像のエンコードApple VT H264 Hardware Encoder

ffmpeg でオーディオ入力のラウドネスをリアルタイムに計測する

ffmpeg のオーディオフィルタには、EBU R 128 で採用されているアルゴリズム (ITU-R BS.1770) を用いて音声のラウドネスを計測できるものがある*1

これと、ffmpeg のオーディオ入力デバイスからリアルタイムに音声をキャプチャする機能を組み合わせることで、ffmpegコマンドライン上で動くリアルタイムラウドネスモニターとして使うことができる。

ffmpeg で各種入力デバイスから音声や映像を取り出す手段は OS ごとに異なる。macOS だと AVFoundation を用いるものが使えるし、Windows だと DirectShow、Linux であれば ALSA / PulseAudio + V4L あたり、というかんじっぽい。

AVFoundation でキャプチャするには、入力デバイスを番号で指定する必要があるので、狙ったデバイスをどの番号で指定したらよいのか一旦調べる必要がある。-list_devices というオプション付きで以下のようなコマンドを実行するとよい。

% ffmpeg -f avfoundation -list_devices true -i ""
(なんかめっちゃログが出る)
[AVFoundation indev @ 0x7fd68c521040] AVFoundation video devices:
[AVFoundation indev @ 0x7fd68c521040] [0] CamTwist
[AVFoundation indev @ 0x7fd68c521040] [1] Microsoft® LifeCam Studio(TM)
[AVFoundation indev @ 0x7fd68c521040] [2] CamTwist (2VUY)
[AVFoundation indev @ 0x7fd68c521040] [3] FaceTime HD Camera (Built-in)
[AVFoundation indev @ 0x7fd68c521040] [4] Capture screen 0
[AVFoundation indev @ 0x7fd68c521040] [5] Capture screen 1
[AVFoundation indev @ 0x7fd68c521040] AVFoundation audio devices:
[AVFoundation indev @ 0x7fd68c521040] [0] Microsoft® LifeCam Studio(TM)
[AVFoundation indev @ 0x7fd68c521040] [1] BlackHole 16ch
[AVFoundation indev @ 0x7fd68c521040] [2] Built-in Microphone

ここでは Built-in Microphone からの音声を処理してみたいので、2 番を指定したらよさそう、ということがわかる。

というわけで、以下のように実行することで、Built-in Microphone からの音声のラウドネスを計測できる:

% ffmpeg -f avfoundation -i ":2" -filter_complex ebur128 -f null /dev/null
Input #0, avfoundation, from ':2':
  Duration: N/A, start: 164969.992630, bitrate: 2822 kb/s
    Stream #0:0: Audio: pcm_f32le, 44100 Hz, stereo, flt, 2822 kb/s
[Parsed_ebur128_0 @ 0x7fc25912bfc0] Summary:

  Integrated loudness:
    I:         -70.0 LUFS
    Threshold:   0.0 LUFS

  Loudness range:
    LRA:         0.0 LU
    Threshold:   0.0 LUFS
    LRA low:     0.0 LUFS
    LRA high:    0.0 LUFS
Stream mapping:
  Stream #0:0 (pcm_f32le) -> ebur128
  ebur128 -> Stream #0:0 (pcm_s16le)
Press [q] to stop, [?] for help
Output #0, null, to '/dev/null':
  Metadata:
    encoder         : Lavf58.45.100
    Stream #0:0: Audio: pcm_s16le, 48000 Hz, stereo, s16, 1536 kb/s
    Metadata:
      encoder         : Lavc58.91.100 pcm_s16le
[Parsed_ebur128_0 @ 0x7fc25743c940] t: 0.0999792  TARGET:-23 LUFS    M:-120.7 S:-120.7     I: -70.0 LUFS       LRA:   0.0 LU
[Parsed_ebur128_0 @ 0x7fc25743c940] t: 0.211583   TARGET:-23 LUFS    M:-120.7 S:-120.7     I: -70.0 LUFS       LRA:   0.0 LU
[Parsed_ebur128_0 @ 0x7fc25743c940] t: 0.311583   TARGET:-23 LUFS    M:-120.7 S:-120.7     I: -70.0 LUFS       LRA:   0.0 LU
[Parsed_ebur128_0 @ 0x7fc25743c940] t: 0.411583   TARGET:-23 LUFS    M: -25.0 S:-120.7     I: -25.0 LUFS       LRA:   0.0 LU
[Parsed_ebur128_0 @ 0x7fc25743c940] t: 0.511583   TARGET:-23 LUFS    M: -25.2 S:-120.7     I: -25.1 LUFS       LRA:   0.0 LU
[Parsed_ebur128_0 @ 0x7fc25743c940] t: 0.623208   TARGET:-23 LUFS    M: -25.1 S:-120.7     I: -25.1 LUFS       LRA:   0.0 LU
[Parsed_ebur128_0 @ 0x7fc25743c940] t: 0.723208   TARGET:-23 LUFS    M: -24.9 S:-120.7     I: -25.1 LUFS       LRA:   0.0 LU
[Parsed_ebur128_0 @ 0x7fc25743c940] t: 0.834812   TARGET:-23 LUFS    M: -24.9 S:-120.7     I: -25.0 LUFS       LRA:   0.0 LU
^C
size=N/A time=00:00:00.89 bitrate=N/A speed=0.99x
video:0kB audio:161kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
[Parsed_ebur128_0 @ 0x7fc25743c940] Summary:

  Integrated loudness:
    I:         -25.0 LUFS
    Threshold: -35.0 LUFS

  Loudness range:
    LRA:         0.0 LU
    Threshold:   0.0 LUFS
    LRA low:     0.0 LUFS
    LRA high:    0.0 LUFS

-i ":2" の部分がデバイスの指定。-i "[[video]:[audio]]" の形式でデバイスの番号を指定してくれとドキュメントにある。ここでの [] は optional ですよという意味であり、今回は video は必要ないので、単になにも指定しなければ良い。

また、最終的に null output に吐き出すことで、出力先のことを気にせずにフィルタだけ便利に使うことができる。


とはいえ、ふつうにリアルタイムにラウドネスを見たいだけなら Youlean Loudness Meter とかを使うほうが 100 倍くらい手軽だとは思う……。Free バージョンでも、プラグインだけじゃなくてスタンドアロンのアプリがついてくるので便利。

youlean.co

*1:EBU R 128 はラウドネスノーマライゼーションに関する規格で、ITU-R BS.1770 はその中で用いられているラウドネスの測定法である、という理解

何かからの帰りでリニアモーターカーに乗って東京から下り方面に行く、MLX01 みたいなフォルムだけど最前部がオープンカーみたいになっており、友人たちとそこに集結する。横浜までの路線は普通に地上区間で踏切なども存在し、路面電車みたいなノリで公園の中みたいなところを突っ切るゾーンなどが存在しヒヤヒヤする。横浜まで半分くらいのところから浮上走行に入り大盛り上がり、揺れないのでジンバルなしでもブレのない動画が撮れてありがたい。横浜より先まで行く予定だったはずだけど、盛り上がりすぎて横浜駅で途中下車し、横浜駅の探索に入る。横浜駅は激しく増改築が繰り返されており、建築基準法で認められないレベルの階段などが多数存在する。エスカレーターから外を眺めるとそこには赤土の砂漠。馬同士が体当たりで戦っている様子を SIGMA dp2 Quattro で撮影していると、紫色のスポーツカーがめちゃくちゃドリフトしながらフレームインしてくる。馬同士の戦いは両方が息絶える形で終わってしまい、スポーツカーはそのまま近くの幹線道路へと抜けて行く。駅舎に併設されている東急百貨店のリニューアルも行われようとしている最中で、上層階以外がほとんどがらんどうになったビルが駅舎に結合している、という体になっている。来年にはリニューアルが終わるらしいが、今年はオリンピック対策としてがらんどうになったフロアを何かに有効活用しようとしているようで、入国管理局などが存在していた。

1Password でアイテム単位のパーマリンクを共有する方法

今年の 4 月にリリースされているバージョンからこの操作ができるようになっている。今確認してみたところ 1Password X とかでもできそう。

会社で 1Password を使っていて、社内 Wiki とかで「これにログインするときに使う共有アカウントはこちら」みたいな感じで誘導するときに便利だと思う。

Get your items to the right person

Helping your teammates and family members to find items in vaults shared with them is now much easier. When viewing an item tap “Share Link” to share a link with your family members or co-workers. Don’t worry, this sends only a link and does not send sensitive data. The recipient can simply use the link to open 1Password and display the item!

1Password for iOS Release Notes

これを使うには、アイテムの右クリックメニューから 共有 とか Share ってなってるやつを選ぶとよい。どのプラットフォームのアプリでもどこかしらになんか共有できそうなボタンがあると思う……。

f:id:polamjag:20200616234535p:plain

リンクを開くと 1password.com に飛ばされてログイン画面が表示されるけど、deep link 的なアレ *1 で直接ネイティブアプリを開くダイアログが表示されるので、開くよう操作するとそのアイテムがアプリ内で表示される、という動きをする。そのアイテムにアクセスする権限がなければ当然開くことはできない。

f:id:polamjag:20200616234134p:plain

この機能がリリースされたことに気がついてから何度かこういう仕草をしているけど普通に便利だと思う。まあ SSO とかで全部済んでしまうのが理想なのはそうなんだけど……

*1:正確には違うけど

Certbot を使って Let's Encrypt の staging 環境用アカウントの取得だけをやる方法

Certbot を使うと、証明書の発行などは実行せずに、Let's Encrypt など ACME プロトコルに対応しているサービスのアカウントの発行だけする、というのが簡単にできる。証明書の自動更新システムで使いたい練習用のアカウント情報だけを作りたい、というようなときに便利。

Staging Environment - Let's Encrypt - Free SSL/TLS Certificates

やりかた

# certbot がログや設定情報などを書き込む先のディレクトリをでっち上げる
# (特に指定しなかった場合 `/var/` 以下とかに書き込みにいってしまうため)
$ mkdir -p tmp/{config,work,logs}

# certbot register でアカウントを登録する
# このとき `--server` オプションで Let's Encrypt の staging エンドポイントを指定するのがミソ
% certbot register --config-dir tmp/config --work-dir tmp/work --logs-dir tmp/logs  --server https://acme-staging-v02.api.letsencrypt.org/directory

こういう感じで、--server で向き先を変えるのが一番重要。メールアドレスが聞かれたりして登録に成功すると、主に tmp/config 以下にもろもろ必要なブツが生成されていると思う。

GitHub からやってくる通知メールを文脈ごとに Gmail のフィルタでさばく

GitHub からメールでやってくる通知には、通知の種別によって CC: なメールアドレスが設定されている。

GitHub will Cc you if you're subscribed to a conversation. The second Cc email address matches the notification reason. The suffix for these notification reasons is @noreply.github.com.

Configuring notifications - GitHub Help

これを活用して Gmail のフィルタを組み立てることで、コンテキスト別に GitHub の通知を仕分けることができる。自分の場合は、以下のようなフィルタを設定している:

  • (cc:assign@noreply.github.com OR cc:mention@noreply.github.com OR cc:comment@noreply.github.com)
    • アサインされているか、コメントでメンションされたか、自分がコメントを書いたことがある issue/p-r
    • 自分はいろんなところからメンションされまくりはしないので、首をつっこんだやつという感じでまとめている。流量が多いなら assign とそれ以外で分けてもよさそう
  • cc:review_requested@noreply.github.com
    • 自分、もしくは自分が所属する team に対してレビューリクエストが送られた issue/p-r
  • cc:manual@noreply.github.com
    • 明示的に watch した repo/issue/p-r の更新。issue/p-r で Subscribe ボタンをクリックしたやつのアップデートとかもこれに含まれる

GitHub Enterprise Server を使っている場合も、@noreply.github.comgithub.com の部分が、その立ててるサーバーのホスト名になった状態で同じ CC がついている (mention@noreply.githubenterprise.example.com みたいな感じ)。

また、他にもリポジトリを識別するための情報なんかも埋まっているので、組み合わせるといい感じにできると思う。完全に想像だけど、大規模 OSS を追ってたりするとそういうのと組み合わせたりしてもっと細かく制御したくなるのかな〜とか思っている。

以上、勤務先のグループウェアに書いてたやつの焼き直しでした。