Intro

gpu_buffer è, come evidenziato nel nome, il gestore di un buffer di memoria per i/o su una GPU;  appartiene al gruppo delle classi derivate da  gpu_mem_obj, e gestisce un blocco di memoria assegnata ad un context OpenCL. Come tutte le altre classi del namespace OPCL  è stata progettata per semplificare l’uso delle API OpenCL.  In sintesi, gpu_buffer è la classe che gestisce la corrispondenza fra un blocco di memoria su CPU ed il suo i/o sulle GPU gestite dalle API OpenCL. nascondendo al programmatore tutte le complessità legate a queste operazioni.

	class AFX_EXT_CLASS gpu_buffer : public gpu_mem_object
	{
	public:
		gpu_buffer ( );
		~gpu_buffer ( );

		bool Init ( class gpu_kernel *kernel, cl_uint memsize, cl_mem_flags mode = CL_MEM_READ_ONLY, void *host_buf=0 );
		void *Ptr ( );
		size_t Bytes ( );

		bool Push_kernel(gpu_kernel *kernel = 0);

		__use_private_struct
	};

void *Ptr() e size_t Bytes()

le due funzioni Ptr() e Bytes() rimandano il puntatore della memoria host  e le dimensioni della memoria allocata. La memoria host è allocata sulla CPU e può essere definita esternamente alla classe GPU, assegnando il puntatore attraverso la funzione gpu_buffer::Init, o allocata automaticamente nella gpu_buffer, ed accedendovi attraverso la funzione Ptr().  di seguito, in questo articolo, vedremo come ( e perchè) utilizzare questi due diversi metodi di allocazione.

La classe contiene un puntatore alla memoria allocata su CPU, e nasconde un corrispondente handle OpenCL cl_mem definito attraverso la funzione OpenCL clCreateBuffer:  l’handle cl_mem è accessibile mediante la funzione Get_id () ereditata da gpu_mem_object, ma non sarà mai necessario utilizzare informazioni e funzioni OpenCL direttamente, a meno che non si debba costruire nuove classe del namespace OPCL,

bool Init()

La prima cosa da notare è il primo parametro della funzione , gpu_kernel *kernel; ciò può apparire strano a  chi ha dimestichezza con  le API OpenCL, poiché la memoria è sempre  gestita su un context, ed in seguito eventualmente passata ad un kernel eseguito su GPU: poichè un kernel è sempre associato ad un programma , a sua volta associato ad un context, è evidente  che l’associazione fra gpu_buffer e context è eseguito nella Init in modo completamente nascosto. Vedremo che questa scelta non comporta alcuna limitazione alla programmazione, anzi semplifica l’interfaccia di programmazione.

Il secondo parametri della funzione è memsize, cioè la dimensione del buffer host da gestire; in un prossimo articolo sulla creazione di nuove classi derivate da gpu_buffer vedremo che questo parametro, per un uso particolare è passato a o, e ne analizzeremo il significato; per l’uso standard invece memsize deve essere >0;

il terzo parametro cl_mem_flags mode è uno dei tipi numerali di OpenCL, e definisce il tipo di trattamento che del buffer dovrà fare l’API OpenCL; i valori possibili sono

CL_MEM_READ_WRITE 
CL_MEM_WRITE_ONLY 
CL_MEM_READ_ONLY 
CL_MEM_USE_HOST_PTR 
CL_MEM_ALLOC_HOST_PTR 
CL_MEM_COPY_HOST_PTR

Per un’approfondimento del significato di questi valori leggere qui.

Il quarto ed ultimo parametro è host_buf, un puntatore alla memoria che definisce la memoria allocata sulla CPU da associare alla host_buf  lato GPU;

Una particolarità di questo parametro è che può essere passato con valore 0; In questo caso la funzione Init procede all’allocazione di un buffer di memsize byte; L’accesso al buffer sarà successivamente effettuato utilizzando il puntatore restituito dalla funzione Ptr() per inizializzare il suo contenuto; In questo caso la distruzione del buffer sarà effettuata dal distruttore del gpu_buffer quando chiamata la funzione gpu_kernel::FlushMemObjects

bool Push_kernel()

La funzione è virtuale ed in genere ridefinita per le classi derivate da gpu_buffer; attraverso questa funzione viene trasferita l’informazione organizzata nella gpu_buffer (o classi derivate) nella queue dei parametri del kernel. In genere non è necessario ridefinire il kernel, in quanto già assegnato nella funzione Init(); tuttavia è possibile passare gli stessi dati ad un kernel aggiuntivo da eseguire in parallelo o in sequenza con quello di default;

Compiti svolti da Push_kernel

Per capire come la funzione trasferisca le informazioni nella coda dei parametri del kernel, viene di seguito riportato il codice della funzione di gpu_buffer;

	bool gpu_buffer::Push_kernel(gpu_kernel *kernel)
	{
		__getstr
		_test_alt_kernel		
		return
		(
			kernel->PushArg(this) &&
			kernel->PushArg(_$str->bytes)		// numero di byte inseriti
		);
	}

la macro _test_alt_str permette di assegnare un kernel alternativo, eventualmente passato alla funzione, e la sua discussione non serve a questa esposizione; la riga kernel->Push(arg) trasferisce il buffer allocato in gpu_buffer (quello ottenibile dalla funzione gpu_buffer::Ptr() sulla coda dei parametri del kernel; con metodo simile le dimensioni del buffer sono aggiunte alla coda come secondo parametro;

Pages: 1 2
Skip to toolbar