Irisを用いた専用サーバのマルチスレッド化について

お世話になっております。

現在、Irisの検証を行っております。そこでIrisを使用して、送信処理(GameNetDriver処理)のマルチスレッド化に取り組んでいます。

マルチスレッドの実現はできました(Iris-Multi-Thread.png)が、サーバがクラッシュする現象が起こっており、それについてご質問させていただきます。

<br/>

・発生している問題

サーバを起動して、クライアントを繋げてしばらく時間が経過した後に専用サーバがクラッシュします。クラッシュした際のログを添付いたします(Iris-Multi-Thread.log)

サーバのログを確認したところ、"SIGSEGV"のエラーが発生しており、その原因がわからない状態です。

またコールバックを確認するとサーバのReceived処理で発生しています。送信処理をマルチスレッドにして、クラッシュが受信処理で発生する原因がわかりません。

サーバがクラッシュする原因は何でしょうか?また、それの解決案についてご教示いただきたいです。

<br/>

・補足情報

通常のIris(マルチスレッド化をしていない状態)で同じクライアント数を接続した際はクラッシュしないことを確認しました。

また、時間経過によって発生(クライアントの接続時などではないようです)しております。

専用サーバのプロセスに割り当てられたメモリ使用率は小さいままです。

<br/>

・追加したソースコード

マルチスレッドをする際に追加したコードを以下に示します。

UNetDriver::TickFlush(float DeltaSeconds)関数

"QUICK_SCOPE_CYCLE_COUNTER(STAT_NetDriver_TickClientConnections)"の下の部分に以下を追加しました。 // Add #if UE_WITH_IRIS if (ReplicationSystem) { SendTasks.Empty(); for (int32 i = 0; i < ClientConnections.Num(); ++i) { SendTasks.Add(UE::Tasks::Launch(TEXT("Iris Multi"), [this, i, DeltaSeconds] { ClientConnections[i]->Tick(DeltaSeconds); })); } // Wait for (const UE::Tasks::FTask& Task : SendTasks) { if (Task.IsValid()) { Task.Wait(FTimespan::FromMilliseconds(500)); } } } elseClientConnectionsごとのTick(送信処理)をコネクションごとにスレッドを作成して、そのすべてが完了するまで待機しています。

このコードを追加した状態でLinux Serverをパッケージ化して、クラウド上で起動しています。

<br/>

よろしくお願いいたします。

単純にご提示いただいたTickFlushのコードを適用するとTick関数の中でアサートが発生するなど、恐らくこの変更以外にも横断的にエンジンに手を加えているのではないかと推察します。エンジンに改造が施されこちらで同じ問題を再現することができないと​適切な回答を用意することは難しいことをご承知ください。

さてクラッシュですが、マルチスレッド化されたことによりリソースへのアクセスの競合が発生していると思われます。

クラウド上にあるプロセスのデバッグは容易なことではなく、Irisのコード自体にはプラットフォーム依存性はないので、まずエディタ上でシンプルなプロジェクトを用いて動作検証を行っていくことをお勧めします。

原因の調査に関しては一般的なプログラミング問題の範疇になると思いますが​問題のシリアライザーのコードは頻繁に呼び出されるため、

FStringNetSerializerBase::CloneDynamicState、FreeDynamicState、Quantizeなどにログを仕込んで対象のメモリをトラックしていくのが良いかと思います。

[mention removed]

検証していただきありがとうございます。

おそらくですが、「UE_NET_VALIDATE_DC_BASELINES」のチェック処理で発生してアサートだと考えています。

ご共有を失念しておりましたが、

Engine\Source\Runtime\Experimental\Iris\Core\Private\Iris\IrisConfigInternal.h

の44行目。

define UE_NET_VALIDATE_DC_BASELINES 1

define UE_NET_VALIDATE_DC_BASELINES 0

に変更して、当該の処理を実行しないようにしておりました。

また、リソースへのアクセス競合の調査手法についてご教授いただければ幸いです。

> また、リソースへのアクセス競合の調査手法についてご教授いただければ幸いです。

エンジンの中にもコードが見つけられると思いますが代表的な方法としては以下のようなものが挙げられると思います​

TryLockを使って重複したリソースアクセスを検出する法​

check(GenerateProcess->GraphEvalCriticalSection.TryLock()); // No ops should be running

アトミック演算を使って検出する方法​

CHECK_CONCURRENT_ACCESS(FPlatformAtomics::InterlockedIncrement(&ConcurrentWriters) == 1); //競合している場合には戻り値が2以上になりアサートが発生する リソースへのアクセス CHECK_CONCURRENT_ACCESS(FPlatformAtomics::InterlockedDecrement(&ConcurrentWriters) == 0);

FPlatformTLS::GetCurrentThreadId()を含めてアクセスに対してログを出力するのも原始的ですが活用できると思います。​

無事に解決いたしました。

ありがとうございます。