MISONLN41's Blog

怪文書置き場

AviUtlでVP9な動画を読み込むと映像が崩れる現象の対策

追記

修正済みのL-SMASH Worksのビルドを配布されている方が居るとTwitterにて教えていただきました。L-SMASH-Works_r1031+libdav1d+libvpx.7z - Google ドライブ よりダウンロードできるみたいです。なので以下に書いてあることは無意味です。

AviUtlの入力プラグインといえばL-SMASH Works。バックエンドにffmpegを用いているのでどんな動画でも読み込める最強のプラグインですよね。

しかし,RePOPn氏がビルド・配布しているL-SMASH Worksには二つ,致命的なバグがあります。それは,VP9動画を読み込むとフレームレートが誤認されることと,映像が崩れることです。今回は,その対策を紹介します。

Steps to reproduce

f:id:MISONLN41:20200316112419p:plain

VP9な動画として,youtube-dlを用いて無劣化ダウンロードした”きららファンタジア”のCMを用意しました。

f:id:MISONLN41:20200316111657p:plain

確かにVP9+Opusになっていますね。フレームレートは23.976fpsです。

早速AviUtlで読み込んでみます。

Actual Result

f:id:MISONLN41:20200316111741p:plain

 

🤔🤔🤔(オタク特有の :thinking: 地獄)

 

映像が完全に崩壊してしまっています。これでは編集どころではありませんね。その上本来23.976fpsの映像が21.445fpsと誤認されています。

How to fix

f:id:MISONLN41:20200316111852p:plain

[ファイル] / [環境設定] / [入力プラグインの設定] / [L-SMASH Worksの設定] から,Preferred Decodersに libvpx-vp9 を追記してやるだけです。

f:id:MISONLN41:20200316115934p:plain

(桃色魔法少女かわいい)

この設定を追記するとVP9動画でも崩れることなく正常に再生できるようになります。

しかしフレームレートの誤認はこの方法では修正できません。

こちらのフォークのコミットでフレームレートの誤認は修正されているのですが,配布されているバイナリはAviSynth等で使うdllファイルのみです。RePOPn氏のビルドは長らく更新されていないし,おそらく今後も修正される見込みはないのかな...と思っています。自前でビルドすることも可能でしょうが,MSYS2やMinGWの環境構築,ffmpegからビルドする必要があるなど,結構面倒そうなのであきらめてしまいました。

フレームレート誤認に対して今すぐできる対策としては,事前にMediaInfo等でフレームレートを確認して,AviUtlで読み込む際にそのフレームレートを指定してやることでしょうか。

気が向いたら自前でビルドして配布しようかと思っています。

上記フォークのL-SMASH Worksのビルドを配布されている方が居るとTwitterにて教えていただきました。L-SMASH-Works_r1031+libdav1d+libvpx.7z - Google ドライブ よりダウンロードできるみたいです。

試してみたら,上記ビルドではlibvpx-vp9の記述を追加しなくても映像が崩壊することもありませんでした。じゃあ何のための記事だこれは。

余談ですが,SisvelがAV1の特許リストを公開したらしいですね。ロイヤリティフリー・パテントフリーを目指していたAOMediaの方針に反する行動でしょうが,果たしてどうなることやら。HEVCのように特許絡みで闇に飲まれないことを祈るばかりです。

今回のエントリは以上です。では,楽しいAviUtlライフを。

 

参考: VP8_and_VP9.webm problems · Issue #79 · VFR-maniac/L-SMASH-Works · GitHub

 

Firefox Fenixはリリースを急ぎ過ぎている。 Firefox 57と同じ轍を踏まないでほしいなと思った。

追記

なんだかんだでロールアウトが始まってしまいましたが、なんだかんだでそれなりに良いブラウザになってきたように思われます。モダンなUIでアドオンが使えて、Fennecと比べてサクサク動くようになったのは素晴らしいものだと感じます。アドオンの数も、ちょこちょこ見られる怪しげな挙動もこれから改善されていくでしょうし(アドオンに関しては誰でも自由に作って公開、ということはできずMozillaからお声がかかったアドオンだけFenixでも使えるようになる、という感じらしいですが...)。とりあえず、今は船出を迎えたFenixを応援しようと思います。

さらに追記

Mozilla Add-ons Blogにて、今後は更にアドオンの対応を拡充していくこと、そして、Firefox Nightlyにおいてaddons.mozilla.org上のアドオンをインストールする(あくまでテスト用)ことを可能にすることが発表されました。

リリースも迫りつつある?Fenixですが、現状にちょっと疑問を抱いたのでかきかき。

まずFenixって何ぞや

FenixはMozillaが開発しているAndroid向けブラウザのコードネームです。現行のFirefox for Android(コードネームFennec)を将来的に置き換えるべく、GitHub上で開発が進められています。おそらくはFenixにリソースを割いているのでしょうが、FennecはVer.68のメジャーリリースを最後に、現在はバグ修正とセキュリティアップデートのみが行われています。

