3

サンドボックス プロセスで安全でないネイティブ コードを実行する必要があり、プロセス切り替えのボトルネックを減らす必要があります。両方のプロセス (コントローラとサンドボックス) は、2 つの自動リセットイベントと、通信に使用されるマップされたファイル (共有メモリ) の一貫したビューを共有します。

この記事を小さくするために、サンプル コードから初期化を削除しましたが、イベントはコントローラーによって作成され、DuplicateHandle を使用して複製され、作業前にサンドボックス プロセスに送信されます。

コントローラ ソース:

void inSandbox(HANDLE hNewRequest, HANDLE hAnswer, volatile int *shared) {
  int before = *shared;
  for (int i = 0; i < 100000; ++i) {
    // Notify sandbox of a new request and wait for answer.
    SignalObjectAndWait(hNewRequest, hAnswer, INFINITE, FALSE);
  }
  assert(*shared == before + 100000);
}

void inProcess(volatile int *shared) {
  int before = *shared;
  for (int i = 0; i < 100000; ++i) {
    newRequest(shared);
  }
  assert(*shared == before + 100000);
}

void newRequest(volatile int *shared) {
  // In this test, the request only increments an int.
  (*shared)++;
}

サンドボックス ソース:

void sandboxLoop(HANDLE hNewRequest, HANDLE hAnswer, volatile int *shared) {
  // Wait for the first request from controller.
  assert(WaitForSingleObject(hNewRequest, INFINITE) == WAIT_OBJECT_0);
  for(;;) {
    // Perform request.
    newRequest(shared);
    // Notify controller and wait for next request.
    SignalObjectAndWait(hAnswer, hNewRequest, INFINITE, FALSE);
  }
}

void newRequest(volatile int *shared) {
  // In this test, the request only increments an int.
  (*shared)++;
}

測定:

  • inSandbox()- 550 ミリ秒、~35 万のコンテキスト スイッチ、42% の CPU (25% のカーネル、17% のユーザー)。
  • inProcess()- 20ms、~2k コンテキストスイッチ、55% CPU (2% カーネル、53% ユーザー)。

マシンは Windows 7 Pro、Core 2 Duo P9700、メモリ 8 GB です。

興味深い事実は、サンドボックス ソリューションが CPU の 42% を使用するのに対し、インプロセス ソリューションの 55% を使用することです。もう 1 つの注目すべき事実は、サンドボックス ソリューションに 35 万のコンテキスト スイッチが含まれていることです。これは、ソース コードから推測できる 20 万のコンテキスト スイッチよりもはるかに多い数です。

別のプロセスへの転送制御のオーバーヘッドを削減する方法があるかどうかを知る必要があります。私はすでにイベントの代わりにパイプを使用しようとしましたが、それははるかに悪いものでした. また、リクエストごとに サンドボックス呼び出しSuspendThread(GetCurrentThread())とコントローラー呼び出しを行うことで、イベントをまったく使用しないようにしましたが、パフォーマンスはイベントを使用した場合と同様でした。ResumeThread(hSandboxThread)

アセンブリ (手動のコンテキスト スイッチの実行など) または Windows Driver Kit を使用するソリューションがある場合は、私にもお知らせください。これを高速化するためにドライバーをインストールする必要はありません。

Google Native Client も同様のことをしていると聞きましたが、このドキュメントしか見つかりませんでした。さらに詳しい情報をお持ちの場合は、お知らせください。

4

1 に答える 1

4

最初に試すことは、待機中のスレッドの優先度を上げることです。これにより、無関係なコンテキストスイッチの数を減らすことができます。

または、2コアシステムを使用しているため、イベントの代わりにスピンロックを使用すると、システムパフォーマンスと消費電力を犠牲にして、コードがはるかに高速になります。

void inSandbox(volatile int *lock, volatile int *shared) 
{
  int i, before = *shared;
  for (i = 0; i < 100000; ++i) {
    *lock = 1;
    while (*lock != 0) { }
  }
  assert(*shared == before + 100000);
}

void newRequest(volatile int *shared) {
  // In this test, the request only increments an int.
  (*shared)++;
}

void sandboxLoop(volatile int *lock, volatile int * shared)
{
  for(;;) {
    while (*lock != 1) { }
    newRequest(shared);
    *lock = 0;
  }
}

このシナリオでは、CPU時間に関してビジースレッドと競合しないように、スレッドアフィニティマスクを設定するか、回転するスレッドの優先度を下げる必要があります。

理想的には、ハイブリッドアプローチを使用します。一方の側がしばらくビジー状態になる場合は、もう一方の側にイベントを待機させて、他のプロセスがCPU時間を取得できるようにします。少し前にイベントをトリガーして(スピンロックを使用して同期を維持する)、他のスレッドの準備ができているようにすることができます。

于 2012-07-09T00:16:33.053 に答える