以下是科研实习第四周的进度

代码修正

在上周的演示中,主要使用了Jacobi迭代法对拉普拉斯方程进行了求解,但是经过测试,在较为复杂的边界条件上,Jacobi法迭代速度较慢甚至过慢,需要很长的时间才能得到解。

对此进行分析,对于这样的一个PDE,使用有限差分法我们很容易将其写成一个线性方程组,对于一个100 * 100 的拉普拉斯方程,其对应的线性方程组具有100*100*100*100的矩阵,有限差分法需要从边界向中心迭代,在开启并行的情况下,中心部分可能需要很多个Epoch才能发生变化。

因此对于大型矩阵,我们一方面可以采用迭代速度更快的G-S迭代法以及松弛系数在1-2的松弛迭代法,另一方面,考虑到拉普拉斯方程对应的系数矩阵是一个非常稀疏的矩阵,我们可以采用稀疏矩阵的求解法对其进行求解。

下面使用基于Givens旋转的QR分解对拉普拉斯方程进行求解(非稀疏矩阵特化,稀疏矩阵特化与另外一个同学讨论并进行实验,目前仍旧存在一些问题,因此求解较慢,使用规模较小的网格)

Unit Test

我们使用 Boost.ut 进行单元测试,具体测试代码如下所示

vector<double> x = solve_linear_system(A,b);
"Serial"_test = [&]{
    for (int i = 0; i < 400; ++i) {
        expect(fabs(x[i]-1<1e-6));
    }
};
x = solve_linear_system_omp(A,b);
"OpenMP"_test = [&]{
    for (int i = 0; i < 400; ++i) {
        expect(fabs(x[i]-1<1e-6));
    }
};
x = solve_linear_system_cu(A,b);
"CUDA"_test = [&]{
    for (int i = 0; i < 400; ++i) {
        expect(fabs(x[i]-1<1e-6));
    }
};

输出结果为:

Suite 'global': all tests passed (1200 asserts in 3 tests)

注:由于并行度不高,CUDA的优化大多不是来源于并行,而是显卡本身对数组的操作速率高于CPU

注:CUDA运行的结果不稳定,原因可能是具有访址冲突,但是Debug过程中存在一定的修复问题,因此还未完全修复

Benchmark

我们使用NanoBench对代码进行性能测试,我们采用的方式是对一个代码连续运行20次取其平均效果,代码如下:

Bench().run("Serial",[&]{
    vector<vector<double>> A_temp(A);
    vector<double> b_temp(b);
    solve_linear_system(A_temp,b_temp);
});
Bench().run("OpenMP",[&]{
    vector<vector<double>> A_temp(A);
    vector<double> b_temp(b);
    solve_linear_system_omp(A_temp,b_temp);
});
Bench().run("CUDA",[&]{
    vector<vector<double>> A_temp(A);
    vector<double> b_temp(b);
    solve_linear_system_cu(A_temp,b_temp);
});

其输出结果如下:

|               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|    2,454,934,332.00 |                0.41 |    0.1% |9,020,857,795.00 |5,620,531,896.00 |  1.605 |1,152,369,662.00 |    0.0% |     27.12 | `Serial`
|    1,411,725,552.00 |                0.71 |    0.7% |2,779,103,816.00 |3,232,946,976.00 |  0.860 | 500,965,126.00 |    3.5% |     15.48 | `OpenMP`
|       51,278,734.00 |               19.50 |    0.2% |  149,190,381.00 |  117,345,448.00 |  1.271 |  27,837,262.00 |    6.0% |      0.74 | `CUDA`