2012-09-14 35 views
11

Tôi mới tham gia C, C++ và OpenCL và cố hết sức để tìm hiểu họ vào lúc này. Đây là một hàm C++ có từ trước mà tôi đang cố gắng tìm ra cách chuyển sang OpenCL bằng cách sử dụng các ràng buộc C hoặc C++.Làm thế nào để vượt qua và truy cập C++ vectơ để OpenCL hạt nhân?

#include <vector> 

using namespace std; 

class Test { 

private: 

    double a; 
    vector<double> b; 
    vector<long> c; 
    vector<vector<double> > d; 

public: 

    double foo(long x, double y) { 
     // mathematical operations 
     // using x, y, a, b, c, d 
     // and also b.size() 
     // to calculate return value 
     return 0.0; 
    } 

}; 

Câu hỏi chung của tôi là cách chuyển tất cả các thành viên lớp mà hàm này truy cập vào liên kết và hạt nhân. Tôi hiểu làm thế nào để vượt qua trong các giá trị vô hướng nhưng các giá trị vector tôi không chắc chắn về. Có lẽ có một cách để vượt qua trong con trỏ đến mỗi thành viên trên hoặc bộ nhớ bản đồ chúng để xem OpenCL của họ là đồng bộ với bộ nhớ máy chủ? Chia nhỏ câu hỏi của tôi như sau.

  1. Làm cách nào để chuyển thành viên b và c vào phần ràng buộc và hạt nhân được cho rằng chúng có kích thước khác nhau?
  2. Làm cách nào để vượt qua thành viên d cho rằng đó là hai chiều?
  3. Làm cách nào để truy cập các thành viên này từ bên trong hạt nhân và chúng sẽ được khai báo như thế nào trong các đối số cho hạt nhân? Chỉ đơn giản là sử dụng ký hiệu chỉ mục mảng tức là b [0] làm việc để truy cập?
  4. Làm cách nào để gọi một phép toán tương đương với b.size() trong hàm hạt nhân hoặc tôi sẽ không thay vì chuyển kích thước từ ràng buộc vào hạt nhân dưới dạng đối số thừa không? Điều gì xảy ra nếu nó thay đổi?

Tôi thực sự sẽ đánh giá cao mã nguồn ví dụ về mã ràng buộc và mã nguồn của C hoặc C++ trong câu trả lời.

Rất cám ơn.

+10

'using namespace std;' - Đừng làm điều đó trong tiêu đề, bao giờ hết. –

+0

@EdS. tại sao lại như vậy? – dominicbri7

+5

@ dominicbri7: Vì bạn đang gây ô nhiễm không gian tên chung cho tất cả những người bao gồm tiêu đề của bạn. Có lẽ tôi không muốn 'std' được nhập vào không gian tên chung của tôi. Có lẽ có lý do chính đáng cho điều đó. Bạn không và đã lựa chọn cho tôi. –

Trả lời

13
  1. Bạn phải cấp phát bộ đệm OpenCL và sao chép dữ liệu CPU vào đó. Một bộ đệm OpenCL có kích thước cố định, vì vậy bạn phải tạo lại kích thước nếu kích thước dữ liệu của bạn thay đổi hoặc bạn làm cho nó đủ lớn và chỉ sử dụng một phần phụ của bộ nhớ nếu cần ít bộ nhớ hơn. Ví dụ, để tạo ra một bộ đệm cho b và đồng thời sao chép tất cả dữ liệu của mình cho các thiết bị:

    cl_mem buffer_b = clCreateBuffer(
        context, // OpenCL context 
        CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, // Only read access from kernel, 
                  // copy data from host 
        sizeof(cl_double) * b.size(), // Buffer size in bytes 
        &b[0], // Pointer to data to copy 
        &errorcode); // Return code 
    

    Nó cũng có thể trực tiếp lập bản đồ bộ nhớ máy chủ (CL_MEM_USE_HOST_PTR), nhưng điều này áp đặt một số hạn chế về căn chỉnh và truy cập vào bộ nhớ máy chủ sau khi tạo bộ đệm. Về cơ bản, bộ nhớ máy chủ có thể chứa rác khi bạn hiện không ánh xạ nó.

  2. Điều đó tùy thuộc. Các kích thước của vectơ trong chiều thứ hai có đồng đều không? Sau đó, chỉ cần san bằng chúng khi tải chúng lên thiết bị OpenCL. Nếu không thì nó trở nên phức tạp hơn.

  3. Bạn khai báo đối số bộ đệm là __global con trỏ trong hạt nhân của bạn. Ví dụ, __global double *b sẽ là thích hợp cho bộ đệm được tạo trong 1. Bạn có thể chỉ cần sử dụng ký pháp mảng trong hạt nhân để truy cập các phần tử riêng lẻ trong bộ đệm.

  4. Bạn không thể truy vấn kích thước bộ đệm từ bên trong hạt nhân, vì vậy bạn phải chuyển nó theo cách thủ công. Điều này cũng có thể xảy ra hoàn toàn, ví dụ: nếu số lượng mục công việc phù hợp với kích thước của b.

