Kopiowanie danych z CPU do GPU [C - CUDA]

0

Witam serdecznie. Mam do wykonania taki o to projekt. Wykonać efekt rozmycia (Blur) na bitmapie na CPU i GPU i porównać szybkość wykonanego algorytmu. Tak jak na CPU mi to działa tak na GPU już nie. Nie wiem dlaczego ale dane odczytane przez CPU z obrazka nie są kopiowane do GPU poprzez funkcję cudaMemcpy. Wstawiam poniżej kod który wykonałem (drobna uwaga, funkcja GPUBlur nie jest jeszcze zrobiona bo szukam pomysłu na jej wykonanie).

#include <iostream>
#include "cuda.h"
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <windows.h>

using namespace std;

BITMAPFILEHEADER BMPH; // 14 bajtowy nagłówek pliku bitmapy
BITMAPINFOHEADER BMPINFOH; // Zawiera informacje na temat wymiarów i kolorów w formacie DIB


// Wczytywanie nagłówka pliku
void ReadFileHeader()
{
	char *filename = "birds.bmp";
	FILE *input = fopen(filename, "rb+");

	if (input == NULL)
	{
		printf("- Plik nie zostal otwarty (Wczytywanie naglowka pliku)\n");
		exit(0);
	}
		printf("- Plik zostal otwarty pomyslnie (Wczytywanie naglowka pliku)\n");

	if (fread(&BMPH, sizeof(BITMAPFILEHEADER), 1, input) != 1) { 
		printf(" Blad w odczycie naglowka bmp\n");
	}

	if (fread(&BMPINFOH, sizeof(BITMAPINFOHEADER), 1, input) != 1) {
		printf(" Blad w odczycie informacji o zdjeciu\n");
	}
	fclose(input);

}

// Pobieranie wartosci RGB do tablicy
void Read_RGB_Array(unsigned char buffer[])
{
	unsigned long int n = BMPINFOH.biWidth*BMPINFOH.biHeight * 3; 
	char *filename = "birds.bmp";
	FILE *input = fopen(filename, "rb+");

	
	fseek(input, BMPH.bfOffBits, SEEK_SET); 

	for (int i = 0; i<n; i++)
	{
		buffer[i] = fgetc(input); 	
	}
	printf("- Odczytano pomyslnie zawartosc danych o obrazie i zapisano do tablicy na CPU\n");
	fclose(input);
}

__global__ void GPUBlur(unsigned char buffer[])
{


	int yi = 512, xi = 768;
	
	//int x = threadIdx.x + blockIdx.x * blockDim.x;
	//int y = threadIdx.y + blockIdx.y * blockDim.y;

	for (int y = 1; y < yi - 1; y++) {
		for (int x = 0; x < xi - 2; x++) {
			for (int c = 0; c < 3; c++) {

 buffer[((y*xi * 3) + (x * 3 + 3)) + c] =
(buffer[(((y - 1)*xi * 3) + (x * 3)) + c] + buffer[(((y - 1)*xi * 3) + (x * 3 + 3)) + c] + buffer[(((y - 1)*xi * 3) + (x * 3 + 6)) + c] +
 buffer[((y*xi * 3) + (x * 3)) + c] + buffer[((y*xi * 3) + (x * 3 + 3)) + c] + buffer[((y*xi * 3) + (x * 3 + 6)) + c] +
 buffer[(((y + 1)*xi * 3) + (x * 3)) + c] + buffer[(((y + 1)*xi * 3) + (x * 3 + 3)) + c] + buffer[(((y + 1)*xi * 3) + (x * 3 + 6)) + c]) / 9;

			}
		}
	}
}

void WriteBMP(unsigned char buffer[])
{
	char *filename = "birds_BLUR.bmp";
	FILE *output = fopen(filename, "wb+");

	if (output == NULL)
	{
		printf("- Plik nie zostal otwarty (Zapisywanie bitmapy do pliku)\n");
		exit(0);
	}
	    printf("- Plik zostal otwarty pomyslnie (Zapisywanie bitmapy do pliku)\n");

	// Zapis nagłówka
	fwrite(&BMPH, 1, sizeof(BMPH), output); 
	// Zapis informacji o pliku
	fwrite(&BMPINFOH, sizeof(BMPINFOH), 1, output);
	// Zapisuje dane obrazu
	fwrite(buffer, 1, BMPINFOH.biWidth*BMPINFOH.biHeight * 3, output);

	fclose(output);

}