Fenixに関して、長々と説明するよりも体験してもらう方が手っ取り早いでしょう。Androidユーザーの方は、とりあえずインストールして試してみてください。

play.google.com

試せば分かると思いますが、Fenixは現行のFirefox for Androidとは全く異なるUIを採用しています。そしてずっと速いです。体感ですが、現行のFirefox for AndroidChromeと比べて目に見えて遅いのに対してFenixはChromeに匹敵するレベルのスピードでサクサクとブラウジングできます。

その理由は、主にFenixがGeckoViewとAndroid Componentsを用いて再構築されていることにあります。

GeckoView/Android Componentsとは

GeckoViewは、簡単に言ってしまえばWebViewのGecko版のようなものです。WebViewはブラウザを作ることを想定した実装ではなく、最低限のAPIしかサポートしてませんが、一方でGeckoViewは再利用可能なライブラリとしてパッケージされたGeckoエンジンで、Geckoがサポートする機能を全て利用することができます。エンジンをパッケージ化して切り離すことで、複数のプロダクト(例えばFenixやFirefox Focus、Firefox Realityなど)に組み込むことが簡単になり、開発を加速させることができます。レンダリングをGeckoViewに切り離すことでソフトウェアの構造をクリーンにすることができ、GeckoViewを使用しない(Gecko自体は使用しています)Firefox for Androidと比べてパフォーマンスが向上します。また、GeckoViewは完全に自己完結型のライブラリなので、自分でコンパイルする必要もありません。

勿論、ブラウザを構築するためにはレンダリングエンジンの他にも沢山のものが必要になります。Android Componentsは、非効率な車輪の再発明を繰り返すことを防ぐべく、ウェブブラウザを構築するうえで必要なコンポーネント群、例えばURLバーやタブ、オートコンプリートなどをまとめたものです。

つまり、GeckoViewとAndroid Componentsを使うことで、Chromiumをフォークしたり、低機能なWebViewに手を出す手間から解放され、最低限の労力でブラウザを構築することができるようになるのです。

Reference Browserは、GeckoViewとAndroid Componentsを使用したブラウザの例です。名前の通り、リファレンスとして、最低限のブラウザが実装されています。この記事の本題ではありませんが、これを参考に「ぼくのかんがえたさいきょうのブラウザ with GeckoView & Android Components」を作ってみるのもいいでしょう。コンポーネント化されたGecko、是非デスクトップにも欲しいところです...需要がどれだけあるのかは分かりませんが。

本題 Fenixの現状

ここからが本題です。

先述の通りFenixはまだ開発中の段階で、一部のFirefox Previewをインストールしているユーザー以外では、一月後半からFirefox for Android Nightlyユーザーに向けて徐々にロールアウトが開始したという段階のものです。例えば、Firefoxの大きな特徴の一つである拡張機能ですが、現時点で利用可能なものはuBlock Originのみです。また、Mozillaは "おすすめ拡張機能(Recommended Extensions)" に選ばれている拡張機能の対応を優先して行うとし、現時点ではそれ以外の拡張機能のサポートについて、詳細は無いとしています。

もちろん、拡張機能が無いと使い物にならないわけではありません。Fenixは実用的な段階に達しつつあり、実際僕はスマホのメインブラウザをFenixにしています。

Mozillaは今年の上半期中にFennecユーザーをFenixへ移行することを予定しています。しかし、僕は今の状態で(既にFirefox PreviewからFirefox Nightlyへのロールアウトが始まっていることを考えると、今までのFirefox Preview 2.x→3.0のような大きな機能追加がこれからあるとは考えにくいです)Fenixをリリースするのはいささか急ぎ過ぎているように思えてなりません。たとえ「Chromeに並んだ」として、それだけでFenixを選ぶ人が居るでしょうか。敬虔なMozillianやデスクトップ版Firefoxとの同期を重視する人はFenixを選ぶかもしれません。しかし、今まで数々の拡張機能でのカスタマイズを楽しんでいた人たちは拡張機能への対応が不完全なFenixを選ぶでしょうか?そして、ChromeSamsung Internet等、ほかのブラウザのユーザーたちは、それらのブラウザと大して変わり映えしない、若しくは機能面で劣っているFenixにわざわざ乗り換えようと思うでしょうか?答えはノーです。

基本的に、Chrome以外のブラウザは、機能面で何らかの差別化を図ることによってユーザーを惹き付けています。ページの強制ダークテーマ化であったり、ジェスチャー操作であったり、ビルトインの広告ブロックであったり、スピードダイヤル機能などです。リリース時に、Fenixが予定通りにおすすめ拡張機能に対応すればそれは確かに機能面での差別化を図れる上、FenixをFirefoxたらしめるでしょう。しかし、単に拡張機能を動かせるブラウザであれば、Kiwi Browserがあります。それに、ページの強制ダークテーマ化なんかは、ビルトインのものと拡張機能のものとを比べるとその動作の軽さには大きな違いがあります。拡張機能に埋もれて、せっかくGeckoViewによって実現できた速さが犠牲になってしまうのでは元も子もありません。

