1

これは私を完全に困惑させます。論理的に同じであるはずの 2 つのコードのセット。一方は GPU でのみクラッシュし、両方とも CPU で正常に動作します。テストコードは次のとおりです。

#include <iostream>
#include <CL/cl.hpp>

class Device
{
public:
    cl::Platform platform_;
    cl::Device device_;
    cl::Context context_;
    cl::CommandQueue queue_;

    Device( void ) : platform_()
                   , device_()
                   , context_()
                   , queue_() {}

    Device(int32_t platform, int32_t device) : platform_()
                                             , device_()
                                             , context_()
                                             , queue_()
    {
        std::vector<cl::Platform> platforms;
        cl::Platform::get(&platforms);
        platform_ = platforms[platform];

        std::vector<cl::Device> devices;
        platform_.getDevices(CL_DEVICE_TYPE_GPU, &devices);
        device_ = devices[device];

        cl_context_properties properties[3] = {
            CL_CONTEXT_PLATFORM,
            (cl_context_properties)(platform_)(),
            0
        };

        cl_int clErr = CL_SUCCESS;
        context_ = cl::Context(device_, properties, NULL, NULL, &clErr);
        queue_ = cl::CommandQueue(context_,device_,0,&clErr);
    }
};

int main()
{
    Device device(0,0);

    cl::Program::Sources source;
    std::string src =
    "__kernel void Pointless(uint total, __global uint *data)"\
    "{"\
    "   uint perStream=total/get_global_size(0);"\
    "   __global uint *dest=data+get_global_id(0)*perStream;"\
    "   for(uint i=0;i<perStream;i++)"\
    "       dest[i] = 1;"\
    "}";

    source.push_back({src.c_str(),src.length()});

    cl_int clErr = CL_SUCCESS;
    cl::Program program = cl::Program(device.context_,source,&clErr);
    if (clErr != CL_SUCCESS)
    {
        std::cerr << "Failed to create program: " << clErr << std::endl;
        return 1;
    }

    clErr = program.build({device.device_});
    if(clErr != CL_SUCCESS)
    {
        std::cerr << "Failed to build program: " << clErr << std::endl;
        std::cerr << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device.device_) << std::endl;
        return 1;
    }

    uint32_t samples = 16*256;
    cl::make_kernel<cl_uint,cl::Buffer> Pointless(cl::Kernel(program,"Pointless"));
    cl::Buffer device_samples(device.context_,CL_MEM_READ_WRITE,sizeof(cl_uint)*samples);
    Pointless(cl::EnqueueArgs(device.queue_, cl::NDRange(16)), samples, device_samples).wait();

    std::vector<cl_uint> host_samples(samples);
    device.queue_.enqueueReadBuffer(device_samples,CL_TRUE,0,sizeof(cl_uint)*samples,host_samples.data());

    for (auto x: host_samples)
        std::cout << x;
    std::cout << std::endl;

    return 0;
}

上記は失敗したようです: でセグメンテーション違反が発生しenqueueReadBufferます。さらに興味深いことに、GPU (Intel P4000) でのみ失敗します。CPU (i3 3xxx) は問題なく実行されます ( CPU でテストするように変更CL_DEVICE_TYPE_GPUします)。CL_DEVICE_TYPE_CPU

以下のコードは、両方のデバイス タイプで正常に動作するようになりました。

#include <iostream>
#include <CL/cl.hpp>

int main()
{
    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);
    cl::Platform platform = platforms[0];

    std::vector<cl::Device> devices;
    platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
    cl::Device device = devices[0];

    cl_context_properties properties[3] = {
        CL_CONTEXT_PLATFORM,
        (cl_context_properties)(platform)(),
        0
    };

    cl_int clErr = CL_SUCCESS;
    cl::Context context(device, properties, NULL, NULL, &clErr);

    cl::CommandQueue queue(context,device,0,&clErr);

    cl::Program::Sources source;
    std::string src =
    "__kernel void Pointless(uint total, __global uint *data)"\
    "{"\
    "   uint perStream=total/get_global_size(0);"\
    "   __global uint *dest=data+get_global_id(0)*perStream;"\
    "   for(uint i=0;i<perStream;i++)"\
    "       dest[i] = 1;"\
    "}";

    source.push_back({src.c_str(),src.length()});

    cl::Program program = cl::Program(context,source,&clErr);

    clErr = program.build({device});
    if(clErr != CL_SUCCESS)
    {
        std::cerr << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device) << std::endl;
    }

    uint32_t samples = 16*256;
    cl::make_kernel<cl_uint,cl::Buffer> Pointless(cl::Kernel(program,"Pointless"));
    cl::Buffer device_samples(context,CL_MEM_READ_WRITE,sizeof(cl_uint)*samples);
    Pointless(cl::EnqueueArgs(queue, cl::NDRange(16)), samples, device_samples).wait();

    std::vector<cl_uint> host_samples(samples);
    queue.enqueueReadBuffer(device_samples,CL_TRUE,0,sizeof(cl_uint)*samples,host_samples.data());

    for (auto x: host_samples)
        std::cout << x;
    std::cout << std::endl;

    return 0;
}

明らかに、ここで非常に基本的なものが欠けています。どちらも Intel ICD を使用しています (このシステムには AMD デバイスがありません)。

4

2 に答える 2

2

(投稿を始めたばかりなので、まだコメントできません)

Nvidia 実装を使用してコードをテストしました (Intel ICD を使用)。C++ コンパイラは G++ 4.7.3 でした。両方の例は、利用可能な Intel CPU でも GPU で完全に機能しました。

したがって、問題はほぼ確実に、Intel GPU の実装でのみ限定されます。

于 2013-11-04T19:20:05.330 に答える
0

cl.hppそのため、ラッパーのバグに遭遇した可能性があります。cl::Context context_; context_ = cl::Context(...);基礎となるオブジェクトのアドレスを適切に割り当てていません。ただし、両方とも正常cl::Context context_ = cl::Context(...)に動作します。cl::Context context_(...);

G++ 4.8.1 と MSVC 2010 の両方でテストしましたが、どちらも同じ結果でした。CPU で正常に動作するということは、おそらく Intel の ICD のバグを示しています。Khronos Group のドキュメントにcl::Contextは、「暗黙的に保持する」と記載されていますが、アプリケーションがラッパーに気付かれずに基になるオブジェクトを解放できることについての簡単なコメントがあります。

Sharpneli、DarkZeros に感謝します。

于 2013-11-05T02:33:05.520 に答える