2009-09-20 123 views
2

我和一些同龄人正在研究游戏(Rigs ofRods),并且正在尝试将OpenCL用于物理计算。同时,我们正在尝试对我们的数据结构进行一些必要的清理。我想我应该说我们正在努力清理我们的数据结构并且注意OpenCL的要求。从指针计算数组索引

使用开放式CL的问题之一是无法使用指针,因为内存空间不同。从我对OpenCL知之甚少的情况就是将所有的数据拷贝到GPU上,然后执行计算,指针值将被复制,但地址不会与期望的地址相对应。

有问题的数据集中在一个数组中,当对象需要该数据时,它们使用指向它所需对象的指针或存储数组索引。

解决OpenCL的一个解决方案是使用数组索引而不是指针。这会导致硬耦合,以后可能会导致头痛。作为一个解决方案,我有基于开始地址和当前地址计算数组索引的想法。这当然只适用于连续数组。

我写了一个示例应用程序来测试它,它工作得很好,有些人也在不同的平台上验证它。

#include <iostream> 

typedef struct beam_t 
{ 
unsigned int item; 
} beam_t; 

#define GLOBAL_STATIC_ASSERT(expr, msg) \ 
    extern char STATIC_ASSERTION__##msg[1]; \ 
    extern char STATIC_ASSERTION__##msg[(expr)?1:2] 


#ifdef __amd64 
typedef unsigned long pointer_int; 
#else 
typedef unsigned int pointer_int; 
#endif 
GLOBAL_STATIC_ASSERT(sizeof(pointer_int) == sizeof(pointer_int*), integer_size); 
#define MAX_BEAM 5 


int main() 
{ 
beam_t beams[MAX_BEAM]; 
beam_t* beam_start = &beams[0]; 
beam_t* beam_ptr = NULL; 

std::cout << "beams: " << &beams << "\n"; 

for(pointer_int i = 0; i < MAX_BEAM; ++i) 
{ 
    beam_ptr = &beams[i]; 
    pointer_int diff = ((pointer_int)beam_ptr - (pointer_int)beam_start); 
    std::cout << "beams[" << i << "]: " << beam_ptr 
     << "\t calculated index:" << diff/sizeof(beam_t) 
     << "\n"; 
} 
return 0; 
} 

我担心的是,这不仅仅是一个优化的解决方案。我知道这不会有任何非连续的记忆。

基本上我的问题是这样的:
在已知的连续记忆中使用这种方法会有什么缺陷?
你会如何判断它是连续的?
人们在处理这类问题时使用了什么方法?

谢谢,以及我的appologies如果格式化关闭,这是我第一次发布一个问题。

回答

12

这应该给你pointer相对的指数base

pointer - base 

是的,就是这么简单。 =]

使用ptrdiff_t可移植地存储结果。

+0

是的,我想通了这一点,我不知道该ptrdiff_t的,虽然,这样的接缝将取代pointer_int类型我在我的例子typedef定义。 我更想知道可靠性和编码实践。这是否是一种好方法,而不是一种有效的黑客/混合物。 – Apeiron 2009-09-20 19:22:28

+1

这是惯用的方法。在C和C++中,POD数组保证是连续的。我希望CUDA和OpenCL也是如此。 – greyfade 2009-09-20 19:46:02

+0

不仅POD,*所有*数组都保证是连续的。 – jalf 2009-09-20 20:35:26

3

虽然指针的简单减法有效,但建议使用std::distance。这也适用于不是指针的迭代器类型,也可以为自定义类型重载。对于指针,结果将是ptrdiff_t

+1

我不知道'std :: distance'。看起来很有用。但是,STL迭代器类型不是'operator-'重载吗? – strager 2009-09-20 20:45:35

1
#define ARRAY_INDEX_FROM_ADDR(base, addr, type) \ 
(((uintptr_t)(addr)-(uintptr_t)(base))/sizeof(type)) 

如果不使用C99,使用uintptr_tunsigned long long代替