なにも、Fenixをはじめから全部入りのブラウザにしろと言っているわけではありません。しかし、現状ではあまりにもほかのブラウザとの差別化が出来ていません。繰り返しますが、Chromeと並んだだけで選ばれるわけではないのです。並んだだけであれば、人々はChromeを選ぶでしょう。

Firefox 57も失敗だった?

話は変わりますが、2017年のFirefox 57のリリースを覚えているでしょうか。2倍の高速化、Chromeと同等のスピード、省メモリーを売りに、刷新されたUIとServoの成果物を取り入れたCSSエンジンを搭載し、Quantumの名を冠して颯爽と登場しました。そして、それは減少傾向にあったFirefoxのシェアを取り戻す......には至りませんでした。これに関しては様々な理由(旧式アドオンのサポートを切ったからとか、そもそもそんなに速くないとか)が考えられますが、一つに「Quantumを銘打ったリリースが早すぎた」ことがあるのではないかと思っています。実は、Project Quantumの目玉の一つに「WebRender」というものがありました。これもServoの成果物で、GPUを使ってレンダリングをすることでより高速に描画できるというものです。これを有効にすると、特にCanvasのパフォーマンスなどが著しく向上します。しかし、これはFirefox 57のリリースの時点では不安定だったため有効化されず、バージョンが60番台に入ってから徐々に有効化されていきました。僕は単純な速度至上主義者ではありませんが、高速化を謳った大型アップデートでWebRenderが投入されなかったのは、絶好の機会を取り逃した考えています。Quantumを銘打ったリリースを、あと一年とは言わずとも、半年ほど遅らせて、その間にWebRenderの完成度を高めて、Quantumリリース時には全環境で有効化できるようにするべきではなかったのか、と思ってしまいます。Mozillaとしては、今出さなければもう立ち直る機会はない、という考えに至ってFirefox 57でのQuantumとしてのリリースを行ったのかもしれませんが、少なくとも高速化をアピールするリリースでそのキー機能が一つ抜けていたことは事実です。結果として、速度面でChromeに完全に並ぶことはできず、シェアの減少を食い止めることはできませんでした。僕は、FenixのリリースでもQuantumと同様、急ぎ過ぎてコケてしまうのではないかと、それが不安です。

Firefoxには頑張ってほしい。だからこそ...

それが時としてwebdevの悩みの種になっていることはさておき、僕はWebの最大の特徴はその多様性と相互運用性にあると思っています。MicrosoftがEdgeHTMLを捨てた今、大規模なブラウザベンダーはAppleGoogle、そしてMozillaの3社のみです。Chrome/Chromiumがどんどん存在感を強めている今日、Webの多様性と相互運用性を守るためにも、Mozilla Firefoxは無くてはならない存在です。だからこそ、これ以上にシェアを減らすようなことはしないでほしい。

幸いにも、FenixはGitHubというMozillaにあまり関わりのない開発者でも気軽に参加しやすい環境(例えばデスクトップ版FirefoxはbugzillaというIssue TrackerとMercurialというコード管理システムで開発されていて、そこに参加するのはあまり手軽ではない)で開発が進められています。そして、ページの強制ダークテーマ化など、様々な機能追加についてのissueも上がっており、活発に議論が行われているように見えます。だからこそ、それらがリリース後に実装予定、もしくは実装する予定なしとされてしまうのはとても残念です。特にモバイルにおいて、今のFirefoxは絶体絶命と言ってもいいでしょう。全く新しいブラウザというのは確かに一つのブレイクスルーになるかもしれませんが、それで「Chromeに並ぶ」だけじゃ意味が無いんです(そろそろしつこい)。どうか、Fenixには選ばれる理由のある、差別化されたブラウザになってほしいと思いました。

 

途中から何かいてるのか自分でもわからなくなって、滅茶苦茶なことを言っている気もしますが、とりあえず僕が伝えたかったのは「このまま出しても数ある他のブラウザの互換にしかなれないよ」ということです。今もそうですが、「新しく作り直した」という、宣伝の、いわば切り札を使って出したものが他のブラウザと同じ(または違いが分かりにくい)ものでは本当にモバイル市場でのFirefoxの行く末が危ないかもしれないと思ったので、何かしら差別化して、選ばれる理由のあるブラウザになってほしい。そんなところです。主張に一貫性が無い。

 

参考:

https://www.soeren-hentzschel.at/firefox-android/fenix-firefox-nightly-umstellung/

https://www.soeren-hentzschel.at/firefox-android/die-ersten-bilder-von-mozillas-neuem-fenix-browser/

https://www.soeren-hentzschel.at/firefox-android/fenix-firefox-preview-3-0/

https://www.soeren-hentzschel.at/firefox-android/firefox-68-5-android/

https://github.com/mozilla-mobile/fenix/issues/2139

https://hacks.mozilla.org/2018/09/focus-with-geckoview/

https://hacks.mozilla.org/2019/06/geckoview-in-2019/

https://blog.mozilla.org/futurereleases/2019/06/27/reinventing-firefox-for-android-a-preview/

