Lưu ý rằng thực tế có hai loại. Bạn có CL_MEM_READ_ONLY
, CL_MEM_WRITE_ONLY
và CL_MEM_READ_WRITE
khi phân bổ bộ đệm nhưng sau đó bạn cũng có __read_only
, __write_only
và __read_write
để trang trí con trỏ của bạn bằng mã hạt nhân.
Đây có thể được sử dụng cho cả việc tối ưu hóa và kiểm tra lỗi. Hãy xem hiệu suất trước. Nếu một bộ đệm chỉ ghi được gặp phải, việc ghi không cần phải được lưu trữ (như trong ghi thông qua bộ nhớ đệm), tiết kiệm bộ nhớ cache nhiều hơn cho các lần đọc. Điều này phụ thuộc vào phần cứng GPU rất nhiều và ít nhất là phần cứng NVIDIA có các hướng dẫn cần thiết để thực sự thực hiện điều này (các sửa đổi .cs
và .lu
). Bạn có thể tham khảo PTX ISA của họ. Tôi chưa thấy bất kỳ bằng chứng về trình biên dịch thực sự thực hiện tối ưu hóa này, ví dụ:
__kernel void Memset4(__global __write_only unsigned int *p_dest,
const unsigned int n_dword_num)
{
unsigned int i = get_global_id(0);
if(i < n_dword_num)
p_dest[i] = 0; // this
}
được biên soạn như:
st.global.u32 [%r10], %r11; // no cache operation specified
này có ý nghĩa như CUDA không có tương đương đối với những vòng loại để trình biên dịch rất có thể âm thầm bỏ qua chúng. Nhưng nó không đau khi đặt chúng ở đó, chúng ta có thể may mắn hơn trong tương lai. Trong CUDA, một số chức năng này được tiếp xúc bằng cách sử dụng chức năng __ldg
và bằng cách sử dụng cờ trình biên dịch để chọn tham gia/thoát khỏi bộ nhớ đệm chuyển toàn bộ bộ nhớ trong L1 (-Xptxas -dlcm=cg
). Bạn cũng có thể luôn sử dụng asm
nếu bạn thấy rằng bộ nhớ đệm bỏ qua mang lại lợi thế lớn.
Để kiểm tra lỗi, việc ghi vào bộ đệm chỉ đọc có thể tránh được bằng cách sử dụng thông số const
trong khai báo hạt nhân. Không cho phép đọc từ bộ đệm chỉ ghi trong "C" thuần túy.
Tối ưu hóa khác có thể xảy ra khi ánh xạ các bộ đệm đó để lưu trữ bộ nhớ. Khi ánh xạ bộ đệm CL_MEM_READ_ONLY
, vùng được ánh xạ có thể không được khởi tạo vì máy chủ sẽ chỉ ghi vào bộ nhớ đó, để thiết bị chỉ đọc nó. Tương tự, khi bỏ ánh xạ bộ đệm CL_MEM_WRITE_ONLY
, trình điều khiển không cần phải sao chép nội dung (có thể được sửa đổi bởi máy chủ lưu trữ) từ bộ nhớ máy chủ sang bộ nhớ thiết bị. Tôi không đo lường điều này.
Như một mặt lưu ý, tôi đã cố gắng sử dụng:
inline unsigned int n_StreamingLoad(__global __read_only const unsigned int *p_src)
{
#ifdef NVIDIA
unsigned int n_result;
asm("ld.global.cs.u32 %r0, [%r1];" : "=r" (n_result) : "r" (p_src));
return n_result;
#else // NVIDIA
return *p_src; // generic
#endif // NVIDIA
}
inline void StreamingWrite(__global __write_only unsigned int *p_dest, const unsigned int n_value)
{
#ifdef NVIDIA
asm("st.global.cs.u32 [%r0], %r1;" : : "r" (p_dest), "r" (n_value) : "memory");
#else // NVIDIA
*p_dest = n_value; // generic
#endif // NVIDIA
}
mà cung cấp cho bạn khoảng 15 phụ GB/giây ngay cả trên một hạt nhân memcpy đơn giản với sm_35
thiết bị (thử nghiệm trên GTX 780 và K40). Đã không nhìn thấy tốc độ đáng chú ý trên sm_30
(không chắc chắn nếu nó thậm chí có nghĩa là để được hỗ trợ ở đó - mặc dù các hướng dẫn không bị tước khỏi ptx). Lưu ý rằng bạn cần phải tự xác định NVIDIA
chính mình (hoặc xem Detect OpenCL device vendor in kernel code).