在为自定义对象oneAPI创建数据缓冲区时遇到了麻烦。

问题描述 投票:1回答:1

我是oneAPI和类似框架的新手,所以在使用SYCL数据缓冲区管理数据时遇到了麻烦。

我的任务是使用Aho-Corasick算法在一个给定的字符串中寻找子串。

我的想法是建立一个Trie,然后提交一个内核,在Trie中并行查找子串。因此,我创建了一个SYCL队列,为字符串(查找子串)、向量(存储搜索结果)和我的Aho-Corasick对象创建了缓冲区,其中包含了之前建立的Trie的根。然而,关于最后一个我不确定,因为我在主机内存中为一个对象创建了一个缓冲区,这个缓冲区包含指向其他对象的指针(比如Nodes,它包含指向其他Nodes的指针)。

Node对象的结构。

class Node {

        typedef Node *node_ptr;

    private:

        std::set<std::pair<int, std::string>> retVals;
        std::unordered_map<char, node_ptr> children;
        node_ptr fail;
        char value;

这是搜索方法。

 void
        matchWords(char *text, int startIdx, int endIdx,  cl::sycl::cl_int *matched) {

            node_ptr child = start;
            int item = startIdx;
            for (int i = startIdx; i < endIdx; ++i) {
                child = child->nextNode(text[i]);
                if (child == nullptr) {
                    child = start;
                    continue;
                }
                for (const auto &returns: child->getRetVals()) {
                    matched[item++] = returns.first;
                    if (item == endIdx) item = startIdx;
                }
            }
        }

缓冲区。

cl::sycl::buffer<char, 1> fasta_buf(tempFasta.data(), cl::sycl::range<1>(len));
cl::sycl::buffer<cl::sycl::cl_int, 1> vec_buf(vec.data(), cl::sycl::range<1>(len));
cl::sycl::buffer<aho_corasick::AhoCorasick, 1> aho_buf(a, cl::sycl::range<1>(1));

和队列sumbition。

q.submit([&](cl::sycl::handler &cgh) {
        auto string_acc = fasta_buf.get_access<cl::sycl::access::mode::read>(cgh);
        auto vec_acc = vec_buf.get_access<cl::sycl::access::mode::read_write>(cgh);
        auto aho_acc = aho_buf.get_access<cl::sycl::access::mode::read>(cgh);

        cgh.parallel_for<class dummy>(
                cl::sycl::range<1>(10), [=](cl::sycl::item<1> i) {
                    // 10 is the number of workers I want 
                    int startInx = (int) (i.get_linear_id() * (len / 10)); 
                    int endInx = (int) ((i.get_linear_id() + 1) * (len / 10));
                    aho_acc.get_pointer()->matchWords(string_acc.get_pointer(), startInx, endInx, vec_acc.get_pointer());
                });
    });
    q.wait_and_throw();

我发现,程序在试图访问子地图的项目后失败了。因此,我认为问题出在map中存储的指针是指向主机内存的指针,而设备并不能访问这些内存。

c++ opencl sycl intel-oneapi dpc++
1个回答
4
投票

如果我的理解正确的话,你是在尝试使用 std::unordered_map, std::stringstd::set 的设备代码中。我不是Intel特有的oneAPI SYCL扩展的专家,但在纯SYCL 1.2.1中,这是不允许的,如果这在DPC++中也能用,我会很惊讶。

SYCL 1.2.1规范并没有真正定义SYCL如何与标准库交互。虽然一些实现可以保证标准库的某些定义良好的部分作为扩展在devie代码中工作(常见的如:数学函数),但这并不是标准库的一部分。std:: 另外,在设备代码中支持STL容器(这不是SYCL规范所要求的),我想是特别困难的,我从来没有听说过SYCL实现支持这一点。这是因为容器通常采用SYCL设备代码中不支持的机制,因为它们需要运行时支持,例如抛出异常。因为在比如说GPU上没有C++运行时,这样的机制在SYCL中无法工作。

同样重要的是要明白,这其实并不是SYCL特有的限制,而是异构编程模型中常见的限制。其他异构编程模型,如CUDA,也出于类似的原因施加了类似的限制。

在内核中使用容器的另一个困难是,STL数据结构通常不是真正为SYCL设备上的大规模并行SIMT执行模型设计的,这使得它们容易出现竞赛条件。

最后一个问题是你已经发现的问题。你正在复制指针到主机内存中. 由于你使用的是oneAPI DPC++,所以处理基于指针的数据结构最简单的解决方案是使用英特尔SYCL扩展的 统一共享内存 USM),它可以用来生成在主机和设备上都有效的指针。还有一个USM分配器,如果设备代码中支持USM,可以将其传递给容器。

© www.soinside.com 2019 - 2024. All rights reserved.