[英]Is There Any Way To Copy vtable From Host To Device (CUDA & C++)
似乎 Cuda 不允許我“將源自虛擬基類的 class 的 object 傳遞給__global__
函數”,原因與“虛擬表”或“虛擬指針”有關。
我想知道有什么方法可以讓我手動設置“虛擬指針”,這樣我就可以使用多態性了嗎?
有沒有辦法將 vtable 從主機復制到設備
您不想將 vtable 從主機復制到設備。 主機上的vtable(即在主機上創建的object)在vtable中有一組主機function指針。 當您將這樣的 object 復制到設備時,vtable 不會更改或“修復”,因此您最終會在設備上得到 object,其 vtable 中充滿了主機指針。
如果您然后嘗試調用其中一個虛擬功能(使用設備上的 object,來自設備代碼),就會發生不好的事情。 vtable 中列出的數字 function 入口點是在設備代碼中沒有任何意義的地址。
這樣我就可以使用多態性
我建議在設備代碼中使用多態性的方法是在設備上創建 object 。 這將使用一組設備 function 指針而不是主機 function 指針設置 vtable,諸如此類的問題表明它有效。 一階近似,如果你有辦法在主機代碼中創建一組多態對象,我不知道你為什么不能在設備代碼中使用類似的方法。 這個問題確實與互操作性有關——在主機和設備之間移動這些對象——這就是編程指南中所述的限制所指的內容。
我想知道有什么方法可以讓我手動設置“虛擬指針”
可能有。 為了分享知識,我將概述一種方法。 但是,我不知道 C++ 足以說明這是否可以接受/合法。 我唯一能說的是在我非常有限的測試中,它似乎有效。 但我認為這是不合法的,所以我不建議您將此方法用於實驗以外的任何事情。 即使我們不解決它是否合法,已經有一個聲明的 CUDA 限制(如上所述),您不應該嘗試在主機和設備之間傳遞具有虛擬功能的對象。 所以我提供它只是作為一個觀察,這可能對實驗或研究很有趣。 我不建議將它用於生產代碼。
此線程中概述了基本思想。 這是基於這樣的想法,即普通的對象副本似乎不會復制虛擬 function 指針表,這對我來說是有意義的,但 object 作為一個整體確實包含該表。 因此,如果我們使用這樣的方法:
template<typename T>
__device__ void fixVirtualPointers(T *other) {
T temp = T(*other); // object-copy moves the "guts" of the object w/o changing vtable
memcpy(other, &temp, sizeof(T)); // pointer copy seems to move vtable
}
it seems to be possible to take a given object, create a new "dummy" object of that type, and then "fix up" the vtable by doing a pointer-based copy of the object (considering the entire object size) rather than a “典型”對象副本。 使用它需要您自擔風險。 這個博客也可能是有趣的閱讀,雖然我不能保證那里的任何陳述的正確性。
除此之外, cuda
標簽上還有各種其他建議,您不妨查看它們。
我想提供一種不同的方法來修復不依賴於在對象之間復制 vtable 的 vtable。 這個想法是在設備上使用placement new 來讓編譯器生成適當的vtable。 但是,這種方法也違反了編程指南中規定的限制。
#include <cstdio>
struct A{
__host__ __device__
virtual void foo(){
printf("A\n");
}
};
struct B : public A{
B(int i = 13) : data(i){}
__host__ __device__
virtual void foo() override{
printf("B %d\n", data);
}
int data;
};
template<class T>
__global__
void fixKernel(T* ptr){
T tmp(*ptr);
new (ptr) T(tmp);
}
__global__
void useKernel(A* ptr){
ptr->foo();
}
int main(){
A a;
a.foo();
B b(7);
b.foo();
A* ab = new B();
ab->foo();
A* d_a;
cudaMalloc(&d_a, sizeof(A));
cudaMemcpy(d_a, &a, sizeof(A), cudaMemcpyHostToDevice);
B* d_b;
cudaMalloc(&d_b, sizeof(B));
cudaMemcpy(d_b, &b, sizeof(B), cudaMemcpyHostToDevice);
fixKernel<<<1,1>>>(d_a);
useKernel<<<1,1>>>(d_a);
fixKernel<<<1,1>>>(d_b);
useKernel<<<1,1>>>(d_b);
cudaDeviceSynchronize();
cudaFree(d_b);
cudaFree(d_a);
delete ab;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.