Slide 1

Slide 1 text

他言語がメインの場合のRustの活用法 csbindgenによるC# x Rust FFI実践事例 Rust.Tokyo 2023 2023-10-21 Yoshifumi Kawai / Cysharp, Inc.

Slide 2

Slide 2 text

About Speaker 河合 宜文 / Kawai Yoshifumi / @neuecc Cysharp, Inc. - CEO/CTO 株式会社Cygamesの子会社として2018年9月設立 C#関連の研究開発/OSS/コンサルティングを行う Microsoft MVP for Developer Technologies(C#) since 2011 CEDEC AWARDS 2022エンジニアリング部門優秀賞 .NETのクラスライブラリ設計 改訂新版 監訳 50以上のOSSライブラリ開発(UniRx, UniTask, MessagePack C#, etc...) C#では世界でもトップレベルのGitHub Star(合計30000+)を獲得

Slide 3

Slide 3 text

普段の開発 C#によるクライアント/サーバーの開発言語統一がもたらす高効率な開発体制 ~プリコネ!グランドマスターズ開発事例~ https://speakerdeck.com/cygames/sabanokai-fa-yan-yu-tong-gamotarasugao-xiao-lu-nakai-fa-ti-zhi-purikone-gurandomasutazukai-fa-shi-li つまり全部C#でやる Web Admin/Debug (C#, ASP.NET, Blazor) Unity(C#, iOS/Android) C# Server(ASP.NET, gRPC, MagicOnion) C# Batch, C# IaC, etc… C# Monorepo

Slide 4

Slide 4 text

普段のOSS https://github.com/Cysharp/ (ほぼ)全てC#......

Slide 5

Slide 5 text

Why Rust

Slide 6

Slide 6 text

原則なんでもC#でやる、が…… ネイティブコードを利用すべき状況がある ・Android NDKなどネイティブAPIしかないものを利用したい ・Cなどで作られているネイティブライブラリを利用したい C++使う? C++は(特にクロスプラットフォームビルドが)厳しい…… あと普通にC++書きたくない(?) Pure C#で移植する? モノによってはあまりにも大変すぎる…… (パフォーマンス面ではC#に満足しているため、それは理由にない) (コード共有などの面も、クライアントもサーバーもWASMも全部C#でやるため普通に共有できている)

Slide 7

Slide 7 text

救いの手、Rust ネイティブコードの選択肢 C++ or Rust まともな標準パッケージマネージャー C++は無 十分な開発環境(rust-analyzer, RustRover) 総合的にはVisual Studio 2022でC++のほうが強力かも 特にRustのデバッガー周りはかなり不満はある cargo buildのクロスプラットフォームコンパイル めっちゃサクッとできる、すごい!!! cc / cmakeクレートによる既存Cライブラリとの連携 ビルドが全てRustで完結できて楽ちんすぎて、すごい!! bindgenによるC->Rust自動生成 めっちゃ安定して生成できて、すごい!!!

Slide 8

Slide 8 text

救いの手、Rust ネイティブコードの選択肢 C++ or Rust まともな標準パッケージマネージャー C++は無 十分な開発環境(rust-analyzer, RustRover) 総合的にはVisual Studio 2022でC++のほうが強力かも 特にRustのデバッガー周りはかなり不満はある cargo buildのクロスプラットフォームコンパイル めっちゃサクッとできる、すごい!!! cc / cmakeクレートによる既存Cライブラリとの連携 ビルドが全てRustで完結できて楽ちんすぎて、すごい!! bindgenによるC->Rust自動生成 めっちゃ安定して生成できて、すごい!!! 総合的にはRustに大満足 言語的に難しいという先入観というか風評があったため 当初かなり躊躇ったのですが、やってみると意外とス ムーズに使えて良かった。C#と似てる部分も多いので (?)C#の人にもお勧め(?) ZigやC# NativeAOTという選択もモノによってはな くはなかったんですが、現在においてRustの完成 度やエコシステムの充実度は群を抜いていた