https://blog.mozilla.org/addons/2020/02/06/ublock-origin-for-firefox-android-nightly/

https://blog.mozilla.org/addons/2019/10/23/fx-preview-geckoview-add-ons-support/

https://blog.mozilla.org/addons/2020/02/11/faq-for-extension-support-in-new-firefox-for-android/

 

なぜDiscordはGoからRustへ移行するのか

DiscordがGoで書かれていたコンポーネントをRustに移行しているらしい。Windowsの低レイヤ層の一部で採用されるなど、近年どんどん注目を集めているRustだが、DiscordはなぜRustを選んだのか。その最大の特徴である「パフォーマンスを妨げる要素であるGCを排した上でメモリセーフな言語」であることにクローズアップした面白い内容だったので、えっちらおっちら和訳してみた。英語が得意というわけでもなく、無理やり翻訳しているところも多いのであしからず。ほとんどGoogle翻訳のままというのは内緒。

追記: 7/31にはてブでいっぱいブックマークされたみたい。気になったブコメへの返信を末尾に追記した。

原文: Why Discord is switching from Go to Rust - Discord Blog


Rustは様々な分野において第一級の言語になりつつあります。Discordでは、Rustはクライアントサイドとサーバーサイドにおいて成功を収めました。例えば、クライアントサイドではGo Live向けの動画エンコードパイプライン、サーバーサイドではElixir NIFsです。最近では、実装をGoからRustに変更することでサービスのパフォーマンスを劇的に改善しました。この記事では、なぜサービスを実装し直すことが理にかなっているのか、それがどのように行われたのか、そしてその結果としてのパフォーマンスの改善について説明します。

Read Statesサービス

Discordは製品中心の会社なので、製品のコンテキスト(利用者の意図や状況、環境などの総体)からスタートします。私たちがGoからRustへ移行したサービスは "Read States" サービスです。Read Statesの目的は、あなたが読んだチャンネルとメッセージを追跡することです。Read Statesは、あなたがDiscordにアクセスするたび、メッセージが送信されるたび、メッセージが読まれるたびにアクセスされます。つまり、Read Statesはホットパス(パフォーマンスがとても重要なパス)にあります。私たちはDiscordを常にきびきびとした状態に保ちたいので、Read Statesを高速にする必要があります。

Goの実装では、Read Statesサービスはプロダクトとしての要件をサポートしていませんでした。それはほとんどの時間において高速でしたが、数分毎にUXに悪影響を及ぼす大きな遅延の急上昇が発生していました。調査ののち、その原因はGoのコア機能であるメモリーモデルとガベージコレクタ (GC) にあると判断しました。

Goがパフォーマンス要件を達成しなかった理由

Goがパフォーマンス要件を達成しなかった理由を明らかにするため、はじめにサービスのデータ構造、スケール、アクセスパターン、アーキテクチャについて説明する必要があります。

Discordにおいて、読み取り状態を保存するために使用するデータ構造は"Read State"と呼ばれています。Discordにはそれぞれのチャンネル、ユーザーごとにRead Statesがあり、合計で数億に及びます。それぞれのRead Stateには不可分的(アトミック)に更新する必要のあるいくつかのカウンターがあり、しばしば0にリセットされます。例えば、カウンターの一つはチャンネル内のメンションの数です。カウンターのアップデートを不可分的かつ素早く行うために、それぞれのRead StatesサーバーにはRead StatesのLeast Recently Used (LRU) キャッシュがあり、そこでは毎秒数十万のキャッシュの更新があります。

データの永続化のために、Cassandra Database Clusterを用いてキャッシュをバックアップします。キャッシュキーを削除する場合、Read Statesをデータベースにコミットします。また、Read Statesがアップデートされているかに関わらず30秒ごとにデータベースへのコミットをスケジュールしています。データベースには一秒あたり数万の書き込みがあります。

下図はGoサービスのピーク時のサンプルフレーム*1です。お気付きのように、遅延とCPU使用率の急上昇が約2分毎に発生しています。

f:id:MISONLN41:20200212021158p:plain

2分毎に遅延とCPU使用率が増える理由

Goでキャッシュキーを削除する際、メモリはすぐには解放されません。

その代わり、ガベージコレクタが頻繁に実行され、参照されていないメモリを見つけて解放しています。つまり、メモリが使用されなくなった直後に解放される代わりにガベージコレクタがメモリが本当に使用されていないかを判断するまで、メモリは少しの間ハングアップします。ガベージコレクションの際、Goは様々な作業を行って空きメモリを判断する必要があり、プログラムの速度が低下する恐れがあります。

Goのソースコードを調べていくと、Goは最低2分毎にガベージコレクションを実行することがわかりました。つまり、ヒープの増加とは関係なく、ガベージコレクションが2分以上実行されなかった際にGoはガベージコレクションを強制的に実行しているのです。

私たちはこの遅延の急上昇を改善するため、ガベージコレクションをより頻繁に実行するべきだと考えました。そして、Goサービスにエンドポイントを実装し、ガベージコレクタのGC Percentを直接変更しました。

