gpt4 book ai didi

c - MKL 是否为*主要订单优化 cblas?

转载 作者:太空狗 更新时间:2023-10-29 14:58:45 34 4
gpt4 key购买 nike

我正在使用 mkl cblas_dgemm,目前它与 CblasRowMajorCblasNoTransCblasNotrans,用于我的矩阵。

我知道 c 是行主要语言,而 dgemm 是列主要算法。我很想知道如果我链接到 mkl,切换矩阵的顺序是否会对 cblas_dgemm 算法产生任何影响。 mkl 是否足够聪明,可以在幕后做一些我想做的事情来优化矩阵乘法?如果不是,使用 mkl 执行矩阵乘法的最佳方法是什么?

最佳答案

TL;DR:简而言之使用行优先列优先排序执行矩阵-矩阵乘法并不重要使用 MKL(和其他 BLAS 实现)。


I know that c is a row major language, whereas dgemm is a column major algorithm.

DGEMM 不是列优先算法,它是用于计算矩阵与一般矩阵的矩阵乘积的 BLAS 接口(interface)。 DGEMM(和大多数 BLAS)的通用引用实现是 Netlib's这是用 Fortran 语言编写的。它采用列优先排序的唯一原因是因为 Fortran 是一种列优先排序语言。 DGEMM(以及相应的 BLAS Level 3 函数)不是专门用于column-major数据。

DGEMM 计算什么?

基础数学中的 DGEMM 执行二维 matrix-matrix multiplication .标准Order N^3二维矩阵相乘算法要求您沿行遍历一个矩阵,沿列遍历另一个矩阵。要执行矩阵-矩阵乘法,AB = C,我们会将 A 的行乘以 B 产生 C。因此,输入矩阵的顺序无关紧要,因为一个矩阵必须沿其行遍历,另一个矩阵必须沿其列遍历。

使用 MKL 研究行优先和列优先 DGEMM 计算

英特尔 MKL 非常智能,可以在底层利用这一点,并为行优先列优先 数据提供完全相同的性能。

cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, ...);

cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, ...);

将以类似的性能执行。我们可以用一个相对简单的程序来测试一下

#include <float.h>
#include <mkl.h>
#include <omp.h>
#include <stdio.h>

void init_matrix(double *A, int n, int m, double d);
void test_dgemm(CBLAS_LAYOUT Layout, double *A, double *B, double *C, const MKL_INT m, const MKL_INT n, const MKL_INT k, int nSamples, double *timing);
void print_summary(const MKL_INT m, const MKL_INT n, const MKL_INT k, const int nSamples, const double *timing);

int main(int argc, char **argv) {
MKL_INT n, k, m;
double *a, *b, *c;
double *timing;
int nSamples = 1;

if (argc != 5){
fprintf(stderr, "Error: Wrong number of arguments!\n");
fprintf(stderr, "usage: %s mMatrix nMatrix kMatrix NSamples\n", argv[0]);
return -1;
}

m = atoi(argv[1]);
n = atoi(argv[2]);
k = atoi(argv[3]);

nSamples = atoi(argv[4]);

timing = malloc(nSamples * sizeof *timing);

a = mkl_malloc(m*k * sizeof *a, 64);
b = mkl_malloc(k*n * sizeof *a, 64);
c = mkl_calloc(m*n, sizeof *a, 64);

/** ROW-MAJOR ORDERING **/
test_dgemm(CblasRowMajor, a, b, c, m, n, k, nSamples, timing);

/** COLUMN-MAJOR ORDERING **/
test_dgemm(CblasColMajor, a, b, c, m, n, k, nSamples, timing);

mkl_free(a);
mkl_free(b);
mkl_free(c);
free(timing);
}

void init_matrix(double *A, int n, int m, double d) {
int i, j;
#pragma omp for schedule (static) private(i,j)
for (i = 0; i < n; ++i) {
for (j = 0; j < m; ++j) {
A[j + i*n] = d * (double) ((i - j) / n);
}
}
}