Slide 9

Slide 9 text

FFI & csbindgen

Slide 10

Slide 10 text

csbindgen Rust to C# https://github.com/Cysharp/csbindgen bindgen(C to Rust), cbindgen(Rust to C)のようにRust to C#(cs) build.rsにコンフィグを書いてコンパイル時 にsynで指定の.rsを解析して.csを生成する 手書きバインディング作成はしんどいけど、生 成系でいいものがなかったので作ってOSS公開

Slide 11

Slide 11 text

C to Rust to C# bindgenが.hからC呼び出 し用の.rs生成 csbindgenが.rsを元にC公 開用の.rsを生成 csbindgenが.rsを元にRust 呼び出し用の.cs生成 ccでCライブラリをRustラ イブラリにリンク

Slide 12

Slide 12 text

Concept of csbindgen ブラックボックスのないバインディング生成 FFI可能なメソッドをRustで定義すると、1:1対応したC#が吐かれる FFI不可能なものを無理やり中間生成で自動対応させたりはしない SWIGなどが複雑な中間コードを生成するのが嫌だった 凝った自動生成する必要はないのでマクロ(proc-macro)は不採用 元コード(rs)は解析のみで弄らずC#生成 FFIの境界面ではRust, C#ともにunsafeなコード Rustなのに安全じゃない! が、それがいい(?) unsafe

Slide 13

Slide 13 text

Concept of csbindgen ブラックボックスのないバインディング生成 FFI可能なメソッドをRustで定義すると、1:1対応したC#が吐かれる FFI不可能なものを無理やり中間生成で自動対応させたりはしない SWIGなどが複雑な中間コードを生成するのが嫌だった 凝った自動生成する必要はないのでマクロ(proc-macro)は不採用 元コード(rs)は解析のみで弄らずC#生成 FFIの境界面ではRust, C#ともにunsafeなコード Rustなのに安全じゃない! が、それがいい(?) 無理やりRustスタイルで安全にFFIできるように ブラックボックスな生成をするよりも、境界を 超えることを表に出して、安全ではないコード を明示的に書かせたほうがむしろRustっぽくな いか……?境界面の唯一の共通言語はC(安全で はない)なのだから。 境界近辺ではメモリもそれぞれC# で確保したメモリ、Rustで確保し たメモリと違うものが飛び交うの でunsafeに留意して慎重にやる クリーンな世界は一歩外側で クリーンな世界は一歩外側で

Slide 14

Slide 14 text

Type Marshalling C# <-> Rust で 1:1 でマッピ ングできるのでかなり自然

Slide 15

Slide 15 text

Case study

Slide 16

Slide 16 text

MagicPhysX 物理エンジンNVIDIA PhysX 5のC#バインディング https://github.com/Cysharp/MagicPhysX ・GUIアプリケーションの3D部分 ・自作ゲームエンジンへの物理エンジン組み込み ・ディープラーニングのためのシミュレーション ・リアルタイム通信におけるサーバーサイド物理 といった用途に使うことを想定して開発 NVIDIAの公開しているPhysX 5(C++)ではなく、EmbarkStudioが公 開しているphysx-rsをビルド元に使って、csbindgenでバインディ ングを生成した EmbarkStudioは、EA DICE でBattlefieldなどで使われ ている内製エンジン Frostbiteを作っていた人達 が独立して立ち上げたスタ ジオで、Rustでゲームエン ジンを開発している!

Slide 17

Slide 17 text

physx-rs C++/Rust is not easy C++のheaderをbindgenに 投げてもうまくいかない cxx/autocxxのような取り 組みもあるけれど…… physx-rsはPhysXに特化して元の C++コードからC APIを公開する コードを自動生成して、それを 通してC++とRustを繋げた An unholy fusion of Rust and C++ in physx-rs (Stockholm Rust Meetup, October 2019) https://www.youtube.com/watch?v=RxtXGeDHu0w 非常に良いセッション でしたので必見 そしてMagicPhysXはその成果に相乗 りして、RustからC#をcsbindgenで 自動生成して繋げた physx-rsがなかったら 実現は難しかった!

