我有一个C程序来查找2组多边形是否重叠。用户输入2组多边形(每组数据有几千个多边形),程序看到set1中哪个多边形与set2中的哪个多边形重叠
我有2个这样的结构:
struct gpc_vertex /* Polygon vertex */
{
double x;
double y;
};
struct gpc_vertex_list /* Polygon contour */
{
int pid; // polygon id
int num_vertices;
double *mbr; // minimum bounding rectangle of the polygon, so always 4 elements
};
我有以下代码段:
#pragma acc kernels copy(listOfPolygons1[0:polygonCount1], listOfPolygons2[0:polygonCount2], listOfBoolean[0:dump])
for (i=0; i<polygonCount1; i++){
polygon1 = listOfPolygons1[i];
for (j=0; j<polygonCount2; j++){
polygon2 = listOfPolygons2[j];
idx = polygonCount2 * i + j;
listOfBoolean[idx] = isRectOverlap(polygon1.mbr, polygon2.mbr); // line 115
}
}
listOfPolygons1和listOfPolygons2是(如名称所示)gpc_vertex_list的数组。
listOfBoolean是一个int数组
检查2个多边形的mbr是否重叠,函数“isRectOverlap”如果是则返回1,如果不是则返回0并将值放入listOfBoolean
问题
代码可以编译但无法运行。它返回以下错误:
call to cuEventSynchronize returned error 700: Illegal address during kernel execution
我的观察
该程序可以通过将第115行更改为:
isRectOverlap(polygon1.mbr, polygon2.mbr); // without assigning value to listOfBoolean
或者这个:
listOfBoolean[idx] = 5; // assigning an arbitrary value
(虽然结果是错误的,但至少可以运行)
问题
如果值没有从“isRectOverlap”传递到“listOfBoolean”,那么“isRectOverlap”和“listOfBoolean”似乎都不会产生问题
如果我将“isRectOverlap”的返回值赋给“listOfBoolean”,有没有人知道为什么它不能运行?
isRectOverlap函数是这样的:
int isRectOverlap(double *shape1, double *shape2){
if (shape1[0] > shape2[2] || shape2[0] > shape1[2]){
return 0;
}
if (shape1[1] < shape2[3] || shape2[1] < shape1[3]){
return 0;
}
return 1;
}
当没有在OpenACC中运行时,程序没有问题
感谢您的帮助
答案 0 :(得分:1)
在OpenACC数据子句中使用聚合数据类型时,将执行该类型的浅表副本。这里最有可能发生的事情是当listOfPolygons数组被复制到设备时,&#34; mbr&#34;将包含主机地址。因此,当一个&#34; mbr&#34;被访问。
鉴于评论说&#34; mbr&#34;将永远是4,最简单的事情是做&#34; mbr&#34;一个大小为4的固定大小的数组。
假设您正在使用带有NVIDIA设备的PGI编译器,第二种方法是通过编译&#34; -ta = tesla:managed&#34;来使用CUDA统一内存。所有动态内存都将由CUDA运行时处理,并允许在设备上访问主机地址。需要注意的是,它只适用于动态数据,您的整个程序只能使用设备上可用的内存,并且可能会降低程序速度。 http://www.pgroup.com/lit/articles/insider/v6n2a4.htm
第三种选择是对设备执行聚合类型的深层复制。如果你决定走这条路,我可以发一个例子。作为我在GTC2015上做过的演讲的一部分,我还谈到了这个主题:https://www.youtube.com/watch?v=rWLmZt_u5u4
答案 1 :(得分:1)
这是一个简化的例子。关键是在分配主机数据的相同位置使用非结构化数据区域。首先分配结构数组并在数组中创建或复制到设备。这里我只是创建数组,因此设备数据是垃圾,但如果我做了copyin,那么会发生浅拷贝,并且“mbr”的主机地址将被复制到设备。要解决此问题,您需要在设备上创建每个“mbr”。然后,编译器将分配“附加”设备“mbr”指针,从而覆盖垃圾/主机指针值。一旦“mbr”具有有效的设备指针,就可以在设备上引用它们。
% cat example_struct.c
#include <stdlib.h>
#include <stdio.h>
#ifndef N
#define N 1024
#endif
typedef struct gpc_vertex_list
{
int pid; // polygon id
int num_vertices;
double *mbr; // minimum bounding rectangle of the polygon, so always 4 elements
} gpc_vertex_list;
gpc_vertex_list * allocData(size_t size);
int deleteData(gpc_vertex_list * A, size_t size);
int initData(gpc_vertex_list *Ai, size_t size);
#pragma acc routine seq
int isRectOverlap(double * mbr) {
int result;
result = mbr[0];
result += mbr[1];
result += mbr[2];
result += mbr[3];
return result;
}
int main() {
gpc_vertex_list *A;
gpc_vertex_list B;
size_t size, i;
int * listOfBoolean;
size = N;
A=allocData(size);
initData(A,size);
listOfBoolean = (int*) malloc(sizeof(int)*size);
#pragma acc parallel loop present(A) copyout(listOfBoolean[0:size]) private(B)
for (i=0; i<size; i++){
B = A[i];
listOfBoolean[i] = isRectOverlap(B.mbr);
}
printf("result: %d %d %d\n",listOfBoolean[0], listOfBoolean[size/2], listOfBoolean[size-1]);
free(listOfBoolean);
deleteData(A, size);
exit(0);
}
gpc_vertex_list * allocData(size_t size) {
gpc_vertex_list * tmp;
tmp = (gpc_vertex_list *) malloc(size*sizeof(gpc_vertex_list));
/* Create the array on device. */
#pragma acc enter data create(tmp[0:size])
for (int i=0; i< size; ++i) {
tmp[i].mbr = (double*) malloc(sizeof(double)*4);
/* create the member array on the device */
#pragma acc enter data create(tmp[i].mbr[0:4])
}
return tmp;
}
int deleteData(gpc_vertex_list * A, size_t size) {
/* Delete the host copy. */
for (int i=0; i< size; ++i) {
#pragma acc exit data delete(A[i].mbr)
free(A[i].mbr);
}
#pragma acc exit data delete(A)
free(A);
}
int initData(gpc_vertex_list *A ,size_t size) {
size_t i;
for (int i=0; i< size; ++i) {
A[i].pid = i;
A[i].num_vertices = 4;
for (int j=0; j<4;++j) {
A[i].mbr[j]=(i*4)+j;
}
#pragma acc update device(A[i].pid,A[i].num_vertices,A[i].mbr[0:4])
}
}
% pgcc example_struct.c -acc -Minfo=accel
isRectOverlap:
20, Generating acc routine seq
main:
39, Generating copyout(listOfBoolean[:size])
Generating present(A[:])
Accelerator kernel generated
Generating Tesla code
40, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */
39, Local memory used for B
allocData:
55, Generating enter data create(tmp[:size])
59, Generating enter data create(tmp->mbr[:4])
deleteData:
67, Generating exit data delete(A->mbr[:1])
70, Generating exit data delete(A[:1])
initData:
83, Generating update device(A->mbr[:4],A->pid,A->num_vertices)
% a.out
result: 6 8198 16374