2013-07-11 6 views
1

Как передать список строк в ядро ​​opencl правильным способом?Как передать список строк в ядро ​​opencl с помощью pyopencl?

Я пробовал этот способ с использованием буферов (см. Следующий код), но мне не удалось.

OpenCL (struct.cl):

typedef struct{ 
      uchar uc[40]; 
} my_struct9; 

inline void try_this7_now(__global const uchar * IN_DATA , 
          const uint IN_len_DATA , 
          __global uchar * OUT_DATA){ 
    for (unsigned int i=0; i<IN_len_DATA ; i++) OUT_DATA[i] = IN_DATA[i]; 
} 

__kernel void try_this7(__global const my_struct9 * pS_IN_DATA , 
         const uint IN_len , 
         __global my_struct9 * pS_OUT){ 

    uint idx = get_global_id(0); 
for (unsigned int i=0; i<idx; i++) try_this7_now(pS_IN_DATA[i].uc, IN_len, pS_OUT[i].uc); 
    } 

Python (opencl_struct.py):

# -*- coding: utf-8 -*- 

import pyopencl as cl 
import pyopencl.array as cl_array 
import numpy 

ctx = cl.create_some_context() 
queue = cl.CommandQueue(ctx) 
# -------------------------------------------------------- 
LIMIT = 40 
mf = cl.mem_flags 

import ctypes,sys,struct 
""" 
typedef struct{ 
      uchar uc[40]; 
} my_struct9; 
""" 
INlist = [] 
INlist.append("That is VERY cool!") 
INlist.append("It is a list!") 
INlist.append("A big one!") 
#INlist.append("But it failes to output. :-(") # PLAY WITH THOSE 
INlist.append("WTF is THAT?") # PLAY WITH THOSE 
print "INlist : "+str(INlist) 
print "largest string "+str(max(len(INlist[iL]) for iL in range(len(INlist)))) 
strLIMIT=str(LIMIT) 
s7 = struct.Struct( (str(strLIMIT+'s') *len(INlist))) 
IN_host_buffer = ctypes.create_string_buffer(s7.size) 
s7.pack_into(IN_host_buffer, 0, *INlist) 
IN_dev_buffer = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=IN_host_buffer) 

OUT_host_buffer = ctypes.create_string_buffer(s7.size) 

OUT_dev_buffer = cl.Buffer(ctx, mf.WRITE_ONLY, len(OUT_host_buffer)) 
print "> len(OUT_host_buffer) "+str(len(OUT_host_buffer)) 

# ======================================================================================== 
f = open("struct.cl", 'r') 
fstr = "".join(f.readlines()) 
prg = cl.Program(ctx, fstr).build() 

#cl.enqueue_copy(queue, IN_dev_buffer, IN_host_buffer, is_blocking=True) # copy data to device 
cl.enqueue_write_buffer(queue, IN_dev_buffer, IN_host_buffer).wait() 

prg.try_this7(queue, (1,), None, IN_dev_buffer, numpy.uint32(LIMIT), OUT_dev_buffer) 
# ======================================================================================== 
cl.enqueue_copy(queue, OUT_host_buffer, OUT_dev_buffer).wait() 

SSS = s7.unpack_from(OUT_host_buffer,0) 

# unpack here OUT_host_buffer 
print "(GPU) output : "+str(SSS)+" " 

for s in range(len(SSS)): 
print ">>> (GPU) output : "+str(SSS[s]) 

Я побежал программу первый раз с "но failes к выходу" в качестве 4-го элемента списка , Затем я играл, увеличивая и уменьшая элементы списка. И, наконец, появилась такая проблема: Выход программы должен быть (короткая версия)

(GPU) выход: Это очень здорово!

(GPU) output: Это список!

(GPU) мощность: большой!

(GPU) мощность: WTF это?

Но:

питон opencl_struct.py

INlist: [ '! Это очень круто', '! Это список', «Большой!», «WTF is THAT?»]

наибольшая строка 18

Выход len (OUT_host_buffer) 160 (GPU): («Это ОЧЕНЬ круто! \ X00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 ', ' Это список ! \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \, 'Большой один! \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00' , 'Но это не позволяет выводить. : - (\ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00')

(GPU) выход: Это очень здорово!

(GPU) output: Это список!

(GPU) мощность: большой!

(GPU) выход: но он не подходит для вывода.:-(

Как вы видите, на 4-й differes список элементов.

Так, может быть, мой подход является неправильным или есть ошибка в pyopencl или где-нибудь еще.

Я использую NVidia 9400 GPU.

Рэмбо

ответ

1

Код мне кажется очень сложным. И какая-то часть мне не очень понятна. Например, я не понимаю, почему вы создаете только один рабочий элемент:

prg.try_this7(queue, (1,), None,...) 

, которые заставляют вас перебрать ваши строки (в ядре), вместо того, чтобы использовать доступный параллелизм. Во всяком случае, если я хорошо понимаю, вы хотите отправить несколько строк на GPU, скопировав их в другой буфер, вернуть их на стороне хоста и отобразить их.

Если это так вот версия с использованием только NumPy и конечно pyopencl:

import numpy as np 
import pyopencl as cl 


ctx = cl.create_some_context() 
queue = cl.CommandQueue(ctx) 
#The kernel uses one workitem per char transfert 
prog_str = """kernel void foo(global char *in, global char *out, int size){ 
        int idx = get_global_id(0); 
        if (idx < size){ 
         out[idx] = in[idx]; 
        } 
      }""" 
prog = cl.Program(ctx, prog_str).build() 
#Note that the type of the array of strings is '|S40' for the length 
#of third element is 40, the shape is 3 and the nbytes is 120 (3 * 40) 
original_str = np.array(('this is an average string', 
         'and another one', 
         "let's push even more with a third string")) 
mf = cl.mem_flags 
in_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=original_str) 
out_buf = cl.Buffer(ctx, mf.WRITE_ONLY, size=str_size) 
copied_str = np.zeros_like(original_str) 
#here launch the kernel with str_size number of workitems in this case 120 
#this mean that some of the workitems won't process any meaningful char 
#(not all string have a lenght of 40) but it's no biggie 
prog.foo(queue, (str_size,), None, in_buf, out_buf, np.int32(str_size)) 
cl.enqueue_copy(queue, copied_str, out_buf).wait() 
print copied_str 

И отображаемый результат:

['this is an average string' 'and another one' 
"let's push even more with a third string"] 

 Смежные вопросы

  • Нет связанных вопросов^_^