0

すべての GPU アクティビティ (特に実行中のすべてのスレッド) が確実に停止されるように、いくつかのコードを作成しようとしています。dlclose でモジュールをアンロードするには、これを行う必要があるため、ホストとデバイスの両方ですべてのスレッドが停止していることを確認する必要があります。

CUDA のドキュメントによると、cudaDeviceSynchronize:

デバイスが以前に要求されたすべてのタスクを完了するまでブロックします... cudaDeviceScheduleBlockingSync フラグがこのデバイスに設定されている場合、ホスト スレッドはデバイスがその作業を完了するまでブロックします。

ただし、ブロッキング同期フラグを設定して cudaDeviceSynchronize を呼び出すと、新しいホスト スレッドが生成され、cudaDeviceSynchronize が戻った後も実行されています。これは、私が達成しようとしていることの反対です。

この動作は、サンプル プログラムで示されています。

#include <iostream>

void initialiseDevice()
{
    cudaError result = cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync);

    if (cudaSuccess == result)
            std::cout << "Set device flags." << std::endl;
    else
            std::cout << "Could not set device flags. (" << result << ")"
                    << std::endl;
}

void synchroniseDevice()
{
    cudaError result = cudaDeviceSynchronize();

    if (cudaSuccess == result)
            std::cout << "Device synchronise returned success." << std::endl;
    else
            std::cout << "Device synchronise returned error. (" << result << ")"
                    << std::endl;
}

int main()
{
    initialiseDevice();
    sleep(1);
    synchroniseDevice(); // new thread is spawned here
    sleep(1);            // new thread is still running here!
    return 0;
}

このプログラムを でコンパイルしnvcc -g main.cu、gdb で実行すると、 への呼び出しにより、info threadscudaDeviceSynchronize が返された後に 2 つのスレッドが実行されていることが示されます。

gdb で実行中の cudaDeviceSynchronise の後の行の情報スレッドの出力:

(gdb) info threads 
  Id   Target Id         Frame 
  2    Thread 0x7ffff5b8b700 (LWP 28458) "a.out" 0x00007ffff75aa023 in select
    () at ../sysdeps/unix/syscall-template.S:82
* 1    Thread 0x7ffff7fd4740 (LWP 28255) "a.out" main () at cuda_test.cu:30

cudaDeviceSynchronize が新しいスレッドを生成する理由と、呼び出しが戻った後もスレッドがまだ実行されている理由を理解できる人はいますか?

すべてのデバイスとホストのアクティビティ/スレッドが終了するまでブロックする方法を見つけるのを助けるために、誰かが私を正しい方向に向けることができますか?

4

1 に答える 1

1

CUDA 4.2 以降には、アプリケーション スレッドとオペレーティング システム間のブロッキング呼び出しを仲介する中間ワーカー スレッドがあります。私のテストでは、アプリケーションが使用する GPU ごとに 1 つのスレッドが作成されることが示唆されています (CUDA コンテキストごとに 1 つ?)。これらのワーカー スレッドは、ストリーム イベント コールバックの実装を容易にするために導入されたものと思われます (これらのスレッドがコールバックを実行する可能性があると思います)。ただし、この技術的な理由から、私は完全に間違っている可能性があります。

NVIDIA がこれらの中間スレッドを無効にする環境変数を提供してくれればよかったのにと思います。プログラムを SCHED_FIFO として実行する場合、問題が発生します。CUDA ルーチンが呼び出される前に、必ず SCHED_FIFO に移行する必要があります。そうしないと、SCHED_FIFO 遷移の前に生成されたワーカー スレッドは、メイン スレッドが SCHED_FIFO である間、通常のスレッドとしてスケジュールされます。これにより、優先度の低いワーカー スレッドがスケジュールされるのを待ってメイン スレッドがブロックされるという優先度の逆転が発生します。スレッドが生成される前に SCHED_FIFO に移行すると、将来のスレッドは親の SCHED_FIFO ポリシーと優先度を継承できます。

あなたの問題の解決策として: アプリケーションのコンテキストで cudaDeviceReset() を呼び出すことはできますか? これにより、システム内の CUDA ランタイム状態が再初期化され、ワー​​カー スレッドが強制終了されることが期待されます。それ以外の場合は、常に pthread_cancel() (または Windows の同等の関数) が存在しますが、これにより CUDA が一貫性のない状態になる可能性があります。

于 2013-04-12T21:57:33.373 に答える