void test_dgemm(CBLAS_LAYOUT Layout, double *A, double *B, double *C, const MKL_INT m, const MKL_INT n, const MKL_INT k, int nSamples, double *timing) {
int i;
MKL_INT lda = m, ldb = k, ldc = m;
double alpha = 1.0, beta = 0.0;

if (CblasRowMajor == Layout) {
printf("\n*****ROW-MAJOR ORDERING*****\n\n");
} else if (CblasColMajor == Layout) {
printf("\n*****COLUMN-MAJOR ORDERING*****\n\n");
}

init_matrix(A, m, k, 0.5);
init_matrix(B, k, n, 0.75);
init_matrix(C, m, n, 0);

// First call performs any buffer/thread initialisation
cblas_dgemm(Layout, CblasNoTrans, CblasNoTrans, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc);

double tmin = DBL_MAX, tmax = 0.0;
for (i = 0; i < nSamples; ++i) {
init_matrix(A, m, k, 0.5);
init_matrix(B, k, n, 0.75);
init_matrix(C, m, n, 0);

timing[i] = dsecnd();
cblas_dgemm(Layout, CblasNoTrans, CblasNoTrans, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc);
timing[i] = dsecnd() - timing[i];

if (tmin > timing[i]) tmin = timing[i];
else if (tmax < timing[i]) tmax = timing[i];
}

print_summary(m, n, k, nSamples, timing);
}

void print_summary(const MKL_INT m, const MKL_INT n, const MKL_INT k, const int nSamples, const double *timing) {
int i;

double tavg = 0.0;
for(i = 0; i < nSamples; i++) {
tavg += timing[i];
}
tavg /= nSamples;

printf("#Loop | Sizes m n k | Time (s)\n");
for(i = 0; i < nSamples; i++) {
printf("%4d %12d %3d %3d %6.4f\n", i + 1 , m, n, k, timing[i]);
}

printf("Summary:\n");
printf("Sizes m n k | Avg. Time (s)\n");
printf(" %8d %3d %3d %12.8f\n", m, n, k, tavg);
}

在我的系统上产生

$ ./benchmark_dgemm 1000 1000 1000 5
*****ROW-MAJOR ORDERING*****

#Loop | Sizes m n k | Time (s)
1 1000 1000 1000 0.0589
2 1000 1000 1000 0.0596
3 1000 1000 1000 0.0603
4 1000 1000 1000 0.0626
5 1000 1000 1000 0.0584
Summary:
Sizes m n k | Avg. Time (s)
1000 1000 1000 0.05995692

*****COLUMN-MAJOR ORDERING*****

#Loop | Sizes m n k | Time (s)
1 1000 1000 1000 0.0597
2 1000 1000 1000 0.0610
3 1000 1000 1000 0.0581
4 1000 1000 1000 0.0594
5 1000 1000 1000 0.0596
Summary:
Sizes m n k | Avg. Time (s)
1000 1000 1000 0.05955171

我们可以看到column-major 排序时间和row-major 排序时间之间的差别很小。 列优先 0.0595 秒行优先 0.0599 秒。再次执行此操作可能会产生以下结果,其中行优先计算快了 0.00003 秒。

$ ./benchmark_dgemm 1000 1000 1000 5
*****ROW-MAJOR ORDERING*****

#Loop | Sizes m n k | Time (s)
1 1000 1000 1000 0.0674
2 1000 1000 1000 0.0598
3 1000 1000 1000 0.0595
4 1000 1000 1000 0.0587
5 1000 1000 1000 0.0584
Summary:
Sizes m n k | Avg. Time (s)
1000 1000 1000 0.06075310

*****COLUMN-MAJOR ORDERING*****

#Loop | Sizes m n k | Time (s)
1 1000 1000 1000 0.0634
2 1000 1000 1000 0.0596
3 1000 1000 1000 0.0582
4 1000 1000 1000 0.0582
5 1000 1000 1000 0.0645
Summary:
Sizes m n k | Avg. Time (s)
1000 1000 1000 0.06078266

关于c - MKL 是否为*主要订单优化 cblas?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32445741/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com