質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

FORTRAN

FORTRAN(フォートラン)は科学時術計算に向いた手続き型プログラミング言語です。 並列計算の最適化が行いやすい特性上、数値予報および気候モデルなどの大規模な計算を行う分野のスーパーコンピュータで使われています。

Q&A

解決済

1回答

1628閲覧

BLASを用いた行列積の高速化

PC_breakman

総合スコア30

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

FORTRAN

FORTRAN(フォートラン)は科学時術計算に向いた手続き型プログラミング言語です。 並列計算の最適化が行いやすい特性上、数値予報および気候モデルなどの大規模な計算を行う分野のスーパーコンピュータで使われています。

0グッド

0クリップ

投稿2021/10/28 07:57

前提・実現したいこと

Netlibのサイト上のBLASのdgemm関数ををC言語から呼び出して行列積を計算し、性能比較を行ったのですが、本来BLASを用いたものの方が性能が良くなるはずですが、自分の書いたコードの方が良い性能を出してしまいました。「BLASを用いたコード」の方の誤りを指摘していただきたいです。

発生している問題・エラーメッセージ

以下の表の通り、自分で最適化したコードの方が性能が良くなってしまいます。
性能計算には、行列サイズN、計測時間t[s]として
MFlops = 2n^3 / t
で定義されるMFlopsという値を用いました。

行列サイズ自分で書いたコードの性能BLASの性能
10004266.672000
11004259.21936
12003949.712067.140187
13004260.852008.685714
14004231.711973.213483
150045001963.636364
160040962032.124031
17004249.081894.168675
18004496.961852.347395
19004456.611817.706004
20004551.111865.209472
21004374.21863.849057
22004340.591831.913978
23004338.091830.054054
24004243.341938.085433
25004366.811913.875598
26004285.21973.445614
27004321.482036.721099
28004383.551975.988748
29004421.82007.58328
30004330.832003.478261

該当のソースコード

自分で最適化したコード

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <time.h> 4 5#define N 3000 // Max matrix size 6#define M 50 // Block size 7 8double A[N][N], B[N][N], C[N][N]; 9 10void mm_ikj_opt(int, int, int); 11 12int main() 13{ 14 int i, j, n; 15 double t, MFlops; 16 clock_t tic, toc; 17 18 int index; 19 printf("N,t,MFlops\n"); 20 21 for(index = 1000; index <= 3000; index += 100) { // 行列サイズ1000~3000まで100おきにデータを取る 22 n = index; 23 srand(2021); 24 for(i = 0; i < n; i++) { 25 for(j = 0; j < n; j++) { 26 A[i][j] = rand(); 27 B[i][j] = rand(); 28 C[i][j] = 0.0; 29 } 30 } 31 32 tic = clock(); 33 mm_ikj_opt(n, n, n); 34 toc = clock(); 35 t = (double)(toc - tic) / CLOCKS_PER_SEC; 36 MFlops = (2.0 * n) * n * n / t / 1e+6; // 性能 37 printf("%d, %.2f, %.2f\n", n, t, MFlops); 38 } 39 return 0; 40} 41 42void mm_ikj_opt(int m, int p, int n) 43{ 44 int ii, jj, kk; 45 int i, k, j; 46 47 // ループアンローリング、ブロック化などで最適化 48 for(ii = 0; ii < m; ii += M) { 49 for(kk = 0; kk < p; kk += M) { 50 for(jj = 0; jj < n; jj += M) { 51 for(i = ii; i < ii + M; i++) { 52 for(k = kk; k < kk + M; k++) { 53 for(j = jj; j < jj + M - 4; j += 4) { // loop unrolling 54 C[i][j] += A[i][k] * B[k][j]; 55 C[i][j + 1] += A[i][k] * B[k][j + 1]; 56 C[i][j + 2] += A[i][k] * B[k][j + 2]; 57 C[i][j + 3] += A[i][k] * B[k][j + 3]; 58 } 59 } 60 } 61 } 62 } 63 } 64}

BLASを用いたコード

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <time.h> 4 5#define N 3000 // matrix size 6double A[N * N], B[N * N], C[N * N]; 7 8int main() 9{ 10 int i, j, n; 11 double t, MFlops; 12 clock_t tic, toc; 13 14 int index; 15 printf("N,t,MFlops\n"); 16 17 for(index = 1000; index <= 3000; index += 100) { 18 n = index; 19 srand(2021); 20 double alpha = 1.0, beta = 0.0; 21 for(i = 0; i < n; i++) { 22 for(j = 0; j < n; j++) { 23 int id1 = i * n + j; 24 int id2 = i + j * n; 25 A[id1] = rand(); 26 B[id2] = rand(); 27 C[id1] = 0.0; 28 } 29 } 30 31 tic = clock(); 32 dgemm_("T", "N", &n, &n, &n, &alpha, A, &n, B, &n, &beta, C, &n); // dgemmで行列積を計算 33 toc = clock(); 34 t = (double)(toc - tic) / CLOCKS_PER_SEC; 35 MFlops = (2.0 * n) * n * n / t / 1e+6; 36 printf("%d, %f, %f\n", n, t, MFlops); 37 38 } 39 return 0; 40}

試したこと

FORTRANが列方向アクセスなのに対してCは行方向アクセスなので、行方向に計算を行っていく行列Aの方を値を代入する段階で転置した状態で代入し、dgemm関数内でも行列Aを転置させて計算することで速くなると思ったが、ならなかった。

補足情報(FW/ツールのバージョンなど)

OS: Windows 11
CPU: AMD Ryzen 7 3700U with Radeon Vega Mobile Gfx 2.30 GHz
コンパイラ: gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

コンパイル・実行方法

$ gcc -O2 hoge.c -lblas -o hoge $ ./hoge > hoge.csv

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2021/10/28 10:40

> 本来BLASを用いたものの方が性能が良くなるはずです その根拠は?
PC_breakman

2021/10/29 01:34

FORTRANで書かれたBLASにCからアクセスしようとして遅くなっていたのかもしれません。CBLASを使ったら最適化の2倍以上の性能を出せました。ありがとうございます。
guest

回答1

0

自己解決

CBLASを用いたら2倍以上の性能が出せました。

投稿2021/10/29 01:34

PC_breakman

総合スコア30

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問