【问题标题】:calculate array index from pointers从指针计算数组索引
【发布时间】:2010-11-29 22:04:42
【问题描述】:

我和一些同行正在开发一款游戏 (Rigs ofRods),并尝试将 OpenCL 集成到物理计算中。同时,我们正在尝试对我们的数据结构进行一些急需的清理。我想我应该说我们正在尝试清理我们的数据结构并注意 OpenCL 的要求。

使用 open 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;
}

我担心这更像是一个拼凑而不是一个完善的解决方案。我知道这在没有非连续记忆的情况下是行不通的。

基本上我的问题是这样的:
在已知的连续内存中使用这种方法会有什么缺陷?
你怎么能说它是连续的?
人们在处理此类问题时使用了哪些方法?

谢谢,如果格式关闭,我很抱歉,这是我第一次发布问题。

【问题讨论】:

    标签: c++ pointers cuda opencl


    【解决方案1】:

    这应该给你pointer相对于base的索引:

    pointer - base
    

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

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

    【讨论】:

    • 是的,我想通了,但我不知道 ptrdiff_t,这样的接缝将替换我在示例中键入的 pointer_int 类型。我更想知道可靠性和编码实践。即这是 good 方法,而不是有效的 hack/kludge。
    • 这是惯用的方法。在 C 和 C++ 中,POD 数组保证是连续的。我希望在 CUDA 和 OpenCL 中也是如此。
    • 不只是 POD,所有数组都保证是连续的。
    【解决方案2】:

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

    【讨论】:

    • 我不知道std::distance。似乎很有用。但是,operator- 不是为 STL 迭代器类型重载了吗?
    【解决方案3】:
    #define ARRAY_INDEX_FROM_ADDR(base, addr, type) \
    (((uintptr_t)(addr)-(uintptr_t)(base))/sizeof(type))
    

    如果不使用 C99,请使用 unsigned long long 而不是 uintptr_t

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-14
      • 2018-10-17
      • 2013-01-16
      相关资源
      最近更新 更多