LoginSignup
2

More than 5 years have passed since last update.

LJの力計算のSIMD化ステップ・バイ・ステップ その4

Last updated at Posted at 2016-11-06

はじめに

前回までで4倍展開したループのSIMD化が完了した。いよいよ実測である。

コードは
https://github.com/kaityo256/lj_simdstep
においてある。

SIMD化完了

4倍展開したSIMD化が完了した。基本的に4倍展開されたループのSIMD化はほぼ自明だが、少しだけ非自明なのは、4倍展開して得られた4つの相対距離を一つのYMMレジスタにまとめ、力の計算を4ペア同時に行ってから、またバラす作業。まずまとめるところ。

    v4df vr2_13 = _mm256_unpacklo_pd(vr2_1, vr2_3);
    v4df vr2_24 = _mm256_unpacklo_pd(vr2_2, vr2_4);
    v4df vr2 = _mm256_shuffle_pd(vr2_13, vr2_24, 12);
    v4df vr6 = vr2 * vr2 * vr2;
    v4df vdf = (vc24 * vr6 - vc48) / (vr6 * vr6 * vr2);

    v4df mask = vcl2 - vr2;
    vdf = _mm256_blendv_pd(vdf, vzero, mask);

vr2_1からvr2_4までには、(r2_1, r2_1, r2_1, 0)みたいなデータが入っている。ここから(r2_1, r2_2, r2_3, r2_4)を作るのに、unpack二回とshuffleを使っている。その後は普通に計算している。ただし相互作用範囲外のペアの処理が必要となるため、blendv_pdでマスク処理をしている。

次にバラすところ。

    v4df vdf_1 = _mm256_permute4x64_pd(vdf, 0);
    v4df vdf_2 = _mm256_permute4x64_pd(vdf, 85);
    v4df vdf_3 = _mm256_permute4x64_pd(vdf, 170);
    v4df vdf_4 = _mm256_permute4x64_pd(vdf, 255);

計算された力(df1,df2,df3,df4)から、(df1,df1,df1,df1)〜(df4,df4,df4,df4)を作っているこうすると力積ベクトルの計算がスムーズなので。非自明なところはこれくらいだと思う。

結果

計算手法 実行時間[sec] 備考
pair 8.176446 ペアごとにループをまわしたもの
pair_swp 6.995374 上記をソフトウェアパイプライニングしたもの
pair_swp_intrin 4.276301 上記を4倍展開してSIMD化したもの
sorted_intrin 3.882854 i粒子でソートしたものをSIMD化したもの

・・・ソートバージョンのSIMD化に負けた ○| ̄|_

それなりに加速したものの、ソートバージョンに低密度でも負けたので、ループ長が短いところで「ゴミがほとんど生じない」メリットは、メモリアクセスが増えるデメリットに負けたようだ。

調べてみると、ソートしてソフトウェアパイプライニングしたのの(SIMD化前)のIPCが2.12なのに対し、ソートしないでソフトウェアパイプライニングしたもの(SIMD化前)のIPCが1.99と若干低く、かつ命令数が増えてしまっているのが敗因のようだ。

残念ながら、今回の方針では早くならなかった。参考にならないだろうが、コードは

においておく。

次回に続く

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2