残念ながら、GC Percentをどのように変更しても何も変わりませんでした。どうしてでしょう?それは、ガベージコレクタ頻繁に実行するのに十分なメモリを割り当てていなかったからでした。

Goのソースコードを調べ続けると、遅延の急上昇が大きい理由がすぐに開放できるメモリが大量にあることではなく、メモリが本当に参照されていないかを判断するためにガベージコレクタがLRUキャッシュ全体をスキャンする必要があるからだとわかりました。したがって、LRUキャッシュを小さくすればガベージコレクタがスキャンするものも減り、ガベージコレクションが早くなると考えました。そこで、Goサービスに別の設定を追加してLRUキャッシュのサイズを変更し、サーバーごとに多数の分割されたLRUキャッシュを持つようにアーキテクチャを変更しました。

これは成功しました。LRUキャッシュを小さくすると、ガベージコレクションは少ない遅延で実行されるようになりました。

残念ながら、LRUキャッシュを小さくしたトレードオフとして、99パーセンタイルの遅延時間を大きくしてしまいました(つまり、遅延の急上昇は抑えられたものの、普段の遅延が大きくなってしまいました)。キャッシュが小さい場合、ユーザーのRead Stateがキャッシュ内にある可能性が低いからです。ユーザーのRead Stateがキャッシュにない場合は、データベースにアクセスする必要があります。

様々なキャッシュのサイズでテストを行った結果、よさげな設定が見つかりました。100%満足というわけではありませんが、十分に満足できるもので、しばらくの間はその設定でサービスを運用していました。

その間、Discordの他の部分においてRustはますます成功を収めており、新しいサービスをRustで構築するために必要なライブラリとフレームワークを作成することをまとめて決定しました。Read Statesサービスは小規模且つ自己完結型であるため、Rustに移植するのにちょうどいい候補でしたが、同時にRustが遅延の急上昇を解決することも期待していました。そこで、Rustがサービス開発に使える言語であることを証明することと、ユーザー体験を向上させることを期待し、Read StatesをRustに移植する作業を始めました。*2

Rustにおけるメモリ管理

Rustは非常に高速かつメモリ効率が良く、ランタイムやガベージコレクタがないため、パフォーマンスが重要なサービスを強化し、組み込みデバイスで動作し、他の言語と簡単に統合できます 。*3

Rustはガベージコレクタがないので、Goのときのような遅延の急上昇は発生しないと考えました。

Rustはメモリに「所有権」という概念を取り入れた、比較的ユニークなメモリ管理のアプローチを採用しています。基本的に、Rustは誰がメモリを読み書きできるのか追跡します。プログラムがいつメモリを使用しているかを認識し、不要になったらすぐにメモリを解放します。Rustはコンパイル時にメモリルールを適用するため、ランタイムのメモリバグを発生させることは事実上不可能です。*4メモリ管理はコンパイラが自動で処理するため、メモリを手動で追跡する必要はありません。

そのため、Rust版のRead Statesでは、ユーザーのRead StateがLRUキャッシュから削除されると直ぐにメモリが解放されます。Read Stateメモリはガベージコレクタが使用されていないメモリを解放するのを待つ必要がありません。Rustはメモリが使用されなくなったら即座にそれを解放します。解放の是非を判断するランタイムプロセスはありません。

RustのAsync

しかし、Rustのエコシステムには問題があります。このサービスをRustで再実装した時点で、安定版のRustは非同期処理に関して不完全でした。ネットワークサービスにおいて非同期プログラミングは必要なものです。非同期処理を有効にした有志のライブラリがありましたが、大量のおまじないコードが必要なうえ、エラーメッセージはとても分かりにくいものでした。

幸いなことに、Rustチームは非同期プログラミングを簡単にすることについて大変に意欲的であり、RustのNightlyチャンネルでは非同期プログラミングが強化されていました。

Discordは、有望そうな新しい技術を採用することを恐れません。例えば、我々はElixir、React、React Native、Scyllaの早期採用者です。技術の一部が有望であり、我々にメリットをもたらすのであれば、先端技術特有の難しさ、不安定性は小さな問題です。これは、50人未満のエンジニアですぐに2億5,000万人以上のユーザーに到達した方法の1つです。

Rust Nightlyの新しいasyncの機能を採用することは、そういった新しい技術を採用することへの意欲の表れの一つです。エンジニアリングチームとして、Rust Nightlyを採用する価値があると判断し、asyncがRustの安定版で完全にサポートされるまでRust Nightlyを使用することを決定しました。同時に我々はRust Nightlyに発生した問題に対処し、そして安定版Rustは非同期処理をサポートしました。*5我々の挑戦は報われました。

実装、負荷テスト、そしてローンチ