Một hạt nhân có thể truy cập vào tất cả các dữ liệu cho việc tính toán có thể trông như thế này:

__kernel void foo(long x, double y, double a, __global double* b, int b_size, 
        __global long* c, __global double* d, 
        __global double* result) { 
    // Here be dragons 
    *result = 0.0; 
} 

Lưu ý rằng bạn cũng phải phân bổ bộ nhớ cho kết quả. Nó có thể là cần thiết để vượt qua các đối số kích thước bổ sung nếu bạn cần chúng. Bạn sẽ gọi hạt nhân như sau:

// Create/fill buffers 
// ... 

// Set arguments 
clSetKernelArg(kernel, 0, sizeof(cl_long), &x); 
clSetKernelArg(kernel, 1, sizeof(cl_double), &y); 
clSetKernelArg(kernel, 2, sizeof(cl_double), &a); 
clSetKernelArg(kernel, 3, sizeof(cl_mem), &b_buffer); 
cl_int b_size = b.size(); 
clSetKernelArg(kernel, 4, sizeof(cl_int), &b_size); 
clSetKernelArg(kernel, 5, sizeof(cl_mem), &c_buffer); 
clSetKernelArg(kernel, 6, sizeof(cl_mem), &d_buffer); 
clSetKernelArg(kernel, 7, sizeof(cl_mem), &result_buffer); 
// Enqueue kernel 
clEnqueueNDRangeKernel(queue, kernel, /* ... depends on your domain */); 

// Read back result 
cl_double result; 
clEnqueueReadBuffer(queue, result_buffer, CL_TRUE, 0, sizeof(cl_double), &result, 
        0, NULL, NULL); 
+0

Cảm ơn bạn rất nhiều reima. Điều đó giúp ích rất nhiều. Hai câu hỏi: (1) dữ liệu gốc của tôi là tất cả trong các loại C++ như bạn biết. Nhưng tất cả các cấp phát bộ nhớ trong mã của bạn ở trên là trong cl_types. Tôi hiểu tại sao. Nhưng, trong một chương trình thử nghiệm, nơi tôi truyền hai vectơ dài vào một hạt nhân để thêm giá trị tại [0] đến b [1], điều này chỉ hoạt động nếu tất cả các kiểu là cl_types trong chương trình bao gồm các khai báo vector gốc có vẻ lạ dữ liệu gốc phải là kiểu C++. Tôi đang thiếu gì ở đây? (2) Làm thế nào để sử dụng 'kết quả' như một loại C++ ở trên? – junkie

+2

Bạn nói đúng, tôi hơi cẩu thả với những loại đó. Mã ví dụ của tôi sẽ chỉ hoạt động nếu 'cl_long' có cùng kiểu với' long'. Nếu không giống nhau, có thể bạn sẽ phải thực hiện bước chuyển đổi trước khi tải dữ liệu lên thiết bị. 'cl_long' và' cl_double' là các kiểu C++ giống như bất kỳ loại nào khác, chúng chỉ là typedef. Bạn có thể sử dụng 'result' trực tiếp, vì nó có lẽ đã là' double'. – reima

+0

Thx. Tôi có thể xác nhận rằng trong chương trình thử nghiệm của mình, việc sử dụng con trỏ tới vector dữ liệu không hoạt động. Vì vậy, có thể chuyển đổi cần thiết (tạo ra bộ thứ hai của vectơ/mảng và sao chép vào nó?) Và thiết lập kết quả thành một biến dài cho một cảnh báo trong VS nói rằng "có thể mất dữ liệu". cl_long trong cl_platform.h được đặt thành 'typedef signed __int64 cl_long;' trong khi dài là 4 byte. Vì vậy, có thể không có cách nào để sử dụng lâu dài mà không mất dữ liệu? – junkie

Các vấn đề liên quan