团队名称:
西南石油大学:天鹅湖
问题陈述:
组建2个序列(向量)的浮点数,每个序列的规格是N(如N=1024*1024),构成矩阵输入值。用随机值初始化序列。使用缓存和存储来实现对设备(GPU)上矩阵内存的分配并运行。运行SYCL Kernel实现两个矩阵的并行运算,这里你需要运用SYCL nd_range概念来定义Kernel的运行范围。使用SYCL排队系统来运行设备上的Kernel。 Kernel运行结束后,使用存储将结果从设备(GPU)检索回主机。 通过比较主机上的预设结果来验证你的程序是否正确。并且程序中需要使用同意共享内存来实现内存分配和数据转换,从而代替缓存和存储。
软硬件设施:
使用英特尔oneAPI Developer Cloud平台
[opencl:cpu:0] Intel(R) OpenCL, Intel(R) Xeon(R) E-2176G CPU @ 3.70GHz 3.0
[2023.16.7.0.21_160000] [opencl:gpu:1] Intel(R) OpenCL HD Graphics, Intel(R) UHD Graphics P630 [0x3e96] 3.0 [22.43.24595.35]
[ext_oneapi_level_zero:gpu:0] Intel(R) Level-Zero, Intel(R) UHD Graphics P630 [0x3e96] 1.3 [1.3.24595]
实现方案:
使用qsub命令提交run.sh到指定队列完成任务
run.sh内容:(./a.out后紧接着的是矩阵的宽度)
我们使用两种方法来完成统一共享内存的分配 一种是使用malloc_shared隐式数据移动另一种是使用malloc_device显示数据移动。
隐式数据移动:
使用malloc_shared的USM的实现,其中数据在主机和设备之间隐式地移动。可以用最少的代码快速获得功能,开发人员不必担心在主机和设备之间移动内存。
数据初始化为一百以内的随机数:
使用nd_range概念来定义Kernel的运行范围:
测试数据为五组 每组N的大小为64、128、256、512、1024
测试结果如下:单位:ms
显示数据移动:
使用malloc_device的USM实现,其中主机和设备之间的数据移动应该由开发人员使用memcpy显式地完成。这允许开发人员在主机和设备之间进行更可控的数据移动。
使用nd_range概念来定义Kernel的运行范围:
内核计算完毕后需要将数据从device上拷贝回host:
测试数据为五组 每组N的大小为64、128、256、512、1024
测试结果如下:单位:ms
注:测试时间为一千次运行取平均值。
总结:
隐式数据移动情况下,对于小规模矩阵,GPU 的性能相对较好,但随着矩阵大小增加,GPU 相对于 CPU 的性能提升逐渐减缓。显示数据移动情况下,GPU 的性能在中等大小的矩阵上相对较好,但在较小和较大矩阵上可能不如 CPU。这是因为显示数据移动涉及显式地将数据从主机(CPU)传输到设备(GPU)。在大规模矩阵上,GPU 的性能提升可能会受到内存传输带宽等因素的限制,导致相对较慢的性能。选择隐式数据移动还是显示数据移动取决于问题的特定要求以及矩阵的大小。在一些情况下,可能需要根据输入规模动态选择使用哪种数据移动方式以优化性能。
总体而言,OneAPI 的 USM是一项强大的技术,为异构编程提供了灵活性和性能优化的可能性并且USM 的设计理念使得代码可以更容易地在不同硬件架构上运行,为异构计算提供了一致的编程接口。对于那些需要在 CPU 和 GPU 上进行异构编程的开发者来说,USM 提供了一种更简单和直观的方式来管理内存和任务分发,降低了编程的复杂度。
github链接:GitHub - dxf2003/usm_matrix-multiplication: Shared memory matrix multiplication using oneapi