コードの書き直しはとても簡単でした。まずはラフな変換から初めて、それからスリム化が理にかなっている部分においてコードのスリム化を行いました。例えば、Rustはジェネリクスへの広いサポートがある素晴らしい型システムがあるため、Goにおいてジェネリクスが不足していたために必要だったコードを削除できます。また、Rustのメモリモデルは複数スレッドに渡ってメモリ安全性を推論できるため、Goで必要だった手動でのcross-goroutineメモリ保護(おそらく複数スレッドをまたいでメモリ安全性を検証するという意味でのcross)が不要になりました。

負荷テストを開始したら、すぐに満足できる結果が出ました。Rust版Read Statesにおける遅延はGoとほぼ同じで、その上Goのような遅延の急上昇はありませんでした!

驚くべきことに、Rust版を実装したときに、私たちは最適化の際にとても基本的な考え方を導入しただけでした。基本的な最適化だけでも、Rust版は手を加えて最適化したGoのそれよりも優れたパフォーマンスを発揮できました。これは、Goで行う必要のある手の込んだ最適化と比較して、Rustがいかに簡単に効率的なプログラムを作成できるのかを示す大きな証拠です。

しかし、我々はただGoのパフォーマンスに並んだだけでは満足しませんでした。プロファイリングとパフォーマンスの最適化を少し行うと、すべてのパフォーマンス測定基準においてGoのパフォーマンスを超えることが出来ました。遅延、CPU使用率、メモリ使用量の全てにおいてです。

Rustのパフォーマンス最適化のためにしたことは、以下の通りです。

  1. メモリ使用量を最適化するために、LRUキャッシュ内のBTreeMapをHashMapに変更した
  2. 内部のMetrics Library(メトリクスが「測定・評価」らしいので、パフォーマンスを測定するライブラリのことだろうか)を最新のRustの並列化を使用したものに変更した
  3. メモリコピーの回数を減少させた

負荷テストを行っていたため、ローンチはとてもシームレスでした。初めに一つのCanary(Chrome Canaryみたいなものだと思う)ノードに展開し、いくつかのエッジケースを見つけて修正しました。その後、すべての環境に向けてロールアウトしました。

結果を下図に示します。

Goが紫のライン、Rustが青色のラインです。

f:id:MISONLN41:20200212220110p:plain

キャッシュ容量を増やす

サービスが数日の間正常に動いた後、LRUキャッシュのサイズを再び増やすことを決定しました。先述の通り、Go版ではLRUキャッシュの容量を増やすとガベージコレクションにかかる時間が長くなります。Rust版ではガベージコレクションをする必要がなくなったため、キャッシュの上限を引き上げてパフォーマンスをさらに向上させることができると考えました。メモリ上限を引き上げ、メモリ使用量を少なくするためデータ構造を最適化し、800万のRead Statesが格納できるまでにキャッシュ容量引き上げました。

結果は以下の通りです。平均時間はマイクロ秒(μs)で、@mentionが最大の時(メンションが最大限の数貯まっている状態?)がミリ秒(ms)です。

f:id:MISONLN41:20200212222126p:plain

進化するエコシステム

最後に、もう一つのRustの素晴らしい点は、どんどん進化していくエコシステムがあることです。最近、tokio(我々が使用しているasyncランタイム)はバージョン0.2がリリースされました。アップグレードすると、それだけでCPUに恩恵がありました。下図の通り、16日以降のCPU使用率が一貫して低くなっています。

f:id:MISONLN41:20200212224919p:plain

おわりに

現時点で、Discordはソフトウェアスタック全体にわたって、様々な場所でRustを使用しています。ゲーム SDK、Go Liveの映像キャプチャとエンコードElixir NIFs、いくつかのバックエンドサービスなどです。

新しいプロジェクトまたはソフトウェアコンポーネントを開発するとき、我々はRustの使用を検討します。もちろん、Rustを使う意味がある場合にのみ利用します。

パフォーマンスに加えて、Rustを採用することはエンジニアリングチームにとって様々な利点があります。例えば、型の安全性と借用チェッカーにより、製品要件の変更やRustに関する新たな知見が発見された際に、コードのリファクタリングが非常に簡単になります。また、Rustのエコシステムとツールは非常に優れており、その背後にはかなりの勢いがあります。ここまで読み進めたあなたは、おそらくRust(を使う利点)にワクワクしていることでしょう。Rustを専門的に使用し、興味深い問題に取り組みたい場合は、ぜひDiscordで働くことを検討してみてください。

また、面白い事実として、RustチームはDiscordを使用して協調(coordinate。おそらくDiscordを用いて連絡を取り合ったり調整をしたりしているという意)しています。非常に役に立つRustコミュニティのサーバーがあり、我々(Discord開発者)も時々ここで話しています。こちらをクリックしてサーバーに参加できます。


ブコメ・コメントありがとう

こういうの初めてなので、ちょっとびっくりした。自分はプログラミングが出来ないので的確な返しは出来ないと思うけど、気になったものにちょっとずつ言及してみる。

