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

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

我的想法是建立一个Trie,然后提交一个可在Trie中并行查找子字符串的内核。为此,我创建了一个SYCL队列,为字符串(用于在其中查找子字符串的缓冲区), vector (用于存储搜索结果的缓冲区)以及Aho-Corasick对象的缓冲区创建了缓冲区,该对象包含先前构建的trie的根。但是,关于最后一个,我不确定,因为我正在为主机内存中的对象创建一个缓冲区,该缓冲区包含指向其他对象的指针(例如Node,其中包含指向其他Node的指针)。

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));

和队列摘要:
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 的项目后失败。因此,我认为问题在于映射中存储的指针是指向设备无法访问的主机内存的指针。

最佳答案

如果我理解正确,则您正在尝试在设备代码中使用std::unordered_mapstd::stringstd::set。我不是特定于Intel的oneAPI SYCL扩展的专家,但是在纯SYCL 1.2.1中这是不允许的,如果在DPC++中可以使用,我会感到惊讶。

SYCL 1.2.1规范并未真正定义SYCL如何与标准库交互。尽管某些实现可能能够保证标准库中定义明确的部分以devie代码作为扩展(通常是std::数学函数)工作,但在SYCL实现中并不能得到普遍保证。
另外,我还认为在设备代码中支持STL容器(这不是SYCL规范所要求的)特别困难,而且我从未听说过SYCL实现支持该代码。这是因为容器通常采用SYCL设备代码不支持的机制,因为它们需要运行时支持,例如抛出异常。因为,例如,在GPU上没有C++运行时,所以此类机制无法在SYCL中使用。

同样重要的是要了解,这实际上不是SYCL特定的限制,而是异构编程模型之间的常见限制。出于类似的原因,其他异构编程模型(例如CUDA)也施加了类似的限制。

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

最后一个探针是您已经确定的探针:您正在将指针复制到主机内存。由于您使用的是oneAPI DPC++,因此使用基于指针的数据结构最简单的解决方案是使用unified shared memory(USM)的英特尔SYCL扩展名,该扩展名可用于生成在主机和设备上均有效的指针。如果设备代码中支持容器,也可以将USM分配器传递给容器。

关于c++ - 无法为自定义对象oneAPI创建数据缓冲区,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/61681965/

10-13 06:20