int main()
{
    

	int start = GetTickCount(); // Pobiera aktualny czas

	ReadFileHeader();

	unsigned char *buffer_cuda;
	cudaMalloc((void**)&buffer_cuda, BMPINFOH.biWidth*BMPINFOH.biHeight * 3); 

	unsigned char *buffer = (unsigned char*) malloc(BMPINFOH.biWidth*BMPINFOH.biHeight * 3); 
	
	Read_RGB_Array(buffer);	

	cudaMemcpy(buffer_cuda, buffer, BMPINFOH.biWidth*BMPINFOH.biHeight * 3, cudaMemcpyHostToDevice); // Kopiowanie danych CPU --> GPU

	GPUBlur<<<BMPINFOH.biWidth*BMPINFOH.biHeight * 3, 1>>> (buffer); 

	cudaMemcpy(buffer, buffer_cuda, BMPINFOH.biWidth*BMPINFOH.biHeight * 3, cudaMemcpyDeviceToHost);

	WriteBMP(buffer); 

	cudaFree(buffer_cuda); 
	free(buffer); 

	cout << "Czas wykonania kodu aplikacji: " << GetTickCount() - start << "ms." << endl;
	system("pause");
}
 
0

Chodzi o to że jak ustawię breakpoint na linii

 GPUBlur<<<BMPINFOH.biWidth*BMPINFOH.biHeight * 3, 1>>> (buffer); 

to podczas debuggowania w okienku Locals/Autos dla buffer_cuda pokazuje wartość: "buffer_cuda 0x406e0000 < Error reading characters of string. > ".

0

Nie możesz debugować kernel code "zwykłym" debuggerem. Zainstaluj Parallel Nsight.
Poza tym definiuj poprawniej problemy, bo napisałeś, że cudaMemcpy ci nie działa a wychodzi na to, że po prostu nie wiesz jak debugować kernel code.

0

Posiadam NSight. Dokonałem "Start CUDA Debugging" ustawiając pułapkę na tej samej linii. Pokazuje się jakiś błąd na breakpoincie: "The breakpoint will not currently be hit. No CUDA device code is associated with line 83 - EOF". Komunikat ten wyświetla się po najechaniu myszką na breakpoint.

0

Sprawdź czy w opcjach masz włączone generowanie danych debuggera GPU. Sprawdź czy w katalogu z exe masz pliki *.pdb i *.ilk. I najważniejsze sprawdź czy kompilujesz kod z tym samym compute capability, jaki ma twoja karta z cuda.

0

Chyba nie wiem gdzie sprawdzić w opcjach czy jest włączone generowanie danych debuggera GPU :/ . Jeżeli chodzi o pliki *.pdb i *.ilk to są w katalogu w którym znajduje się plik *.exe. Moja karata GTX660M posiada Compute Capability: 3.0. Dobrze patrzę na opcję by sprawdzić czy kompiluje się na tym samym Compute Capability ? : Projekt ->Właściwości Nazwa_Projektu -> CUDA C/C++ -> Device -> Code Generation: compute_20, sm_20 ?

0

W takim razie spróbuj ustawić compute capability na compute_30,sm_30.

0

compute capability zmienione na compute_30,sm_30. Mimo wszystko po wykonaniu "Start CUDA debugging" na NSIGHT nadal pojawia się to samo ostrzeżenie na breakpoincie. Nie debuggowałem nigdy kernel code (pierwszy jakikolwiek projekt związany z CUDA) i nie mam pomysłów jak sprawić bym w końcu mógł sprawdzić czy dane są skopiowane do zaalokowanej pamięci na GPU.

0

No a jak postawisz breakpoint w metodzie kernela i spróbujesz tam zdereferować pointer? Jeśli nie poleci segfault to znaczy, że działa. (Przy okazji sprawdzisz, czy nsight ci działa).

1 użytkowników online, w tym zalogowanych: 0, gości: 1