budougumi0617 Go1.12(2019/02リリース)でGCは改善されてるので今はもっとマシです(時間軸的に比較当時も存在していたはずだけれど...😢 https://twitter.com/mattn_jp/status/1226772703413071872

恐らく、Rustへの移行を検討しだした時点でのデータなんじゃないかな。

kwhrtsk GCが無いからといって必ずしもRustの方が安定するわけではない点に注意が必要。例えばデータサイズの小さなKVS/gRPCサーバ実装の例ではRustのレイテンシの方が不安定という結果だった。 https://tech-blog.abeja.asia/entry/2020/04/09/1151

適材適所というのかな、規模や用途によって使い分ける必要は確かにありそう。Dropboxの同期エンジンなんかは、かなり慎重な検討の末にRustへの移行を決めたらしい。

j5ik2o Rustはよい言語なんだけど、この記事では人間側のパフォーマンスやオーバーヘッドがどうなるかが書かれていないってことなんだよな…。

Rustの難しさ、ということだろうか。学習曲線がどうこう、という話はよく聞くけれど、実際のところどうなんだろう?よくわからん。

takaBSD もう前から不思議なんだけど、システムプログラミング言語であるRustとInternet上での使用に最適化されてるGoを比較する人が多いのは何故? RustはCとC++を置き換えるための言語だ!

Rust は C/C++を置き換えるための言語、ではないと思います。それこそWASMとかもありますし、応用先はいくらでもあるんじゃないでしょうか。Goと比較されることが多いのは、確かになんでだろうって感じですね。出てきた時期が近いから?

getcha 面倒くさいから全部 C/C++でいいんじゃないと思っている人です。早いし工夫しようと思えばいろいろできるしCに追いつこうとしなくて良いし。GCは設計上のハンデだから速さ求めちゃ行けないと思う。

絶対に安全なプログラムを書ける、優秀なプログラマーならそれでいいのかなと思う。大半の人間はそこまで賢くないんじゃないかな。プログラミングできないので憶測でしかないけれど。

dowhile “99th” percentileが抜けてるのかな?99パーセンタイルの遅延時間を大きくしてしまった。

den8 "higher 99th latency times" たぶん計測されたレイテンシーを最小 ~ 最大で並べたときの99%部分のレイテンシー時間(いわゆる99 percentile)のことかな?

この記事のコメント欄でも指摘を頂いた。ありがとう。

metatrading dropboxPythonからRustへ移行した意味合いとは異なるね。GoからRustはかなり慎重な意思決定が必要だったように思う。

Malan あわせて読みたい https://navi.dropbox.jp/rewriting-the-heart-of-our-sync-engine

これも前に読んだ。Discordの記事が統計情報とかを中心に書いているのに対して、この記事だと「〇〇がつらい」とか、書き換えの哲学みたいなものが沢山書いてあって面白かった。

*1:グラフはGo 1.9.2のものです。1.8、1.9、1.10も試しましたが改善は見られませんでした。GoからRustへの最初に移植は2019年5月に完了しました。

*2:誤解のないように言うと、我々は全てをRustに移植する必要はないと考えています。

*3:https://www.rust-lang.org/より引用

*4:もちろん、unsafeを使用しない場合に限ります。

*5:https://areweasyncyet.rs/

SVPFlowで赤枠が入る場合の対処法

年末にTS抜き可能なDTV環境を構築できたので、さっそく恋する小惑星 (アステロイド) を録画してみた。せっかくだからフレーム補完もしてみようと思い、SVPFlowを導入、AviSynth経由で動画を読み込んだのだが...

f:id:MISONLN41:20200104201042p:plain

は????

 

いや、なんか赤枠入ってるんですけど。しかもフレーム補完もされてない。

とりあえずSVPflow plugins parameters - SmoothVideo Project (SVP) - frame doubling interpolation を見てみると、

Please note that SVPflow libs require a SVP Manager running (Windows and macOS only), otherwise you'll see a red rectangle around the video frame. (Windows/MacではSVPFlowはSVP Managerが無いと動かないで赤枠が表示されるよ!)

との記述が。SVP ManagerというのはSVPのメインプロダクトで、シェアウェアだ。おそらく僕のようなSVPFlow+AviSynthでフレーム補完する人からも金を得ようという目論見なのだろう。

で、2ちゃ5ちゃんねるを見てみると、

SmoothVideo Project (SVP) part4 [無断転載禁止]©2ch.net

これはSVPFlow 4.3以降の仕様とのこと。4.2.xを使用すれば赤枠は出なくなるらしい。同じレスにWebArchiveのバイナリもあった。

https://web.archive.org/web/20190526051617/http://www.svp-team.com/files/gpl/svpflow-4.2.0.142.zip

こちらのファイルを使用すれば赤枠は出なくなり、ちゃんとフレーム補完もできるようだ。

f:id:MISONLN41:20200104202318p:plain

できた。ちゃんとヌルヌル動くぞ。

おわり。

最近思ったこと、その他(2019年12月13日)

最近モノカキしていないことに気付いた。どんな時でも何かを書き残しておかないと、だんだん自分の存在が薄れて、フワフワしてくる気がする。拙文でも、何か書いておこうと思った。考えがまとまっていないので書き辛い上に読み辛い文章になってしまった。

 

その1

街を歩くと、様々な場所で女性のイラストが描かれたポスターなんかを見かける。イラストに描かれる率として、男女比は圧倒的に女性のほうが高いように感じる。茨城県民な僕が通う学校には、茨ひよりが献血の呼びかけをしているポスターが貼ってあった。それを見て思い起こされるのが、少し前にTwitterで話題に上がっていた宇崎ちゃん献血ポスターの騒動である。あの時問題とされていた「過度に性的」云々の話題、日本のFirefox界隈に詳しい人ならデジャヴを感じるのではないだろうか。詳しくは Latest topics > 絵を消した件 - outsider reflex を参照。この時もまた、どこまでが公の場で許される表現なのかということで意見が対立し、結果的にpiro氏がイラストを削除する事態になった。当時よりはオタク文化のようなものも浸透して、流石に「顔が見切れてるのは性的だ」なんていうなんじゃそりゃー的なものは無くなったと思う。それでも、宇崎ちゃん献血ポスターも、この時の騒動と本質的なところは一緒だよなと思った。本当はもっと詳しく書きたいけど、文章力がないのでうまく表せない。

 

その2

Twitterをすべてだと思ってる人って割と居るよね。トレンドに入ったから日本全土で話題になってると思ってる人とか、なんかの商品がTwitterで批判を浴びまくったことによって発売中止になるとか。確かにTwitterは日本に浸透しているし、世界的に見てもとても大規模なSNSだけれど、どこまで行っても物事を図る尺度の一つに過ぎないんじゃないかな。Twitterであんなことこんなことやってみて、共感を得られました。一緒に行動してくれる人が居ました。素晴らしいことなのかもしれないけど、それはNHKが行う世論調査じゃなくて、あなたがほしい情報を取捨選択して生まれたあなたのTLの上に広がっている世界なんだよと、そう声を大にして言いたい。あとリツイート廃止してくんないかな。

 

その3

2020年冬アニメのPVがぼちぼち出始めている。個人的に一番期待しているのが恋する小惑星なんだけども、他にも面白そうなのがいくつか。やっぱり冬アニメはあたりが多いなと、2016年ぐらいからアニメを見始めたばかりのにわかは思った。

 

その4

それほど悪いことをしていない人が、誤解やら勝手な印象やらで極悪人のように扱われているのを見ると、しかもそれが自分の友人だったりすると、とても悔しい気分になる。そうじゃないです、誤解なんですと言おうとしても聞く耳も持ってもらえず、ただただ無駄な時間が流れていく。自分には何もできないという無力感に苛まれるんだけども、この不条理こそが人間が人生の中で学べる最も大きなものなのかもしれないとも思った。悔しいけど。

Firefox 69でuserChrome.cssやuserContent.cssがデフォルトで反映されなくなった話と解決法

結論から言う。使いたいなら toolkit.legacyUserProfileCustomizations.stylesheets を true にしろ。

What will happen

Firefox は userChrome.css や userContent.css というファイルを使うことによってブラウザの外見を細かくカスタマイズすることができる。しかし、これが Firefox 69 (現在の Stable Release の最新版は68.xなので、Beta を使用すれば69.xを試すことができる) ではデフォルトで無効化されるらしい。

Reason

1541233 - Stop loading userContent.css or userChrome.css by default unless a preference is set

上記の Bugzilla に詳細が書いてあるが、今の状態では Firefox のマスタープロセスが起動するたびに、それが存在しているかに関わらず userChrome.css や userContent.css を読みに行っているらしい(私の英語力はゼロなので間違っているかもしれない)。でもそれは普通のユーザーは使わない機能だから、高速化のためにデフォルトでは無効にしようということらしい。

「以前のバージョンでは使えていた機能が新バージョンでは使えなくなった」時の原因の調べ方 - Qiita

余談だが、上記のように Firefox のインストール先の特定の場所に ico ファイルを置くとウィンドウのアイコンがそれに置き換わるというおちゃめ機能があったのだが、それも同様の理由で削除されているそう。

bugの内容を読むと、どうやら起動処理の高速化の一環として、「まず存在しないファイルを探しに行く」のではなく「明示的にアイコンが指定されている時だけファイルを探しに行く」という方針に改める変更が行われ、その一環として前述の機能が削除されたという事のようです。

真っ当で正しい判断だろう。こんな機能を使うのはそれなりのパワーユーザー (ツリー型タブを使っているとか) だろうし、今のPhotonデザインはそこまでして変えたいほど古臭くない。そもそも設定を変えれば使えるのだから、文句を言うこともないだろう。こういう地味なところで高速化を加えていくというのはWebRenderのような大きなものと並行して進めていくべきだと思う。

How to enable

先述の bug によれば、 userChrome.css や userContent.css を再び使えるようにするには、おなじみ about:config から toolkit.legacyUserProfileCustomizations.stylesheets を true にしてやればいいようだ。

情報元:

PSA: Firefox v69 users will have to set a pref to enable userChrome.css and userContent.css : FirefoxCSS.