Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

性能改善を目的としたリファクタリングの提案 #1

Merged
merged 3 commits into from
Sep 6, 2019

Conversation

pCYSl5EDgo
Copy link

このPRにはいくつかの要素が含まれています。

  • 性能を低下させる範囲での無駄なアロケーションの撤廃
  • Taskを使用したAsyncの廃止
  • インターフェースの新たな定義
  • C# Job SystemとAsyncReadManagerを利用した非同期APIの新たな定義

各項目について説明します

性能を低下させる範囲での無駄なアロケーションの撤廃

既存の実装ではReadAllBytesでbyte[]を取ってきて、それからJSONをstring化していました。
しかし、このstringに対してJsonUtilityを使用するわけでもなく、IndexOfからSubStringするのはロスが大きいことがわかりました。
IndexOf自体は非常に高速で問題はありません。
しかし、元のJSONがかなり巨大(3万文字相当)だったりしますので、かなり非効率的でした。

このPRではbyte[]をUnsafeUtility.PinGCArrayAndGetDataAddressし、byte*を取得し、それに対して作業することで巨大string生成を避けています。
なお、JsonUtility.FromJson<GltfTextureModel>などの部分ではstringを生成していますが、これはJsonUtilityが信じられないほど高速であったためです。
Utf8Jsonを元にしてほぼゼロアロケーションの実装をしてみたのですが、速度向上を果たせませんでした。

Taskを使用したAsyncの廃止

このライブラリで一番性能的にボトルネックになっているのはImageConverter.LoadImage拡張メソッドです。
これは必ずメインスレッド上で動作させなければなりません。
他は誤差と言えるでしょう。
重いTaskを利用してAsync対応をするのは疑問です。

インターフェースの新規定義

public interface IMetaLoader {
    VRMMetaObject Read();
    Texture2D LoadThumbnail();
}

後述C# Job Systemを利用した非同期ローダーと同期であるMetaLoaderのAPIを揃えるついでにインターフェースを定義しました。

C# Job SystemとAsyncReadManagerを利用したファイルベースの非同期ローディング方法の提案

JobMetaLoaderという構造体を新たに定義しました。
物理ディスク上のファイルから読み込む場合に限り、ReadAllBytesで全byte列を取得せずともよいローダです。
処理の流れとしては
コンストラクタでインスタンス生成時にメタデータの最初の20byteを非同期で読みます。
その後、読み込み終了時に別スレッドでJSONファイルの長さを調べ、JSONファイルを全てUnsaUtility.Mallocで確保した領域に非同期で読み出します。
そして読み出し後にこれも別スレッドでメタデータを解釈します。
Readメソッドを呼ぶとメタデータ解釈後までメインスレッドをブロックします。
Readを呼ぶとその中でサムネイルをLoadImageするのに必要な分量だけ非同期で読み出します。
その後LoadThumbnail()を呼ぶと読み出し終了までメインスレッドがブロックされ、Texture2Dが生成されて戻されます。

各段階についてJobHandleが露出していますので、コルーチンやUniRx、UniTaskなどと組み合わせることで柔軟に非同期処理が行えると思います。

性能改善を目的としたPR
ジッサイハヤイ
@m2wasabi
Copy link
Owner

m2wasabi commented Sep 5, 2019

性能を低下させる範囲での無駄なアロケーションの撤廃

JsonUtilityは速いヨ
LGTM!

Taskを使用したAsyncの廃止

なるほど、実際その通りだと思います。(数字として速くならなかった…)

インターフェースの新規定義

LGTM!

C# Job SystemとAsyncReadManagerを利用したファイルベースの非同期ローディング方法の提案

Androidなどファイルの読み込みで検証の必要がありますね。

LGTM

コードががっつり変わっている & Unsafe を用いているので、実際にビルドして検証します
特にUnsafeを用いて Android向けにビルドして、落ちないかは確認が必須です。

@m2wasabi
Copy link
Owner

m2wasabi commented Sep 5, 2019

Unity Editor 上で走らせてみましたがテクスチャが読み込めないです。
ビルドはまだ試していません。

Copy link
Owner

@m2wasabi m2wasabi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IL2CPP(Windows)と Android実機で正常動作を確認しました。
Good Job!:sparkling_heart:

@m2wasabi m2wasabi merged commit 004ab14 into m2wasabi:master Sep 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants