基于oneAPI的C++/SYCL程序来执行矩阵乘法

OneAPI

OneAPI是英特尔提供的一个综合性编程模型和工具集,旨在简化并行计算的开发和优化。它提供了一致的编程接口和工具,使开发者能够在不同的硬件架构上编写高性能并行代码。

实验

DPC++是oneAPI工具集中基于C++的的一种编程模型,提供了对并行计算的支持,本实验采用DPC++编程模型来加速矩阵乘法。

传统的矩阵乘法

代码如下,时间较高

#include <chrono>
#include <iostream>
#include <random>
#include <vector>

// 定义矩阵的大小
const int matrix_size = 100;

// 生成随机矩阵
std::vector<std::vector<double>> generateRandomMatrix(int rows, int cols)
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<double> dis(0.0, 1.0);

    std::vector<std::vector<double>> matrix(rows, std::vector<double>(cols));
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            matrix[i][j] = dis(gen);
        }
    }

    return matrix;
}

// 计算矩阵乘法
std::vector<std::vector<double>> matrixMultiply(const std::vector<std::vector<double>> &matrix1, const std::vector<std::vector<double>> &matrix2)
{
    int rows1 = matrix1.size();
    int cols1 = matrix1[0].size();
    int cols2 = matrix2[0].size();

    std::vector<std::vector<double>> result(rows1, std::vector<double>(cols2));

    for (int i = 0; i < rows1; ++i) {
        for (int j = 0; j < cols2; ++j) {
            double sum = 0.0;
            for (int k = 0; k < cols1; ++k) {
                sum += matrix1[i][k] * matrix2[k][j];
            }
            result[i][j] = sum;
        }
    }

    return result;
}

int main()
{
    // 生成随机矩阵
    std::vector<std::vector<double>> matrix1 = generateRandomMatrix(matrix_size, matrix_size);
    std::vector<std::vector<double>> matrix2 = generateRandomMatrix(matrix_size, matrix_size);

    // 进行1000次随机矩阵乘法并计时
    auto start_time = std::chrono::high_resolution_clock::now();
    int total_iterations = 1000;
    int progress_interval = total_iterations / 100; // 计算进度的显示间隔
    for (int i = 0; i < total_iterations; ++i) {
        std::vector<std::vector<double>> result = matrixMultiply(matrix1, matrix2);
        if ((i + 1) % progress_interval == 0) {
            // 清屏后显示
            std::cout << "\033[2J\033[1;1H";
            double progress = (static_cast<double>(i + 1) / total_iterations) * 100;
            std::cout << "进度: " << progress << "%" << std::endl;
        }
    }
    auto end_time = std::chrono::high_resolution_clock::now();

    // 计算总时间(以秒为单位)
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
    double total_time = duration.count() / 1000.0;

    // 打印结果
    std::cout << "总时间: " << total_time << "秒" << std::endl;

    return 0;
}


该算法实现了一个随机矩阵乘法算法,并计时执行1000次矩阵乘法的时间。下面是算法的思路:

首先定义了一个常量matrix_size,表示矩阵的大小,这里设定为100。

generateRandomMatrix函数用于生成一个指定大小的随机矩阵。它使用了C++的随机数发生器库,通过调用random_device来获取真随机数种子,然后使用mt19937引擎和uniform_real_distribution分布来生成0到1之间的随机数,并将它们填充到一个二维向量中。

matrixMultiply函数实现了矩阵乘法操作。它接受两个二维向量matrix1和matrix2作为输入,并返回它们的乘积矩阵。函数中使用了三个嵌套的循环来遍历矩阵元素进行乘法运算,并将结果保存在result矩阵中。

main函数是程序的入口。首先使用generateRandomMatrix函数生成两个随机矩阵matrix1和matrix2。

然后开始执行1000次随机矩阵乘法,并计时。使用high_resolution_clock来获取当前时间,记录开始时间。接下来的循环中,调用matrixMultiply函数计算乘积矩阵,并根据进度间隔显示计算进度。在每次更新进度时,使用特殊的控制字符"\033[2J\033[1;1H"实现清屏,并打印当前进度。

循环结束后,再次获取当前时间,记录结束时间。通过计算时间差,得到总时间,并将其转换为秒为单位。

最后,打印总时间。
运行结果如图所示

使用OneAPI加速的矩阵运算

#include <CL/sycl.hpp>
#include <iostream>
#include <random>
#include <vector>

// 定义矩阵的大小
const int matrix_size = 100;

// 生成随机矩阵
std::vector<std::vector<double>> generateRandomMatrix(int rows, int cols)
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<double> dis(0.0, 1.0);

    std::vector<std::vector<double>> matrix(rows, std::vector<double>(cols));
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            matrix[i][j] = dis(gen);
        }
    }

    return matrix;
}

// 计算矩阵乘法
std::vector<std::vector<double>> matrixMultiply(const std::vector<std::vector<double>> &matrix1, const std::vector<std::vector<double>> &matrix2)
{
    int rows1 = matrix1.size();
    int cols1 = matrix1[0].size();
    int cols2 = matrix2[0].size();

    std::vector<std::vector<double>> result(rows1, std::vector<double>(cols2));

    // 使用 SYCL 编程模型
    {
        // 创建 SYCL 的队列和设备选择器
        sycl::queue queue(sycl::gpu_selector_v);

        // 创建输入和输出缓冲区

        cl::sycl::buffer<double, 2> buffer1(matrix1.data()->data(), cl::sycl::range<2>(rows1, cols1));
        cl::sycl::buffer<double, 2> buffer2(matrix2.data()->data(), cl::sycl::range<2>(cols1, cols2));
        cl::sycl::buffer<double, 2> buffer_result(result.data()->data(), cl::sycl::range<2>(rows1, cols2));

        // 提交 SYCL 的计算任务
        queue.submit([&](cl::sycl::handler &cgh) {
            auto accessor1 = buffer1.get_access<cl::sycl::access::mode::read>(cgh);
            auto accessor2 = buffer2.get_access<cl::sycl::access::mode::read>(cgh);
            auto accessor_result = buffer_result.get_access<cl::sycl::access::mode::write>(cgh);

            cgh.parallel_for<class MatrixMultiplyKernel>(cl::sycl::range<2>(rows1, cols2), [=](cl::sycl::item<2> item) {
                int i = item[0];
                int j = item[1];
                double sum = 0.0;
                for (int k = 0; k < cols1; ++k) {
                    sum += accessor1[i][k] * accessor2[k][j];
                }
                accessor_result[i][j] = sum;
            });
        });

        // 同步等待计算任务完成
        queue.wait_and_throw();
    }

    return result;
}

int main()
{
    // 生成随机矩阵
    std::vector<std::vector<double>> matrix1 = generateRandomMatrix(matrix_size, matrix_size);
    std::vector<std::vector<double>> matrix2 = generateRandomMatrix(matrix_size, matrix_size);

   
    auto start_time = std::chrono::high_resolution_clock::now();
    int total_iterations = 1000;
    int progress_interval = total_iterations / 100; // 计算进度的显示间隔
    for (int i = 0; i < total_iterations; ++i) {
        std::vector<std::vector<double>> result = matrixMultiply(matrix1, matrix2);
        if ((i + 1) % progress_interval == 0) {
            // 清屏后显示
            std::cout << "\033[2J\033[1;1H";
            double progress = (static_cast<double>(i + 1) / total_iterations) * 100;
            std::cout << "进度: " << progress << "%" << std::endl;
        }
    }
    auto end_time = std::chrono::high_resolution_clock::now();

    // 计算总时间(以秒为单位)
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
    double total_time = duration.count() / 1000.0;

    // 打印结果
    std::cout << "总时间: " << total_time << "秒" << std::endl;

    return 0;
}


在上述代码中,首先使用了queue来创建一个执行队列。
然后使用sycl::handler和sycl::parallel_for来创建并行执行的内核函数。
在内核函数中,使用并行迭代遍历矩阵的每个元素,并使用累加求和的方式计算矩阵乘法的结果。实现并行加速效果。
运行结果

总结

通过使用英特尔的oneAPI工具中的DPC++编程模型,我们可以方便地利用并行计算资源来加速矩阵乘法的计算。DPC++提供了一致的编程接口和工具,使开发者能够简化并行计算的开发和优化过程。

对于矩阵乘法算法,我们可以通过将计算任务分配给不同的计算设备(如CPU和GPU),并同时利用它们的并行计算能力来加速计算。通过并行化矩阵乘法的计算过程,可以同时处理多个矩阵元素的乘法和求和操作,从而大幅提高计算性能。
通过合理地使用DPC++中的并行编程模型和相关工具,可以针对不同的硬件设备进行优化,充分发挥它们的计算潜力。这样一来,我们可以有效地加速科学计算和数据处理任务,提高计算效率,并在更短的时间内完成复杂的计算任务。

  • 18
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值