17

複数の CUDA デバイスに分割したいという問題がありますが、現在のシステム アーキテクチャが妨げになっていると思われます。

私がセットアップしたのは、GPU 上で操作を実行する関数を備えた GPU クラスです (奇妙なことです)。これらの操作はスタイルのものです

for iteration in range(maxval):
    result[iteration]=gpuinstance.gpufunction(arguments,iteration)

N個のデバイスに対してN個のgpuインスタンスがあると想像していましたが、これを適用して各デバイスが非同期に割り当てられるようにする最も簡単な方法を確認するには、マルチプロセッシングについて十分に知りません。処理後の照合結果の具体的なデモンストレーション。

誰かがこの分野の指針を教えてもらえますか?

更新 マルチプロセッシング領域に関するガイダンスを提供してくれた Kaloyan に感謝します。CUDA が特に問題になっていなければ、回答済みとしてマークします。ごめん。

以前、この実装で遊んでいた gpuinstance クラスは CUDA デバイスを開始しましたが、(正しくスコープされた) 各スレッドが cuda コマンドに遭遇するとすぐにエラーをimport pycuda.autoinitスローして、うまくいかなかったようです。次に、クラスinvalid contextのコンストラクターで手動で初期化を試みました...__init__

pycuda.driver.init()
self.mydev=pycuda.driver.Device(devid) #this is passed at instantiation of class
self.ctx=self.mydev.make_context()
self.ctx.push()    

ここでの私の仮定は、gpuinstances のリストが作成されてからスレッドがそれらを使用するまでの間、コンテキストが保持されているため、各デバイスは独自のコンテキストで適切に配置されているということです。

pop/detachクリーンアップを処理するためにデストラクタも実装しました)

問題は、invalid contextスレッドが CUDA に触れようとするとすぐに例外が表示されることです。

アイデアはありますか?そして、ここまで来れたおかげです。回答に「バナナ」を使用している人々に自動的に賛成票を投じます! :P

4

2 に答える 2

21

最初にすべてのバナナを CUDA 側に並べる必要があります。次に、Python でこれを行うための最善の方法を考えます [恥知らずな担当者、私は知っています]。

4.0 より前の CUDA マルチ GPU モデルは非常に単純です。各 GPU には独自のコンテキストがあり、各コンテキストは異なるホスト スレッドによって確立される必要があります。したがって、擬似コードのアイデアは次のとおりです。

  1. アプリケーションが起動し、プロセスは API を使用して使用可能な GPU の数を決定します (Linux の計算モードなどに注意してください)
  2. アプリケーションは GPU ごとに新しいホスト スレッドを起動し、GPU ID を渡します。各スレッドは、割り当てられた GPU ID を渡す cuCtxCreate() と同等のものを暗黙的/明示的に呼び出します
  3. 利益!

Python では、これは次のようになります。

import threading
from pycuda import driver

class gpuThread(threading.Thread):
    def __init__(self, gpuid):
        threading.Thread.__init__(self)
        self.ctx  = driver.Device(gpuid).make_context()
        self.device = self.ctx.get_device()

    def run(self):
        print "%s has device %s, api version %s"  \
             % (self.getName(), self.device.name(), self.ctx.get_api_version())
        # Profit!

    def join(self):
        self.ctx.detach()
        threading.Thread.join(self)

driver.init()
ngpus = driver.Device.count()
for i in range(ngpus):
    t = gpuThread(i)
    t.start()
    t.join()

これは、事前にデバイスをチェックせずにコンテキストを確立するだけで安全であると想定しています。コンピューティング モードをチェックして安全に試行できることを確認してから、デバイスがビジー状態の場合に備えて例外ハンドラーを使用するのが理想的です。しかし、うまくいけば、これで基本的な考え方が得られます。

于 2011-05-06T07:57:13.040 に答える
3

必要なのは、map組み込み関数のマルチスレッド実装です。ここに 1 つの実装があります。特定のニーズに合わせて少し変更すると、次のようになります。

import threading

def cuda_map(args_list, gpu_instances):

    result = [None] * len(args_list)

    def task_wrapper(gpu_instance, task_indices):
        for i in task_indices:
            result[i] = gpu_instance.gpufunction(args_list[i])

    threads = [threading.Thread(
                    target=task_wrapper, 
                    args=(gpu_i, list(xrange(len(args_list)))[i::len(gpu_instances)])
              ) for i, gpu_i in enumerate(gpu_instances)]
    for t in threads:
        t.start()
    for t in threads:
        t.join()

    return result

上記のものとほぼ同じですが、大きな違いは、gpufunction.

于 2011-05-05T23:12:01.800 に答える