我有一个C代码,我想将该代码翻译为与CUDA一起使用。
解释完整的问题将是非常复杂和冗长的,这是它的一部分,我有问题。
现在问题是:我需要创建四个AVL树(从树中插入的数据是从文件中读取的(实际文件,较小的一个,有255000行,但最多可以有1,200万行)在每个对应的树上插入四个值后,不同树的每个节点都会有一个不同节点的列表(每棵树一个不同),但首先我需要解决我遇到的问题。
问题如下,如果我创建其中三个没有问题,但如果我创建了四个,CUDA会给出一个错误“Out of memory”。
注意,有410个代码行,使用cudaMallocManaged(...)函数的内存保留在行上:90(函数main)和164,176和190(函数auxCrearIndiceAVL)。所以我认为它有错误,但如果是这样我就看不到它。
此外,我正在使用带有两个NVIDIA 680 GTX(2 GB)和32 GB RAM的Visual Studio在Windows上运行计算机。因此,对于这4种结构,我认为结构存在记忆。我不知道是否需要激活CUDA设置上的任何选项或......
感谢大家提前看到这一切。 Manuel Luis Aznar
代码如下:
#include "cuda_runtime.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
#define CHECK(r) {_check((r), __LINE__);}
/* Estructuras y tipos */
enum { IZQUIERDO, DERECHO };
typedef struct _nodo_especial {
double m2i;
double m1o;
double m2o;
struct _tipo_nodo *dato_next_index;
struct _nodo_especial *siguiente;
struct _nodo_especial *next_index;
} nodoEspecial;
typedef nodoEspecial* pNodoEspecial;
typedef struct _tipo_nodo {
double dato;
int FE;
struct _nodo_especial *list;
struct _tipo_nodo *derecho;
struct _tipo_nodo *izquierdo;
struct _tipo_nodo *padre;
} tipoNodo;
typedef tipoNodo* pNodo;
typedef tipoNodo* Arbol;
typedef struct REGcrowd {
double m1i, m2i, m1o, m2o, x, y, color; // crowding
} EstrellaCrowding;
typedef EstrellaCrowding* pEstrellaCrowding;
typedef EstrellaCrowding* ListaEstrellasCrowding;
typedef struct _nodo_recubrimiento {
double dato;
pNodo enlace;
} nodoRecubrimiento;
typedef nodoRecubrimiento* pNodoRecubrimiento;
typedef nodoRecubrimiento* ListaRecubrimiento;
typedef struct _indices {
Arbol indiceM1i, indiceColor, indiceX, indiceY;
int numeroEstrellasIndice;
int numeroNodosM1i, numeroNodosColor, numeroNodosX, numeroNodosY;
ListaRecubrimiento listaRecubrimiento;
} tipoIndice;
typedef tipoIndice* Indice;
typedef tipoIndice* pIndice;
pNodo auxCrearIndiceAVL(Arbol *a, double dat, int *contador);
__global__ void kernel(Indice indice);
void _check(cudaError_t r, int line);
void check_memory_cuda(void);
__host__ __device__ void InOrden(Arbol a, int *contador);
/* Funciones de equilibrado */
void Equilibrar(Arbol *a, pNodo nodo, int rama, int nuevo);
void RSI(Arbol *raiz, pNodo nodo);
void RSD(Arbol *raiz, pNodo nodo);
void RDI(Arbol *raiz, pNodo nodo);
void RDD(Arbol *raiz, pNodo nodo);
int Vacio(Arbol r);
int main(int argc, char *argv[]) {
check_memory_cuda();
//Indice indice = (pIndice)malloc(sizeof(tipoIndice));
Indice indice;
CHECK(cudaMallocManaged(&indice, sizeof(Indice)));
indice->indiceM1i = NULL;
indice->indiceColor = NULL;
indice->indiceX = NULL;
indice->indiceY = NULL;
indice->listaRecubrimiento = NULL;
indice->numeroEstrellasIndice = 0;
indice->numeroNodosM1i = 0;
indice->numeroNodosColor = 0;
indice->numeroNodosX = 0;
indice->numeroNodosY = 0;
FILE *fcrowd;
int i;
EstrellaCrowding estrellaCrowding;
fcrowd = fopen(argv[1], "r");
for (i = 0; !feof(fcrowd); i++) {
fscanf(fcrowd, "%lf %lf %lf %lf %lf %lf", &estrellaCrowding.m1i, &estrellaCrowding.m2i, &estrellaCrowding.m1o, &estrellaCrowding.m2o, &estrellaCrowding.x, &estrellaCrowding.y);
estrellaCrowding.color = estrellaCrowding.m1i - estrellaCrowding.m2i;
pNodo auxM1i = auxCrearIndiceAVL(&indice->indiceM1i, estrellaCrowding.m1i, &indice->numeroNodosM1i);
pNodo auxColor = auxCrearIndiceAVL(&indice->indiceColor, estrellaCrowding.color, &indice->numeroNodosColor);
pNodo auxX = auxCrearIndiceAVL(&indice->indiceX, estrellaCrowding.x, &indice->numeroNodosX);
//pNodo auxY = auxCrearIndiceAVL(&indice->indiceY, estrellaCrowding.y, &indice->numeroNodosY);
}
fclose(fcrowd);
check_memory_cuda();
printf("Imprimiendo el recorrido en InOrden del arbol M1i CPU\n");
int contador = 0;
InOrden(indice->indiceM1i, &contador);
printf("El numero de nodos del arbol M1i es CPU: %d\n", indice->numeroNodosM1i);
printf("Raiz arbol M1i CPU: %lf\n", indice->indiceM1i->dato);
printf("El numero de nodos del arbol Color es CPU: %d\n", indice->numeroNodosColor);
printf("Raiz arbol Color CPU: %lf\n", indice->indiceColor->dato);
printf("El numero de nodos del arbol X es CPU: %d\n", indice->numeroNodosX);
printf("Raiz arbol X CPU: %lf\n", indice->indiceX->dato);
//printf("El numero de nodos del arbol Y es CPU: %d\n", indice->numeroNodosY);
//printf("Raiz arbol Y CPU: %lf\n", indice->indiceY->dato);
kernel<<<1, 1>>>(indice);
cudaDeviceSynchronize();
return 0;
}
pNodo auxCrearIndiceAVL(Arbol *a, double dat, int *contador) {
pNodo padre = NULL;
pNodo actual = *a;
/* Buscar el dato en el arbol, manteniendo un puntero al nodo padre */
while (!Vacio(actual) && dat != actual->dato) {
padre = actual;
if (dat < actual->dato)
actual = actual->izquierdo;
else if (dat > actual->dato)
actual = actual->derecho;
}
/* Si se ha encontrado el elemento, regresar sin insertar */
if (!Vacio(actual))
return actual;
/* Si padre es NULL, entonces el arbol estaba vacio, el nuevo nodo sera el nodo raiz */
else if (Vacio(padre)) {
//(*a) = (Arbol)malloc(sizeof(tipoNodo));
CHECK(cudaMallocManaged(&(*a), sizeof(tipoNodo), cudaMemAttachGlobal));
(*a)->dato = dat;
(*a)->izquierdo = (*a)->derecho = NULL;
(*a)->padre = NULL;
(*a)->FE = 0;
(*a)->list = NULL;
(*contador)++;
return (*a);
}
/* Si el dato es menor que el que contiene el nodo padre, lo insertamos en la rama izquierda */
else if (dat < padre->dato) {
//actual = (Arbol)malloc(sizeof(tipoNodo));
CHECK(cudaMallocManaged(&actual, sizeof(tipoNodo), cudaMemAttachGlobal));
padre->izquierdo = actual;
actual->dato = dat;
actual->izquierdo = actual->derecho = NULL;
actual->padre = padre;
actual->FE = 0;
actual->list = NULL;
Equilibrar(a, padre, IZQUIERDO, TRUE);
(*contador)++;
return actual;
}
/* Si el dato es mayor que el que contiene el nodo padre, lo insertamos en la rama derecha */
else { /*if (dat > padre->dato) */
//actual = (Arbol)malloc(sizeof(tipoNodo));
CHECK(cudaMallocManaged(&actual, sizeof(tipoNodo), cudaMemAttachGlobal));
padre->derecho = actual;
actual->dato = dat;
actual->izquierdo = actual->derecho = NULL;
actual->padre = padre;
actual->FE = 0;
actual->list = NULL;
Equilibrar(a, padre, DERECHO, TRUE);
(*contador)++;
return actual;
}
}
__global__ void kernel(Indice indice) {
printf("Imprimiendo el recorrido en InOrden del arbol M1i GPU\n");
int contador = 0;
InOrden(indice->indiceM1i, &contador);
printf("El numero de nodos del arbol M1i es GPU: %d\n", indice->numeroNodosM1i);
printf("Raiz arbol M1i GPU: %lf\n", indice->indiceM1i->dato);
printf("El numero de nodos del arbol Color es GPU: %d\n", indice->numeroNodosColor);
printf("Raiz arbol Color GPU: %lf\n", indice->indiceColor->dato);
printf("El numero de nodos del arbol X es GPU: %d\n", indice->numeroNodosX);
printf("Raiz arbol X GPU: %lf\n", indice->indiceX->dato);
//printf("El numero de nodos del arbol Y es GPU: %d\n", indice->numeroNodosY);
//printf("Raiz arbol Y GPU: %lf\n", indice->indiceY->dato);
}
void _check(cudaError_t r, int line) {
if (r != cudaSuccess) {
printf("CUDA error on line %d: %s\n", line, cudaGetErrorString(r), line);
exit(0);
}
}
void check_memory_cuda(void) {
size_t free, total;
cudaMemGetInfo(&free, &total);
printf("CUDA Memory:\n\tFree ---> %llu\n\tTotal ----> %llu\n", free, total);
}
/* Recorrido de arbol en inorden, aplicamos la funcion func, que tiene
el prototipo:
void func(double*);
*/
__host__ __device__ void InOrden(Arbol a, int *contador)
{
if (a->izquierdo) InOrden(a->izquierdo, contador);
printf("%d ---> %lf\n", *contador, a->dato);
(*contador)++;
if (a->derecho) InOrden(a->derecho, contador);
}
/* Equilibrar árbol AVL partiendo del nodo nuevo */
void Equilibrar(Arbol *a, pNodo nodo, int rama, int nuevo)
{
int salir = FALSE;
/* Recorrer camino inverso actualizando valores de FE: */
while (nodo && !salir) {
if (nuevo)
if (rama == IZQUIERDO) nodo->FE--; /* Depende de si añadimos ... */
else nodo->FE++;
else
if (rama == IZQUIERDO) nodo->FE++; /* ... o borramos */
else nodo->FE--;
if (nodo->FE == 0) salir = TRUE; /* La altura de las rama que
empieza en nodo no ha variado,
salir de Equilibrar */
else if (nodo->FE == -2) { /* Rotar a derechas y salir: */
if (nodo->izquierdo->FE == 1) RDD(a, nodo); /* Rotación doble */
else RSD(a, nodo); /* Rotación simple */
salir = TRUE;
}
else if (nodo->FE == 2) { /* Rotar a izquierdas y salir: */
if (nodo->derecho->FE == -1) RDI(a, nodo); /* Rotación doble */
else RSI(a, nodo); /* Rotación simple */
salir = TRUE;
}
if (nodo->padre)
if (nodo->padre->derecho == nodo) rama = DERECHO; else rama = IZQUIERDO;
nodo = nodo->padre; /* Calcular FE, siguiente nodo del camino. */
}
}
/* Rotación doble a derechas */
void RDD(Arbol *raiz, Arbol nodo)
{
pNodo Padre = nodo->padre;
pNodo P = nodo;
pNodo Q = P->izquierdo;
pNodo R = Q->derecho;
pNodo B = R->izquierdo;
pNodo C = R->derecho;
if (Padre)
if (Padre->derecho == nodo) Padre->derecho = R;
else Padre->izquierdo = R;
else *raiz = R;
/* Reconstruir árbol: */
Q->derecho = B;
P->izquierdo = C;
R->izquierdo = Q;
R->derecho = P;
/* Reasignar padres: */
R->padre = Padre;
P->padre = Q->padre = R;
if (B) B->padre = Q;
if (C) C->padre = P;
/* Ajustar valores de FE: */
switch (R->FE) {
case -1: Q->FE = 0; P->FE = 1; break;
case 0: Q->FE = 0; P->FE = 0; break;
case 1: Q->FE = -1; P->FE = 0; break;
}
R->FE = 0;
}
/* Rotación doble a izquierdas */
void RDI(Arbol *a, pNodo nodo)
{
pNodo Padre = nodo->padre;
pNodo P = nodo;
pNodo Q = P->derecho;
pNodo R = Q->izquierdo;
pNodo B = R->izquierdo;
pNodo C = R->derecho;
if (Padre)
if (Padre->derecho == nodo) Padre->derecho = R;
else Padre->izquierdo = R;
else *a = R;
/* Reconstruir árbol: */
P->derecho = B;
Q->izquierdo = C;
R->izquierdo = P;
R->derecho = Q;
/* Reasignar padres: */
R->padre = Padre;
P->padre = Q->padre = R;
if (B) B->padre = P;
if (C) C->padre = Q;
/* Ajustar valores de FE: */
switch (R->FE) {
case -1: P->FE = 0; Q->FE = 1; break;
case 0: P->FE = 0; Q->FE = 0; break;
case 1: P->FE = -1; Q->FE = 0; break;
}
R->FE = 0;
}
/* Rotación simple a derechas */
void RSD(Arbol *a, pNodo nodo)
{
pNodo Padre = nodo->padre;
pNodo P = nodo;
pNodo Q = P->izquierdo;
pNodo B = Q->derecho;
if (Padre)
if (Padre->derecho == P) Padre->derecho = Q;
else Padre->izquierdo = Q;
else *a = Q;
/* Reconstruir árbol: */
P->izquierdo = B;
Q->derecho = P;
/* Reasignar padres: */
P->padre = Q;
if (B) B->padre = P;
Q->padre = Padre;
/* Ajustar valores de FE: */
P->FE = 0;
Q->FE = 0;
}
/* Rotación simple a izquierdas */
void RSI(Arbol *a, pNodo nodo)
{
pNodo Padre = nodo->padre;
pNodo P = nodo;
pNodo Q = P->derecho;
pNodo B = Q->izquierdo;
if (Padre)
if (Padre->derecho == P) Padre->derecho = Q;
else Padre->izquierdo = Q;
else *a = Q;
/* Reconstruir árbol: */
P->derecho = B;
Q->izquierdo = P;
/* Reasignar padres: */
P->padre = Q;
if (B) B->padre = P;
Q->padre = Padre;
/* Ajustar valores de FE: */
P->FE = 0;
Q->FE = 0;
}
/* Comprobar si un árbol es vacío */
int Vacio(Arbol r)
{
return r == NULL;
}
答案 0 :(得分:0)
昨天晚上和晚上我正在进行一些cudaMallocManaged(...)测试,之前我认为统一内存正在使用设备内存,当设备内存空间不足时,他们开始使用主机内存。 / p>
这不是这样的,使用CUDA 6 cudaMallocManaged(...)的统一内存系统,我们只能分配与设备一样多的内存。
非常感谢ArchaeaSoftware的回答
感谢全民阅读,我希望你们所有人尽可能多地享受CUDA 很快见到你们。 曼努埃尔