Slide 18

Slide 18 text

YetAnotherHttpHandler Unity用のHTTP/2(gRPC)クライアント https://github.com/Cysharp/YetAnotherHttpHandler C#のgRPCはPure C#実装(grpc-dotnet)でサーバー性能も結構良い が、Unityではランタイムが古くクライアントとして動作しない しかしgRPCは使いたい…… そこでhyperとRustlsを使って HTTP/2(gRPC)通信部分をRustで実装 win, osx, linux, android, iOS – x64, arm64 C#のバインディング(csbindgen)と C# APIとしての高レベルAPIを提供 0 50000 100000 150000 200000 250000 300000 350000 gRPC Implementation performance(2CPUs) Requests/sec(higher is better) https://github.com/LesnyRumcajs/grpc_bench/d iscussions/354

Slide 19

Slide 19 text

YetAnotherHttpHandler Unity用のHTTP/2(gRPC)クライアント https://github.com/Cysharp/YetAnotherHttpHandler C#のgRPCはPure C#実装(grpc-dotnet)でサーバー性能も結構良い が、Unityではランタイムが古くクライアントとして動作しない しかしgRPCは使いたい…… そこでhyperとRustlsを使って HTTP/2(gRPC)通信部分をRustで実装 win, osx, linux, android, iOS – x64, arm64 C#のバインディング(csbindgen)と C# APIとしての高レベルAPIを提供 0 50000 100000 150000 200000 250000 300000 350000 gRPC Implementation performance(2CPUs) Requests/sec(higher is better) https://github.com/LesnyRumcajs/grpc_bench/d iscussions/354 大部分をPure C#で書く, TLS部分をOpenSSLなどを使うという案があったが、 「Pure C#で書くのは大変」「OpenSSLなどをクロスプラットフォームビル ドするのが大変」といった問題があった。 RustはPure Rustによる素晴らしいライブラリ郡がある&それらはクロスプ ラットフォームビルドがやりやすい&csbindgenはRustからのコード生成を サポートする、といった形によってRustライブラリのC#利用を可能にした

Slide 20

Slide 20 text

NativeCompressions LZ4 / Zstandardの.NETバインディング (開発が今日までに間に合わなかったのでOSS化はまだ!) ・伸縮が爆速のLZ4 ・バランスよく高性能なZStandard Cライブラリの両者をRustのCC/CMakeでビルドしてcsbindgenを通 してC#から呼び出す 圧縮ライブラリは通常Pure C#実装するし、基本的にパフォーマン スも問題ない、のだけれど…… 特にZStandardは頻繁なバージョンアップのたびに性能が向上してい る。C#移植すると、移植時のコードで固定されてしまい、その後の 性能向上の最適化コードにはついていけない、結果、ネイティブラ イブラリと性能が乖離していってしまう。 最高の性能をC#に持ち込むために ネイティブバインディングを選択。 クロスプラットフォームビルドも Rust経由で随分やりやすくなった。

Slide 21

Slide 21 text

Conclusion

Slide 22

Slide 22 text

C# ❤ Rust C#の可能性をRustで広げ切り開く C, C++, RustのライブラリをC#に持ち込んで実証した RustはC#/* 任意の言語名を入れてください */ を補完してくれる csbindgenはよくできてる 自画自賛!作ってよかった! これのお陰でC#とRustの相性が無限大に! syn crateでRustのSyntax Treeを解析するのはやりやすくて快適 C#的には普段Roslyn(C# Compiler)でC#のSyntax Tree解析してるので…… Rust AnalyzerはRoslynで開発されたRed Green Treeを使っていたりなのでより馴染み深い(?) C# ❤ Rustの世界観を深めるため開発していきます……!

Slide 23

Slide 23 text

No content