SlideShare a Scribd company logo
1 of 45
Download to read offline
Xeon PhiとN体計算コーディング
x86/x64最適化勉強会6
理化学研究所計算科学研究機構(@神戸)
似鳥啓吾(にたどりけいご)@k_nitadori
簡単に自己紹介
²  神戸の京コンの建物でポスドクしています
³  09年3月、東大理学天文で博士号(一応天体物理学者)
³  指導教員はGRAPEで有名な牧野淳一郎
³  ポスドク5年目(3つ目)
²  専門(自己申告):N体計算の高速化、並列化、
アルゴリズム改良、良い実装を作る
³  SSE/AVX/CUDA/MPI/OpenMPあたりはカバー
³  最近はXeon phiやHaswellなど
³  アセンブラの知識:組み込み関数でSIMD書いたり
コンパイラの吐いたasmを眺める程度
³  「京」向けのチューンも
ゴードン・ベル賞に関して
²  スパコン上でのアプリケーションに対する論文賞
³  ベンチマークランキング(TOP500, HPCC)ではない
³  冬にはスパコンを確保し計算を走らせたい
³  春に12ページぐらいの論文を投稿
³  夏にはfinalist/不採択の結果通知がくる
³  秋のSC学会で口頭発表、それから受賞論文の発表
²  似鳥が入った論文の成績
³  09年:長崎のGeForceクラスタで価格性能部門賞、
10年には同部門佳作賞 (Honorable Mansion)
³  12年:「京」で受賞(部門なしの単独受賞)
³  06、07、08、13年には落選
今日話す内容
²  どうやって40∼60分も間を持たせよう、、、
³  適当に割り込み、つっこみお願いします
²  専門のN体計算のお話
³  高次積分法で高精度に計算するお話
®  Xeon Phi Nativeで実装したよ
³  テーブル参照で任意のforce shapeを実現するお話
®  SSE/AVXでテーブル参照を頑張った
²  その際の若干トリッキーな最適化の話題
³  普段のセミナーで「そんな話嬉しそうに延々とされても
困ります」といわれるような話題をいくつか
³  Xeon Phi (KNC)とAVX-512の命令セットの概観
N体計算の支配方程式
²  式はひとつ(話題は無数)
²  減算3回、積和6回、乗算3回、逆数平方根1回
²  i-loopとj-loopの二重ループ、O(N2)
²  j-粒子がi-粒子を引っ張る
²  i-並列とj-並列のふたつの並列度
³  i-並列ではj-粒子の放送によってメモリ帯域を節約
³  j-並列では最後に部分力の総和演算が必要
ないし(発散を避けるために)	
  
コードのほうが分
り易いという人用
²  流用資料につき混合精度
²  外側ループのomp
parallel化は自明に近い
と思う
²  レジスタが余っていたら
外側ループをアンロール
しよう
²  j-粒子がキャッシュに収
まるようなブロック化/
並列化も有効
6 const float mj[] ,
7 const float eps2 ,
8 double acci[][3])
9 {
10 for(int i=0; i<ni; i++){
11 const double xi = posi[i][0];
12 const double yi = posi[i][1];
13 const double zi = posi[i][2];
14 double ax = 0.0;
15 double ay = 0.0;
16 double az = 0.0;
17 for(int j=0; j<nj; j++){
18 const float dx = float(posj[j][0] - xi);
19 const float dy = float(posj[j][1] - yi);
20 const float dz = float(posj[j][2] - zi);
21 const float r2 = eps2 + dx*dx + dy*dy + dz*dz;
22 const float ri2 = 1.0f / r2;
23 const float mri1 = m[j] * sqrtf(ri2);
24 const float mri3 = mri1 * ri2;
25 ax += double(mri3 * dx);
26 ay += double(mri3 * dy);
27 az += double(mri3 * dz);
28 }
29 acc[i][0] = ax;
30 acc[i][1] = ay;
31 acc[i][2] = az;
32 }
33 }
このぐらいに書いておけば、コンパイラが「無駄なコード」を吐くことはまずない。コ
によっては、部分的に SIMD 命令を使ってくれることもあるだろうが、得られる性能は
高次の方法(4次のHermite積分法)
²  加速度の一階微分(jerk)も直接計算
³  コスト:「倍にはならない」
²  補間多項式を積分
³  Hermite補間
³  積分の始点と終点で、実質4点分の情報
²  予測子修正子法
³  未来の座標はテイラー展開で予測
³  未来の加速度とjerkを予測子から計算
³  補間多項式から修正子を構築
³  反復してもいいけどしなくても4次精度
®  Runge-Kuttaより高効率	
t
f
Δv
i+1i
もっと高階微分も計算できる?(できます)
高階微分の計算
²  2階微分(snap)まで使って6次精度
²  3階微分(crackle)まで使って8次精度
³  次の微分にはpopと名前が付いている
²  高次のものほど
³  レジスタ消費は多い
³  積和比率が高い(逆数平方根は一回)
³  同期オーバーヘッドが相対的に小さい
38	
  ops
60	
  ops
97	
  ops
144	
  ops
Acceleration:
Jerk:
Snap:
Crackle:
.2.2 Direct calculation of higher order derivatives
The gravitational acceleration from a particle j on a particle i and its first three
me derivatives are expressed as
Aij = mj
rij
r3
ij
, (2.1)
Jij = mj
vij
r3
ij
− 3αAij, (2.2)
Sij = mj
aij
r3
ij
− 6αJij − 3βAij, (2.3)
Cij = mj
jij
r3
ij
− 9αSij − 9βJij − 3γAij. (2.4)
Here, we call the first four time derivatives of the acceleration jerk, snap, crackle and
op, and α, β and γ are given by
α =
rij · vij
r2
ij
, (2.5)
β =
|vij|2
+ rij · aij
r2
ij
+ α2
, (2.6)
γ =
3vij · aij + rij · jij
2 + α(3β − 4α2
), (2.7)
al acceleration from a particle j on a particle i and its first three
re expressed as
Aij = mj
rij
r3
ij
, (2.1)
Jij = mj
vij
r3
ij
− 3αAij, (2.2)
Sij = mj
aij
r3
ij
− 6αJij − 3βAij, (2.3)
Cij = mj
jij
r3
ij
− 9αSij − 9βJij − 3γAij. (2.4)
first four time derivatives of the acceleration jerk, snap, crackle and
γ are given by
α =
rij · vij
r2
ij
, (2.5)
β =
|vij|2
+ rij · aij
r2
ij
+ α2
, (2.6)
γ =
3vij · aij + rij · jij
r2
ij
+ α(3β − 4α2
), (2.7)
i and mi are the position, velocity, total acceleration, total jerk and
Aij = mj
rij
r3
ij
, (2.1)
Jij = mj
vij
r3
ij
− 3αAij, (2.2)
Sij = mj
aij
r3
ij
− 6αJij − 3βAij, (2.3)
Cij = mj
jij
r3
ij
− 9αSij − 9βJij − 3γAij. (2.4)
rst four time derivatives of the acceleration jerk, snap, crackle and
γ are given by
α =
rij · vij
r2
ij
, (2.5)
β =
|vij|2
+ rij · aij
r2
ij
+ α2
, (2.6)
γ =
3vij · aij + rij · jij
r2
ij
+ α(3β − 4α2
), (2.7)
and mi are the position, velocity, total acceleration, total jerk and
and rij = rj − ri, vij = vj − vi, aij = aj − ai and jij = jj − ji
divとsqrtをそれぞれ	
  
10演算と数えてある
for(int j=0; j<nj; j++){ !
const dvec3 dr = pred[j].pos - posi; !
const dvec3 dv = pred[j].vel - veli; !
const dvec3 da = pred[j].acc - acci; !
const dvec3 dj = pred[j].jrk - jrki; !
!
const double r2 = eps2 + dr*dr; !
const double drdv = dr*dv; !
const double dvdv = dv*dv; !
const double drda = dr*da; !
const double dvda = dv*da; !
const double drdj = dr*dj; !
!
const double ri2 = 1.0 / r2; !
const double mri3 = pred[j].mass * ri2 * sqrt(ri2); !
const double alpha = drdv * ri2; !
const double beta = (dvdv + drda)*ri2 + alpha*alpha; !
const double gamma = (3.0*dvda + drdj)*ri2 + alpha*(3.0*beta - 4.0*alpha*alpha);
!
dvec3 tmp1 = dv + (-3.0*alpha) * dr; !
dvec3 tmp2 = da + (-6.0*alpha) * tmp1 + (-3.0*beta) * dr; !
dvec3 tmp3 = dj + (-9.0*alpha) * tmp2 + (-9.0*beta) * tmp1 + (-3.0*gamma) * dr;!
!
acc += mri3 * dr;!
jrk += mri3 * tmp1;!
snp += mri3 * tmp2;!
crk += mri3 * tmp3;!
}
実装例
²  書き散らかしたの置いたので見てね
³  https://github.com/nitadori/
Hermite/blob/master/SRC/
hermite8.h
³  誰か.ignoreその他教えてください
³  AVX/MIC/K版があります
³  積和が多いと嬉しいね
独立時間刻み法
²  重力のN体計算では近接遭遇が多発
³  いちいち全部の粒子の時間刻みを最小のものに切り
揃えていては無駄が多い
³  粒子ごとにadaptiveに刻み幅を下げることを考える
®  とりあえず2の冪に
®  他の粒子の座標には「予測子」を使う
1/1	
  
1/2	
  
1/4	
  
1/8	
  
•  同時にNact個のactive粒子をアップデート
•  全N粒子の予測子を計算:O(N)
•  Nact個の粒子の加速度を計算:O(NactN)
•  力を積分して修正子:O(Nact)
•  <Nact>∼N2/3
続き(ちょっと物理数学)
²  単位箱にN個の粒子をランダムに置いたときの平均粒子間距
離はN -1/3
³  これはまあいいでしょう
²  そのときの最小の粒子ペア距離の期待値はN -2/3
³  これを示すのは大変(誰かhelp!)
²  結果共有時間刻みではN個の粒子を同時に積分できたのが、
独立時間刻みではN2/3個に
³  時間刻みは最近接粒子との距離に比例すると仮定
³  N=1000に対し<Nact>=50ぐらい(系の中心集中度や積分次数
にも依ります)
³  大幅に高速化したのはいいがi-粒子の並列度がそのまま食われて
しまった
時間刻みの決め方
²  Hermite補間の際に得られた加
速度の時間微分から次の時間刻
みを決定
³  経験的な公式
³  pは積分次数、ηは精度パラメタ
²  1/6乗や1/10乗が発生するのが
ちょっと嫌
³  しかも結果は2の冪に丸められる
³  というわけで最適化
³  これでlibmathいらず
template <int N> !
double pow_one_nth_quant(!
const double x)!
{!
assert(x > 0.0); !
union{
double d;!
unsigned long l; !
} m64; !
m64.d = x;!
const int dec = 1023 % N;!
const int inc = 1023 - 1023 / N;
m64.l >>= 52;
m64.l -= dec;!
m64.l /= N; !
m64.l += inc;!
m64.l <<= 52;!
return m64.d;!
}
1ステップの手続き
1.  積分する粒子を選ぶ:O(Nact) or O(logN) (serial)
2.  全粒子の予測子を計算:O(N) (parallel)
3.  重力を計算:O(NactN) (parallel)
4.  修正子と新しい時間刻みを計算:O(Nact) (parallel)
5.  粒子を時間刻み順にソート:O(NactlogNact) (serial)
そろそろXeon Phiの話
²  Xeon Phi 5110P (Knights Corner)
³  1.053 GHz
³  60 core, 240 threads
³  512-bit FMA (16 DP flop/cycle), 1011 DP, 2022 SP
Gflops
³  60 x (32KB L1I, 32KB L1D, 512KB L2)
²  32本の512-bit zmmレジスタ
³  レジスタ幅がキャッシュライン幅に追いついた(64-byte)
³  4スレッドで8KBi!
³  float x16 or double x8
³  16-bitのマスクレジスタが8本
³  xmmもymmもない(Pentium互換+X64+独自拡張)
AVX-512の概観(ぱっと見)
²  次世代KNL (Knights Landing)から
³  普通のXeon/Core iにも搭載されるのだろうか?
²  XMM/YMMが復活、ZMMと共に32本
³  マスクレジスタ、swizzle、bcastもサポート
²  EVEX prefix
³  62hからの4-byte
²  KNC(現行のPhi)のベクトル命令をベースにSSE/
AVXと下位互換を取るように整理したもの、といった
感じ
³  数学関数の取り扱いが若干変わった
プログラミングモデル
²  Native mode
³  Phiのカード上でLinuxが動いていてsshで入れる
³  ホストのディレクトリをNFS経由でマウントできる
®  icc -mmic hello.c
ssh mic0
./a.out
³  コードはintrinsicsとOpenMPで書いておく
®  zmmintrin.h (included from immintrin.h), micvec.h (for C++)
²  Offload mode
³  ホスト実行のコードの一部を#pragma offloadで切り出す
³  GPU的な使い方(生産性は高いとの主張)
³  似鳥は試したことないのでよくわかりません、
講習会とかもやってるっぽい
ニーモニック
²  vaddpd zmm1{k1}, zmm2, zmm3/mem
³  zmm1 = zmm2 + zmm3/mem
³  k1: マスクレジスタで結果代入をマスクできる
³  zmm3: swizzleが使える!
®  dcba-> dcba (no swizzle), cdab (swap inner), badc
(swap outer), dacb (cross prod), aaaa, bbbb, cccc,
dddd (bcast)
³  mem: 放送と型変換(upconv)ができる!
®  DP: 8to8, 4to8, 1to8
®  SP: 16to16, 4to16, 1to16
®  適切にalignされていること
load/store
²  ZMMレジスタとキャッシュラインサイズが64 byteで一致
²  Aligned load/store
³  単にvmovapd
³  no-read, no-global-orderingのstreaming store命令も存在
²  Unaligned load/store
³  2ライン触るので2命令
®  v1	
  =	
  _mm512_loadunpacklo_pd(v1,	
  mt);	
  
®  v1	
  =	
  _mm512_loadunpackhi_pd(v1,	
  mt+64);	
  
®  warning	
  (uninitialized	
  v1)を消す方法ありませんか?	
  
²  Gather/Scatter
³  速度はともかく、命令が存在する
³  コストは触ったライン数に依存とのこと
積和命令
²  VFMADD{132¦213¦231}PD zmm1, zmm2, zmm3
³  zmm1 = zmm1 * zmm3 + zmm2
³  zmm1 = zmm2 * zmm1 + zmm3
³  zmm1 = zmm2 * zmm3 + zmm1
²  あと符号で4種類(*́д`*)
²  swizzle/メモリオペランドは第3opのみ使える
²  まあ、mulとadd/subで書いとけばコンパイラがやってくれ
るんだけど
²  intrinsicsは4オペランド形式
²  swizzleと混ぜるときはmovの数が最小になるといいですね
swizzle万歳
²  レジスタ1本で4つの定数を格納できる
²  C++ラッパのほうが見た目がasmに近い
³  ただしswizzleメソッドがconstになってないというバグ仕様
³  サンプルのasmはAT&T形式です、すみません
#include <micvec.h>!
!
F64vec8 poly3(F64vec8 x, F64vec8 coef){!
return coef.aaaa() + x*(coef.bbbb() + x*(coef.cccc() + x*(coef.dddd())));!
}!
F64vec8 poly3(F64vec8 x, const double *coef){!
return F64vec8(coef[0]) + x*(F64vec8(coef[1]) + x*(F64vec8(coef[2]) + x*(F64vec8(coef[3]))));!
}!
poly3(F64vec8, F64vec8):!
vmovdqa64 %zmm1{dddd}, %zmm2 !
vfmadd213pd %zmm1{cccc}, %zmm0, %zmm2 !
vfmadd213pd %zmm1{bbbb}, %zmm0, %zmm2 !
vfmadd213pd %zmm1{aaaa}, %zmm2, %zmm0 !
ret
poly3(F64vec8, double const*):!
vbroadcastsd 24(%rdi), %zmm1
vfmadd213pd 16(%rdi){1to8}, %zmm0, %zmm1
vfmadd213pd 8(%rdi){1to8}, %zmm0, %zmm1
vfmadd213pd (%rdi){1to8}, %zmm1, %zmm0
ret
Shuffle系の命令
²  mask_blendとswizzleでかなりのことができる
³  vblendmps, vblendmpd
³  引数のマスクレジスタで要素を選択
³  組み込み関数からだと即値指定(imm16/imm8)も可能だけど、
実際は汎用レジスタ経由でマスクレジスタに飛ばされる
²  4語(単精度で128-bit、倍精度で256-bit)の単位をまたい
でshuffleしたい場合
³  vpermf32x4 zmm1{k1}, zmm2/mt, imm8
®  128-bitが4つあるのを、imm8で並び替え
³  vpermd zmm{k1}, zmm2, zmm3/mt
®  32-bitが16語あるのを任意に並び替え
®  indicatorはimmではなくてzmm2の各語下位4-bit
応用:4x4行列転置
²  上4語と下4語で同時に
static	
  inline	
  void	
  transpose_4zmm_pd(F64vec8	
  &v0,	
  F64vec8	
  &v1,	
  F64vec8	
  &v2,	
  F64vec8	
  &v3){	
  
	
  	
  	
  	
  F64vec8	
  c1c0a1a0	
  =	
  _mm512_mask_blend_pd(0xaa,	
  v0,	
  v1.cdab());	
  
	
  	
  	
  	
  F64vec8	
  c3c2a3a2	
  =	
  _mm512_mask_blend_pd(0xaa,	
  v2,	
  v3.cdab());	
  
	
  	
  	
  	
  F64vec8	
  d1d0b1b0	
  =	
  _mm512_mask_blend_pd(0x55,	
  v1,	
  v0.cdab());	
  
	
  	
  	
  	
  F64vec8	
  d3d2b3b2	
  =	
  _mm512_mask_blend_pd(0x55,	
  v3,	
  v2.cdab());	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  F64vec8	
  aaaa	
  =	
  _mm512_mask_blend_pd(0xcc,	
  c1c0a1a0,	
  c3c2a3a2.badc());	
  
	
  	
  	
  	
  F64vec8	
  bbbb	
  =	
  _mm512_mask_blend_pd(0xcc,	
  d1d0b1b0,	
  d3d2b3b2.badc());	
  
	
  	
  	
  	
  F64vec8	
  cccc	
  =	
  _mm512_mask_blend_pd(0x33,	
  c3c2a3a2,	
  c1c0a1a0.badc());	
  
	
  	
  	
  	
  F64vec8	
  dddd	
  =	
  _mm512_mask_blend_pd(0x33,	
  d3d2b3b2,	
  d1d0b1b0.badc());	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  v0	
  =	
  aaaa;	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  v1	
  =	
  bbbb;	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  v2	
  =	
  cccc;	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  v3	
  =	
  dddd;	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
}	
  	
  
²  マスクレジスタを4本消費
³  もっといい方法あったら教えてください
用途
²  インテルさんはSoA推奨だけど
³  x[N], y[N], z[N], m[N]みたいの
²  AoSにしたいこともよくあるわけです
³  {x, y, z, m}[N]みたの
³  高次積分のN体だともっとメンバ多いし
²  今回のN体コードの実装
³  i-粒子4並列、j-粒子2並列で8-way SIMD
³  i-粒子:{x0, x1, x2, x3, x0, x1, x2, x3}
®  yとzも同様
®  さっきの転置で作っておく
³  j-粒子:{x0, y0, z0, m0, x1, y1, z1, m1}
®  swizzleで放送
コードはこんな感じ
²  vsubrpdという新命令で-(lhs-rhs)を計算
³  rhsしかswizzleできないので痒い所に手が届く
³  別にこう書かなくてもコンパイラがやってくれるけど
for(int j=jbeg; j<jend; j+=2){!
const double *jptr = (double *)(&pred[j/2]);!
_mm_prefetch((char *)(jptr + 16), _MM_HINT_T0);!
_mm_prefetch((char *)(jptr + 24), _MM_HINT_T0);!
F64vec8 jxbuf = *(__m512d *)(jptr + 0); !
F64vec8 jvbuf = *(__m512d *)(jptr + 8); !
!
const F64vec8 dx = -(xi - jxbuf.aaaa());!
const F64vec8 dy = -(yi - jxbuf.bbbb());!
const F64vec8 dz = -(zi - jxbuf.cccc());!
const F64vec8 dvx = -(vxi - jvbuf.aaaa());!
const F64vec8 dvy = -(vyi - jvbuf.bbbb());!
const F64vec8 dvz = -(vzi - jvbuf.cccc());!
...!
}
•  j-粒子のL1への手動プリ
フェッチは有効であった
•  ハードもコンパイラもL1へは
無闇にPFするわけにもいかな
いため
60コア240スレッドの使い方
²  単純i-並列/j-並列で使うには多すぎる
³  今回の実装では、コア内4スレッドをi-並列に
60コアをj-並列にしてみた
®  環境変数KMP_AFFINITY=compactとしておくと、コ
ア内4スレッドが連番に
®  OpenMPでは0から239のスレッド番号が取得できる
®  j-粒子が分割キャッシュに乗るという目論見
®  affinityを切ると若干の性能低下
®  部分力[Nact][60]はメモリに書き出して後から総和を
取る
性能
²  コードは倍精度の4/6/8次積分法
³  相互作用あたり60/97/144演算とした
³  横軸は粒子数N
²  比較用:Haswell i7 4C8T 3.40 GHz
³  217.6 Gflops peak
³  AVXで開発済みだったコードをGCC 4.81で
-O2 -march=core-avx2(積和化された)
Gflops値
²  粒子数の多いところ
ではHaswell16コア
分ぐらい
²  GRAPEやGPUのよ
うな振る舞い
²  CPUとの転送は存
在しないのだが、、、
ステップあたりのμ秒
²  200μ秒付近に壁
がある
²  同期オーバーヘッド
のようだ
同期が遅い!
²  omp barrierで20μs、omp parallel {}で30μsぐらい
持っていかれる(実測)
³  Opteron 4 socket, 8 die, 64 coreのマシンより遅い
³  ステップあたり5回同期していたので納得できる
²  粒子ソートもHaswellの50倍ぐらい遅かった
³  同期と同様馬鹿にならない時間がかかっていた
²  Xeon Phiのボトルネック
³  個々のコアが貧弱(これは仕方ないかもだけど)
³  コア間通信が遅い(キャッシュが分散しているため)
®  ランタイムの改良で若干改善できるかも(同期の階層化)
²  なんか、殆どGPUだよね(今日のPhiの話はここまで)
カットオフ関数がある計算
²  宇宙論的なN体計算だと
³  遠方から(低周波)の重力は一様メッシュとFFTで
³  近距離(高周波)の重力は粒子から直接計算する方
法がよく使われる
®  このとき到達距離が数メッシュ間隔ぐらいのカットオフ関数
が掛かる
²  SSE/AVXで無理矢理テーブル参照で実装
²  「京」でのGB賞ではこの関数を直接計算した
具体的なかたち
²  教科書にあったもの
²  分岐を排除したもの
³  「京」ではこれを直接計算した
なく、S2 分布に対する厳密解であることには注意。
P3
M 法の PP パート(つまりは S2 soften された PM force の Newton 重力からの残
差)での重力相互作用へのカットオフ関数 
ai =
j=i
mj(rj − ri)
|rj − ri|3
gP3M(|rj − ri|)/η), (3)
として表現する場合は、 
gP3M(R) =



1 −
1
140
`
224R3
− 224R5
+ 70R6
+ 48R7
− 21R8
´
(0 ≤ R ≤ 1)
1 −
1
140
`
12 − 224R2
+ 869R3
− 840R4
+ 224R5
+ 70R6
− 48R7
+ 7R8
´
(1 ≤ R ≤ 2)
0 (2 ≤ R)
,
(4)
とあらわせる。
2
φ(R) =


1
140
ˆ
208 − 112R2
+ 56R4
− 14R5
− 8R6
+ 3R7
˜
(0 ≤ R ≤ 1)
1
140
»
12
R
+ 128 + 224R − 448R2
+ 280R3
− 56R4
− 14R5
+ 8R6
− R7
–
(1 ≤ R ≤ 2)
1
R
(2 ≤ R)
.
(5)
3 Optimization
このままでは演算量も多く分岐もあるため、PP 相互作用の度にこれを計算するのはさ
すがに無視できないコストとなる。そこでモダンな汎用計算機のための効率的な式変形を
試みてみよう。
S ≡ max(0, R − 1), (6)
として、
gP3M(R) = 1 + R3
−
8
5
+ R2 8
5
+ R −
1
2
+ R −
12
35
+ R
3
20
− S6 3
35
+ R
18
35
+ R
1
5
(0 ≤ R ≤ 2) (7)
ポテンシャルも写経:
φ(R) =



1
140
ˆ
208 − 112R2
+ 56R4
− 14R5
− 8R6
+ 3R7
˜
1
140
»
12
R
+ 128 + 224R − 448R2
+ 280R3
− 56R4
− 14R5
1
R
3 Optimization
このままでは演算量も多く分岐もあるため、PP 相互作用の度に
すがに無視できないコストとなる。そこでモダンな汎用計算機のた
試みてみよう。
S ≡ max(0, R − 1),
として、
一応図示
² 
赤がポテンシャルの
カットオフ
² 
緑が今回欲しい力の
カットオフ
² 
残り2本は多重極展開
するとき使う物
³ 
float4のtexfetch1Dで
一気にやろうとか考え
てた
テーブル参照で関数を評価
²  普通に考えれば(int)(scale * r)でindexを
生成して適当な次数で補間してf(r)を計算
²  しかし、r2 → f(r)/r3 を一発で評価するのが
最速に思える
³  サンプル間隔も最適に近い物を選びたい
³  何をindexに使うか、どうやって得るか?
³  若干トリッキーな方法をとった
indexの生成
²  座標は適当にスケールしておく
²  s = 2.0f + r2を計算
²  指数部の下位4-bitと仮数部の上位6-bitを用いる
³  17-bit右シフトだけでいい
³  あとは1次補間で必要な精度に
smax À 2 smax À 2
’
1
ð2F
þ bFÞ1=2
2bEþ1
=2Fþ2
smax À 2
!1=2
; ð5Þ
where we also assume bE ) 1 and F ) 1 for the last approximation.
Therefore, the sampling points with the same fraction bits are dis-
tributed uniformly in logarithmic scale, and those with the same
exponent bits are aligned uniformly in linear scale unless the frac-
tion bit is small.
As an example, we illustrate how the sampling points of the
look-up table depend on the pre-defined integers E and F in
Fig. 4. We first see the cases in which either of E and F is zero, in
Table 4
s-values, their exponent and fraction bits in the IEEE754 expressions, and their indices
in the table for r ¼ 0, rcut=2 and rcut in the case of E ¼ 4 and F ¼ 6 (underlined portion
of exponent and fraction bits).
r s Exponent
bits
Fraction bits Index
0 2 (smin) 10000000 00000000000000000000000 0
rcut=2 3:2514 Â 104
10001101 11111100000001100000000 895
rcut 1:3005 Â 105
10001111 11111100000000000000000 1023
(smax)
10
-2
10
-1
10
0
10
1
10
2
10
3
10
4
f(r)rcut
3
/r
Conventional
10
-2
10
-1
10
0
10
1
10
2
10
3
10
4
10
-3
10
-2
10
-1
10
0
f(r)rcut
3
/r
r / rcut
Presented
A. Tanikawa et al
AVXでのテーブル参照
²  GatherはAVX2から(しかも遅い)
²  テーブルの実体は補間用の係数を含めてfloat
table[1024][2];
²  indexはpextrwないしL1経由で汎用レジス
タに転送
²  gatherの代わりに(movlps, movhps)^2,
vinsertf128
²  あとは適当にシャッフル
適当にシャッフル
d5 f5 d4 f4 d1 f1 d0 f0
d7 f7 d6 f6 d3 f3 d2 f2
f0f1f2f3f4f5f6f7
d0d1d2d3d4d5d6d7
vshufps 0x88
vshufps 0xdd
0x88 = 2020(4), 0xdd = 3131(4)
AVX2のコード(GCC)
for(j=0; j<nj; j+=2){!
v8sf xj = __builtin_ia32_shufps256(jp, jp, 0x00);!
v8sf yj = __builtin_ia32_shufps256(jp, jp, 0x55);!
v8sf zj = __builtin_ia32_shufps256(jp, jp, 0xaa);!
v8sf mj = __builtin_ia32_shufps256(jp, jp, 0xff);!
jp = *(v8sf *)(jpdata+=2);!
!
v8sf dx = xj - xi, dy = yj - yi, dz = zj - zi;!
v8sf r2 = ((two + dx*dx) + dy*dy) + dz*dz;!
r2 = __builtin_ia32_minps256(r2, r2cut);!
v8si r2_sr = __builtin_ia32_psrldi256((v8si)r2, 23-FRC_BIT);!
v8si r2_sl = __builtin_ia32_pslldi256(r2_sr, 23-FRC_BIT);!
unsigned int idx[8] __attribute__((aligned(32)));!
*(v8si *)idx = r2_sr;!
const long long *ptr = (long long *)fcut;!
v4di tbl_0145 = {ptr[idx[0]], ptr[idx[1]], ptr[idx[4]], ptr[idx[5]]};!
v4di tbl_2367 = {ptr[idx[2]], ptr[idx[3]], ptr[idx[6]], ptr[idx[7]]};!
!
v8sf ff = __builtin_ia32_shufps256((v8sf)tbl_0145, (v8sf)tbl_2367, 0x88);!
v8sf df = __builtin_ia32_shufps256((v8sf)tbl_0145, (v8sf)tbl_2367, 0xdd);!
v8sf dr2 = r2 - (v8sf)r2_sl;!
ff += dr2 * df;!
!
v8sf mf = mj * ff;!
ax += mf * dx; ay += mf * dy; az += mf * dz;!
}!
配列初期化子任せ
shufpsで放送
粒子のプリロード
積和算
256-­‐bit整数命令
L1を経由
1次補間
逆数平方根
²  近似命令から収束公式だね!
³  Newton重力の計算を大幅に高速化
²  2次収束を繰り返すだけが能じゃない
³  例:rsqrtpsは12-bit精度、53-bitの倍精度に近づけたければ
®  2次収束を3回
®  単精度で2次収束をかけて倍精度で3次収束
®  5次収束一発
³  積和算一回につき1次増やせる
®  係数のレジスタ圧迫は問題
³  任意のx-n/mに拡張できる
®  h = 1 ‒ xnym
®  y *= taylor[(1 ‒ h)-1/m]
ハードのサポート状況
²  3DNow! (忘れないでね)
³  pfrsqrt, pfrsqrti1, pfrsqrti2
³  15-bitの近似と、収束補助命令
²  SSE/AVX
³  rsqrtps
³  12-bitの近似命令
³  y *= (1.5f - (0.5f*x)*y*y)ないしy += y*(0.5f - (0.5f*x)*y*y)でほぼ単精度
³  倍精度からだと型変換が煩わしい
²  Xeon Phi (KNC)
³  vrsqrt23ps
³  23-bit、なんと単精度なら生でいい
³  倍精度なら3次収束をかける
²  AVX-512
³  vrsqrt{14¦28}{ss¦ps¦sd¦pd}
³  14-bitと、オプション(?)で28-bitになった
³  倍精度から直接呼べるというのが何より嬉しい、2次収束一発でいい
²  HPC-ACE (Sparc64, K computer extension)
³  倍精度2語に対して8-bit精度
³  高級言語からはコンパイラが2次収束を3回吐く(組み込み関数で明示も可能)
周期境界の補正
²  周期境界では、絶対座標は0≤x<1、
相対座標は−0.5<Δx≤0.5のようにしたい
³  じゃあ整数で、という人もここには多いでしょうが、、、
³  境界の開閉はこだわらないことにする
®  ここだけの話、倍精度から単精度の変換で絶対座標が1.0fになってしまうバグ出したこ
とある
³  x -= round(x)みたく補正できばOK
®  call無し、分岐無し、ハードで
SIMDでやりたいよね
®  roundpsとかなくても演算器の
後には丸めユニットがあります
double myround(double x){!
// returns!
// -1 for -1.5 < x <= -0.5!
// 0 for -0.5 < x <= 0.5!
// 1 for 0.5 < x <= 1.5!
x += (double)(1 + (1LL << 52));!
x -= (double)(1 + (1LL << 52));!
return x;!
}!
Morton曲線とPeano-Hilbert曲線
²  Octree構造と密接な関係
³  Morton/PH keyを作ってソートしておくツリーがで
きたも同然
³  キャッシュヒットの改善、並列化のための領域分割に
も使われる
³  2次元でのMorton ordering(左)と
Hilbert ordering(右)
Morton keyの実装
²  x, y, zをそれぞれ21-
bit整数にしたらビッ
トシャッフルするだ
け
³  ...cba(2) ->
...00c00b00a(2)
uint64 gen_morton(unsigned x, unsigned y, unsigned z){!
uint64 key = 0;!
for(int ish=20; ish>=0; ish--){!
unsigned ix = (x>>ish)&1;!
unsigned iy = (y>>ish)&1;!
unsigned iz = (z>>ish)&1;!
unsigned idx = 4*iz | 2*iy | ix;!
key = (key<<3) | idx;!
}!
return key;!
}
Then we can apply bit-based dilate primitives to compute the Morton key
(List.1, [44]). This dilate primitive converts the first 10 bits of an integer to
a 30 bit representation, i.e. 0100111011 ! 000 001 000 000 001 001 001
000 001 001:
List 1: The GPU code which we use to dilate the first 10-bits of an integer.
1 int dilate(const int value) {
2 unsigned int x;
3 x = value & 0x03FF;
4 x = ((x << 16) + x) & 0xFF0000FF;
5 x = ((x << 8) + x) & 0x0F00F00F;
6 x = ((x << 4) + x) & 0xC30C30C3;
7 x = ((x << 2) + x) & 0x49249249;
8 return x;
9 }
こんな実装もあります
Peano-Hilbertはもう少し難しい
²  3次元だと作り方が一意ではないのに注意
²  自分の周囲に被害者数名
「素晴らしい本で,少し
でもこのテーマに興味あ
るすべての人に全面的に
お勧めである.」
•  これはみんなもってる?	
  
•  2次元の場合の実装に関する	
  
詳細な記述
•  読んだら3次元の実装ができる	
  
とは限りません	
  
•  それでも数学好きにはお勧め
先ずはGray code
Incremental Gray	
  code
000! 000
001 001
010 011
011 010
100 110
101 111
110 101
111 100
zyx ^= zyx>>1;
zyx ^= (zyx>>1) ^ (zyx>>2);
•  一番上の階層はこれでいい	
  
•  あとは部品の回転/反転
namespace{!
const uint64 xmask = 0111111111111111111111;!
const uint64 ymask = 0222222222222222222222;!
const uint64 zmask = 0444444444444444444444;!
!
inline uint64 swap_xy(uint64 key){!
return ((key&xmask)<<1 | (key&ymask)>>1 | (key&zmask));!
}!
inline uint64 swap_yz(uint64 key){!
return ((key&xmask) | (key&ymask)<<1 | (key&zmask)>>1);!
}!
inline uint64 swap_zx(uint64 key){!
return ((key&xmask)<<2 | (key&ymask) | (key&zmask)>>2);!
}!
inline uint64 key_shuffle(uint64 key, int idx){!
switch(idx/2 + idx%2){!
case 4: // idx = 7!
key ^= (xmask | zmask); // fall-through!
case 0: // idx = 0!
key = swap_zx(key);!
break;!
case 3: // idx = 5,6!
key ^= (ymask | zmask); // fall-through!
case 1: // idx = 1,2!
key = swap_yz(key);!
break;!
case 2: // idx = 3,4!
key ^= (xmask | ymask);!
break;!
}!
return key;!
}!
}!
uint64 morton_to_ph(uint64 key){!
uint64 ret = 0;!
for(int ish=60; ish>=0; ish-=3){!
unsigned idx = (key>>ish) & 7;!
idx = (idx>>2) ^ (idx>>1) ^ (idx);

// from Gray code!
key = key_shuffle(key, idx);!
ret = (ret<<3) | idx;!
}!
return ret;!
}!
uint64 ph_to_morton(uint64 key){!
uint64 tmp = key;!
tmp ^= (tmp&(zmask|ymask)) >> 1;

// to Gray code!
for(int jsh=3; jsh<=60; jsh+=3){!
unsigned idx = (key>>jsh) & 7;!
uint64 sfl = key_shuffle(tmp, idx);!
uint64 mask = ((uint64)1<<jsh) - 1;!
tmp &= ~mask;!
tmp |= sfl&mask;!
}!
return tmp;!
}!
ご自由に最適化ください(終)

More Related Content

What's hot

「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料
「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料 「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料
「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料 Ken'ichi Matsui
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門Hideyuki Tanaka
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門Norishige Fukushima
 
暗号文のままで計算しよう - 準同型暗号入門 -
暗号文のままで計算しよう - 準同型暗号入門 -暗号文のままで計算しよう - 準同型暗号入門 -
暗号文のままで計算しよう - 準同型暗号入門 -MITSUNARI Shigeo
 
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexprGenya Murakami
 
指数時間アルゴリズム入門
指数時間アルゴリズム入門指数時間アルゴリズム入門
指数時間アルゴリズム入門Yoichi Iwata
 
tcpdumpとtcpreplayとtcprewriteと他。
tcpdumpとtcpreplayとtcprewriteと他。tcpdumpとtcpreplayとtcprewriteと他。
tcpdumpとtcpreplayとtcprewriteと他。(^-^) togakushi
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!Genya Murakami
 
自作ペアリング/BLS署名ライブラリの紹介
自作ペアリング/BLS署名ライブラリの紹介自作ペアリング/BLS署名ライブラリの紹介
自作ペアリング/BLS署名ライブラリの紹介MITSUNARI Shigeo
 
Linuxのsemaphoreとmutexを見る 
Linuxのsemaphoreとmutexを見る Linuxのsemaphoreとmutexを見る 
Linuxのsemaphoreとmutexを見る wata2ki
 
いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門Fixstars Corporation
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~Nobuhisa Koizumi
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性Hibiki Yamashiro
 
文字列検索のいろいろ
文字列検索のいろいろ文字列検索のいろいろ
文字列検索のいろいろKazuma Mikami
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するYoshifumi Kawai
 
Scapyで作る・解析するパケット
Scapyで作る・解析するパケットScapyで作る・解析するパケット
Scapyで作る・解析するパケットTakaaki Hoyo
 

What's hot (20)

「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料
「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料 「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料
「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
 
新しい暗号技術
新しい暗号技術新しい暗号技術
新しい暗号技術
 
暗号文のままで計算しよう - 準同型暗号入門 -
暗号文のままで計算しよう - 準同型暗号入門 -暗号文のままで計算しよう - 準同型暗号入門 -
暗号文のままで計算しよう - 準同型暗号入門 -
 
入門 シェル実装
入門 シェル実装入門 シェル実装
入門 シェル実装
 
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr
 
Glibc malloc internal
Glibc malloc internalGlibc malloc internal
Glibc malloc internal
 
指数時間アルゴリズム入門
指数時間アルゴリズム入門指数時間アルゴリズム入門
指数時間アルゴリズム入門
 
C++ マルチスレッド 入門
C++ マルチスレッド 入門C++ マルチスレッド 入門
C++ マルチスレッド 入門
 
tcpdumpとtcpreplayとtcprewriteと他。
tcpdumpとtcpreplayとtcprewriteと他。tcpdumpとtcpreplayとtcprewriteと他。
tcpdumpとtcpreplayとtcprewriteと他。
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!
 
自作ペアリング/BLS署名ライブラリの紹介
自作ペアリング/BLS署名ライブラリの紹介自作ペアリング/BLS署名ライブラリの紹介
自作ペアリング/BLS署名ライブラリの紹介
 
Linuxのsemaphoreとmutexを見る 
Linuxのsemaphoreとmutexを見る Linuxのsemaphoreとmutexを見る 
Linuxのsemaphoreとmutexを見る 
 
いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性
 
文字列検索のいろいろ
文字列検索のいろいろ文字列検索のいろいろ
文字列検索のいろいろ
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
Scapyで作る・解析するパケット
Scapyで作る・解析するパケットScapyで作る・解析するパケット
Scapyで作る・解析するパケット
 

Viewers also liked

Xeonphiハッカソンでexpを作ってみた
Xeonphiハッカソンでexpを作ってみたXeonphiハッカソンでexpを作ってみた
Xeonphiハッカソンでexpを作ってみたMITSUNARI Shigeo
 
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 1
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 1CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 1
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 1Computational Materials Science Initiative
 
博士のノンキャリアパス
博士のノンキャリアパス博士のノンキャリアパス
博士のノンキャリアパスMarinChiba
 
Productive parallel programming for intel xeon phi coprocessors
Productive parallel programming for intel xeon phi coprocessorsProductive parallel programming for intel xeon phi coprocessors
Productive parallel programming for intel xeon phi coprocessorsinside-BigData.com
 
鏡はなぜ左右だけ逆になるのか?
鏡はなぜ左右だけ逆になるのか?鏡はなぜ左右だけ逆になるのか?
鏡はなぜ左右だけ逆になるのか?Akira Asano
 
2013年度秋学期 統計学 第2回「統計資料の収集と読み方」
2013年度秋学期 統計学 第2回「統計資料の収集と読み方」2013年度秋学期 統計学 第2回「統計資料の収集と読み方」
2013年度秋学期 統計学 第2回「統計資料の収集と読み方」Akira Asano
 
HOKUSAIのベンチマーク 理研シンポジウム 中田分
HOKUSAIのベンチマーク 理研シンポジウム 中田分HOKUSAIのベンチマーク 理研シンポジウム 中田分
HOKUSAIのベンチマーク 理研シンポジウム 中田分Maho Nakata
 
北海道大学有機元素化学抄録会2014
北海道大学有機元素化学抄録会2014北海道大学有機元素化学抄録会2014
北海道大学有機元素化学抄録会2014Hajime Ito
 
HPCS2015 大規模量子化学計算プログラムSMASHの開発と公開(石村)
HPCS2015 大規模量子化学計算プログラムSMASHの開発と公開(石村)HPCS2015 大規模量子化学計算プログラムSMASHの開発と公開(石村)
HPCS2015 大規模量子化学計算プログラムSMASHの開発と公開(石村)Maho Nakata
 
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 2
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 2CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 2
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 2Computational Materials Science Initiative
 
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013Ryo Sakamoto
 
Kobeworkshop pubchemqc project
Kobeworkshop pubchemqc projectKobeworkshop pubchemqc project
Kobeworkshop pubchemqc projectMaho Nakata
 
セクシー女優で学ぶ画像分類入門
セクシー女優で学ぶ画像分類入門セクシー女優で学ぶ画像分類入門
セクシー女優で学ぶ画像分類入門Takami Sato
 
ジャストシステムJava100本ノックのご紹介
ジャストシステムJava100本ノックのご紹介ジャストシステムJava100本ノックのご紹介
ジャストシステムJava100本ノックのご紹介JustSystems Corporation
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理Norishige Fukushima
 

Viewers also liked (18)

Xeonphiハッカソンでexpを作ってみた
Xeonphiハッカソンでexpを作ってみたXeonphiハッカソンでexpを作ってみた
Xeonphiハッカソンでexpを作ってみた
 
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 1
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 1CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 1
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 1
 
機械工学科へようこそ
機械工学科へようこそ機械工学科へようこそ
機械工学科へようこそ
 
博士のノンキャリアパス
博士のノンキャリアパス博士のノンキャリアパス
博士のノンキャリアパス
 
Productive parallel programming for intel xeon phi coprocessors
Productive parallel programming for intel xeon phi coprocessorsProductive parallel programming for intel xeon phi coprocessors
Productive parallel programming for intel xeon phi coprocessors
 
鏡はなぜ左右だけ逆になるのか?
鏡はなぜ左右だけ逆になるのか?鏡はなぜ左右だけ逆になるのか?
鏡はなぜ左右だけ逆になるのか?
 
2013年度秋学期 統計学 第2回「統計資料の収集と読み方」
2013年度秋学期 統計学 第2回「統計資料の収集と読み方」2013年度秋学期 統計学 第2回「統計資料の収集と読み方」
2013年度秋学期 統計学 第2回「統計資料の収集と読み方」
 
HOKUSAIのベンチマーク 理研シンポジウム 中田分
HOKUSAIのベンチマーク 理研シンポジウム 中田分HOKUSAIのベンチマーク 理研シンポジウム 中田分
HOKUSAIのベンチマーク 理研シンポジウム 中田分
 
北海道大学有機元素化学抄録会2014
北海道大学有機元素化学抄録会2014北海道大学有機元素化学抄録会2014
北海道大学有機元素化学抄録会2014
 
From IA-32 to avx-512
From IA-32 to avx-512From IA-32 to avx-512
From IA-32 to avx-512
 
HPCS2015 大規模量子化学計算プログラムSMASHの開発と公開(石村)
HPCS2015 大規模量子化学計算プログラムSMASHの開発と公開(石村)HPCS2015 大規模量子化学計算プログラムSMASHの開発と公開(石村)
HPCS2015 大規模量子化学計算プログラムSMASHの開発と公開(石村)
 
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 2
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 2CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 2
CMSI計算科学技術特論B(15) インテル Xeon Phi コプロセッサー向け最適化、並列化概要 2
 
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
 
GPU最適化入門
GPU最適化入門GPU最適化入門
GPU最適化入門
 
Kobeworkshop pubchemqc project
Kobeworkshop pubchemqc projectKobeworkshop pubchemqc project
Kobeworkshop pubchemqc project
 
セクシー女優で学ぶ画像分類入門
セクシー女優で学ぶ画像分類入門セクシー女優で学ぶ画像分類入門
セクシー女優で学ぶ画像分類入門
 
ジャストシステムJava100本ノックのご紹介
ジャストシステムJava100本ノックのご紹介ジャストシステムJava100本ノックのご紹介
ジャストシステムJava100本ノックのご紹介
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理
 

Similar to Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)

Intro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたIntro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたMITSUNARI Shigeo
 
Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理Takeshi Arabiki
 
並列対決 Elixir × Go × C# x Scala , Node.js
並列対決 Elixir × Go × C# x Scala , Node.js並列対決 Elixir × Go × C# x Scala , Node.js
並列対決 Elixir × Go × C# x Scala , Node.jsYoshiiro Ueno
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装MITSUNARI Shigeo
 
Shadow gunのサンプルから学べるモバイル最適化
Shadow gunのサンプルから学べるモバイル最適化Shadow gunのサンプルから学べるモバイル最適化
Shadow gunのサンプルから学べるモバイル最適化Katsutoshi Makino
 
Perlと出会い、Perlを作る
Perlと出会い、Perlを作るPerlと出会い、Perlを作る
Perlと出会い、Perlを作るgoccy
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチMasami Ichikawa
 
Go言語のスライスを理解しよう
Go言語のスライスを理解しようGo言語のスライスを理解しよう
Go言語のスライスを理解しようYasutaka Kawamoto
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。Kazuki Onishi
 
AVX命令を用いたLJの力計算のSIMD化
AVX命令を用いたLJの力計算のSIMD化AVX命令を用いたLJの力計算のSIMD化
AVX命令を用いたLJの力計算のSIMD化Hiroshi Watanabe
 
いにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加した
いにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加したいにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加した
いにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加したたけおか しょうぞう
 
PBL1-v1-006j.pptx
PBL1-v1-006j.pptxPBL1-v1-006j.pptx
PBL1-v1-006j.pptxNAIST
 

Similar to Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ) (20)

Prosym2012
Prosym2012Prosym2012
Prosym2012
 
Intro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたIntro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみた
 
HPC Phys-20201203
HPC Phys-20201203HPC Phys-20201203
HPC Phys-20201203
 
Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理
 
フラグを愛でる
フラグを愛でるフラグを愛でる
フラグを愛でる
 
並列対決 Elixir × Go × C# x Scala , Node.js
並列対決 Elixir × Go × C# x Scala , Node.js並列対決 Elixir × Go × C# x Scala , Node.js
並列対決 Elixir × Go × C# x Scala , Node.js
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
 
Rを用いたGIS
Rを用いたGISRを用いたGIS
Rを用いたGIS
 
TVM の紹介
TVM の紹介TVM の紹介
TVM の紹介
 
Shadow gunのサンプルから学べるモバイル最適化
Shadow gunのサンプルから学べるモバイル最適化Shadow gunのサンプルから学べるモバイル最適化
Shadow gunのサンプルから学べるモバイル最適化
 
Perlと出会い、Perlを作る
Perlと出会い、Perlを作るPerlと出会い、Perlを作る
Perlと出会い、Perlを作る
 
Slide
SlideSlide
Slide
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
 
Go言語のスライスを理解しよう
Go言語のスライスを理解しようGo言語のスライスを理解しよう
Go言語のスライスを理解しよう
 
Nginx lua
Nginx luaNginx lua
Nginx lua
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
 
AVX命令を用いたLJの力計算のSIMD化
AVX命令を用いたLJの力計算のSIMD化AVX命令を用いたLJの力計算のSIMD化
AVX命令を用いたLJの力計算のSIMD化
 
llvm入門
llvm入門llvm入門
llvm入門
 
いにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加した
いにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加したいにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加した
いにしえ的ななにか、カニか? RISC-V picoRV32, e203 改造 オレオレ命令追加した
 
PBL1-v1-006j.pptx
PBL1-v1-006j.pptxPBL1-v1-006j.pptx
PBL1-v1-006j.pptx
 

More from MITSUNARI Shigeo

暗号技術の実装と数学
暗号技術の実装と数学暗号技術の実装と数学
暗号技術の実装と数学MITSUNARI Shigeo
 
範囲証明つき準同型暗号とその対話的プロトコル
範囲証明つき準同型暗号とその対話的プロトコル範囲証明つき準同型暗号とその対話的プロトコル
範囲証明つき準同型暗号とその対話的プロトコルMITSUNARI Shigeo
 
暗認本読書会13 advanced
暗認本読書会13 advanced暗認本読書会13 advanced
暗認本読書会13 advancedMITSUNARI Shigeo
 
深層学習フレームワークにおけるIntel CPU/富岳向け最適化法
深層学習フレームワークにおけるIntel CPU/富岳向け最適化法深層学習フレームワークにおけるIntel CPU/富岳向け最適化法
深層学習フレームワークにおけるIntel CPU/富岳向け最適化法MITSUNARI Shigeo
 
WebAssembly向け多倍長演算の実装
WebAssembly向け多倍長演算の実装WebAssembly向け多倍長演算の実装
WebAssembly向け多倍長演算の実装MITSUNARI Shigeo
 
Lifted-ElGamal暗号を用いた任意関数演算の二者間秘密計算プロトコルのmaliciousモデルにおける効率化
Lifted-ElGamal暗号を用いた任意関数演算の二者間秘密計算プロトコルのmaliciousモデルにおける効率化Lifted-ElGamal暗号を用いた任意関数演算の二者間秘密計算プロトコルのmaliciousモデルにおける効率化
Lifted-ElGamal暗号を用いた任意関数演算の二者間秘密計算プロトコルのmaliciousモデルにおける効率化MITSUNARI Shigeo
 
BLS署名の実装とその応用
BLS署名の実装とその応用BLS署名の実装とその応用
BLS署名の実装とその応用MITSUNARI Shigeo
 
LazyFP vulnerabilityの紹介
LazyFP vulnerabilityの紹介LazyFP vulnerabilityの紹介
LazyFP vulnerabilityの紹介MITSUNARI Shigeo
 

More from MITSUNARI Shigeo (20)

暗号技術の実装と数学
暗号技術の実装と数学暗号技術の実装と数学
暗号技術の実装と数学
 
範囲証明つき準同型暗号とその対話的プロトコル
範囲証明つき準同型暗号とその対話的プロトコル範囲証明つき準同型暗号とその対話的プロトコル
範囲証明つき準同型暗号とその対話的プロトコル
 
暗認本読書会13 advanced
暗認本読書会13 advanced暗認本読書会13 advanced
暗認本読書会13 advanced
 
暗認本読書会12
暗認本読書会12暗認本読書会12
暗認本読書会12
 
暗認本読書会11
暗認本読書会11暗認本読書会11
暗認本読書会11
 
暗認本読書会10
暗認本読書会10暗認本読書会10
暗認本読書会10
 
暗認本読書会9
暗認本読書会9暗認本読書会9
暗認本読書会9
 
暗認本読書会8
暗認本読書会8暗認本読書会8
暗認本読書会8
 
暗認本読書会7
暗認本読書会7暗認本読書会7
暗認本読書会7
 
暗認本読書会6
暗認本読書会6暗認本読書会6
暗認本読書会6
 
暗認本読書会5
暗認本読書会5暗認本読書会5
暗認本読書会5
 
暗認本読書会4
暗認本読書会4暗認本読書会4
暗認本読書会4
 
深層学習フレームワークにおけるIntel CPU/富岳向け最適化法
深層学習フレームワークにおけるIntel CPU/富岳向け最適化法深層学習フレームワークにおけるIntel CPU/富岳向け最適化法
深層学習フレームワークにおけるIntel CPU/富岳向け最適化法
 
私とOSSの25年
私とOSSの25年私とOSSの25年
私とOSSの25年
 
WebAssembly向け多倍長演算の実装
WebAssembly向け多倍長演算の実装WebAssembly向け多倍長演算の実装
WebAssembly向け多倍長演算の実装
 
Lifted-ElGamal暗号を用いた任意関数演算の二者間秘密計算プロトコルのmaliciousモデルにおける効率化
Lifted-ElGamal暗号を用いた任意関数演算の二者間秘密計算プロトコルのmaliciousモデルにおける効率化Lifted-ElGamal暗号を用いた任意関数演算の二者間秘密計算プロトコルのmaliciousモデルにおける効率化
Lifted-ElGamal暗号を用いた任意関数演算の二者間秘密計算プロトコルのmaliciousモデルにおける効率化
 
楕円曲線と暗号
楕円曲線と暗号楕円曲線と暗号
楕円曲線と暗号
 
BLS署名の実装とその応用
BLS署名の実装とその応用BLS署名の実装とその応用
BLS署名の実装とその応用
 
LazyFP vulnerabilityの紹介
LazyFP vulnerabilityの紹介LazyFP vulnerabilityの紹介
LazyFP vulnerabilityの紹介
 
ゆるバグ
ゆるバグゆるバグ
ゆるバグ
 

Recently uploaded

Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Danieldanielhu54
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 

Recently uploaded (10)

Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 

Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)

  • 2. 簡単に自己紹介 ²  神戸の京コンの建物でポスドクしています ³  09年3月、東大理学天文で博士号(一応天体物理学者) ³  指導教員はGRAPEで有名な牧野淳一郎 ³  ポスドク5年目(3つ目) ²  専門(自己申告):N体計算の高速化、並列化、 アルゴリズム改良、良い実装を作る ³  SSE/AVX/CUDA/MPI/OpenMPあたりはカバー ³  最近はXeon phiやHaswellなど ³  アセンブラの知識:組み込み関数でSIMD書いたり コンパイラの吐いたasmを眺める程度 ³  「京」向けのチューンも
  • 3. ゴードン・ベル賞に関して ²  スパコン上でのアプリケーションに対する論文賞 ³  ベンチマークランキング(TOP500, HPCC)ではない ³  冬にはスパコンを確保し計算を走らせたい ³  春に12ページぐらいの論文を投稿 ³  夏にはfinalist/不採択の結果通知がくる ³  秋のSC学会で口頭発表、それから受賞論文の発表 ²  似鳥が入った論文の成績 ³  09年:長崎のGeForceクラスタで価格性能部門賞、 10年には同部門佳作賞 (Honorable Mansion) ³  12年:「京」で受賞(部門なしの単独受賞) ³  06、07、08、13年には落選
  • 4. 今日話す内容 ²  どうやって40∼60分も間を持たせよう、、、 ³  適当に割り込み、つっこみお願いします ²  専門のN体計算のお話 ³  高次積分法で高精度に計算するお話 ®  Xeon Phi Nativeで実装したよ ³  テーブル参照で任意のforce shapeを実現するお話 ®  SSE/AVXでテーブル参照を頑張った ²  その際の若干トリッキーな最適化の話題 ³  普段のセミナーで「そんな話嬉しそうに延々とされても 困ります」といわれるような話題をいくつか ³  Xeon Phi (KNC)とAVX-512の命令セットの概観
  • 5. N体計算の支配方程式 ²  式はひとつ(話題は無数) ²  減算3回、積和6回、乗算3回、逆数平方根1回 ²  i-loopとj-loopの二重ループ、O(N2) ²  j-粒子がi-粒子を引っ張る ²  i-並列とj-並列のふたつの並列度 ³  i-並列ではj-粒子の放送によってメモリ帯域を節約 ³  j-並列では最後に部分力の総和演算が必要 ないし(発散を避けるために)  
  • 6. コードのほうが分 り易いという人用 ²  流用資料につき混合精度 ²  外側ループのomp parallel化は自明に近い と思う ²  レジスタが余っていたら 外側ループをアンロール しよう ²  j-粒子がキャッシュに収 まるようなブロック化/ 並列化も有効 6 const float mj[] , 7 const float eps2 , 8 double acci[][3]) 9 { 10 for(int i=0; i<ni; i++){ 11 const double xi = posi[i][0]; 12 const double yi = posi[i][1]; 13 const double zi = posi[i][2]; 14 double ax = 0.0; 15 double ay = 0.0; 16 double az = 0.0; 17 for(int j=0; j<nj; j++){ 18 const float dx = float(posj[j][0] - xi); 19 const float dy = float(posj[j][1] - yi); 20 const float dz = float(posj[j][2] - zi); 21 const float r2 = eps2 + dx*dx + dy*dy + dz*dz; 22 const float ri2 = 1.0f / r2; 23 const float mri1 = m[j] * sqrtf(ri2); 24 const float mri3 = mri1 * ri2; 25 ax += double(mri3 * dx); 26 ay += double(mri3 * dy); 27 az += double(mri3 * dz); 28 } 29 acc[i][0] = ax; 30 acc[i][1] = ay; 31 acc[i][2] = az; 32 } 33 } このぐらいに書いておけば、コンパイラが「無駄なコード」を吐くことはまずない。コ によっては、部分的に SIMD 命令を使ってくれることもあるだろうが、得られる性能は
  • 7. 高次の方法(4次のHermite積分法) ²  加速度の一階微分(jerk)も直接計算 ³  コスト:「倍にはならない」 ²  補間多項式を積分 ³  Hermite補間 ³  積分の始点と終点で、実質4点分の情報 ²  予測子修正子法 ³  未来の座標はテイラー展開で予測 ³  未来の加速度とjerkを予測子から計算 ³  補間多項式から修正子を構築 ³  反復してもいいけどしなくても4次精度 ®  Runge-Kuttaより高効率 t f Δv i+1i もっと高階微分も計算できる?(できます)
  • 8. 高階微分の計算 ²  2階微分(snap)まで使って6次精度 ²  3階微分(crackle)まで使って8次精度 ³  次の微分にはpopと名前が付いている ²  高次のものほど ³  レジスタ消費は多い ³  積和比率が高い(逆数平方根は一回) ³  同期オーバーヘッドが相対的に小さい 38  ops 60  ops 97  ops 144  ops Acceleration: Jerk: Snap: Crackle: .2.2 Direct calculation of higher order derivatives The gravitational acceleration from a particle j on a particle i and its first three me derivatives are expressed as Aij = mj rij r3 ij , (2.1) Jij = mj vij r3 ij − 3αAij, (2.2) Sij = mj aij r3 ij − 6αJij − 3βAij, (2.3) Cij = mj jij r3 ij − 9αSij − 9βJij − 3γAij. (2.4) Here, we call the first four time derivatives of the acceleration jerk, snap, crackle and op, and α, β and γ are given by α = rij · vij r2 ij , (2.5) β = |vij|2 + rij · aij r2 ij + α2 , (2.6) γ = 3vij · aij + rij · jij 2 + α(3β − 4α2 ), (2.7) al acceleration from a particle j on a particle i and its first three re expressed as Aij = mj rij r3 ij , (2.1) Jij = mj vij r3 ij − 3αAij, (2.2) Sij = mj aij r3 ij − 6αJij − 3βAij, (2.3) Cij = mj jij r3 ij − 9αSij − 9βJij − 3γAij. (2.4) first four time derivatives of the acceleration jerk, snap, crackle and γ are given by α = rij · vij r2 ij , (2.5) β = |vij|2 + rij · aij r2 ij + α2 , (2.6) γ = 3vij · aij + rij · jij r2 ij + α(3β − 4α2 ), (2.7) i and mi are the position, velocity, total acceleration, total jerk and Aij = mj rij r3 ij , (2.1) Jij = mj vij r3 ij − 3αAij, (2.2) Sij = mj aij r3 ij − 6αJij − 3βAij, (2.3) Cij = mj jij r3 ij − 9αSij − 9βJij − 3γAij. (2.4) rst four time derivatives of the acceleration jerk, snap, crackle and γ are given by α = rij · vij r2 ij , (2.5) β = |vij|2 + rij · aij r2 ij + α2 , (2.6) γ = 3vij · aij + rij · jij r2 ij + α(3β − 4α2 ), (2.7) and mi are the position, velocity, total acceleration, total jerk and and rij = rj − ri, vij = vj − vi, aij = aj − ai and jij = jj − ji divとsqrtをそれぞれ   10演算と数えてある
  • 9. for(int j=0; j<nj; j++){ ! const dvec3 dr = pred[j].pos - posi; ! const dvec3 dv = pred[j].vel - veli; ! const dvec3 da = pred[j].acc - acci; ! const dvec3 dj = pred[j].jrk - jrki; ! ! const double r2 = eps2 + dr*dr; ! const double drdv = dr*dv; ! const double dvdv = dv*dv; ! const double drda = dr*da; ! const double dvda = dv*da; ! const double drdj = dr*dj; ! ! const double ri2 = 1.0 / r2; ! const double mri3 = pred[j].mass * ri2 * sqrt(ri2); ! const double alpha = drdv * ri2; ! const double beta = (dvdv + drda)*ri2 + alpha*alpha; ! const double gamma = (3.0*dvda + drdj)*ri2 + alpha*(3.0*beta - 4.0*alpha*alpha); ! dvec3 tmp1 = dv + (-3.0*alpha) * dr; ! dvec3 tmp2 = da + (-6.0*alpha) * tmp1 + (-3.0*beta) * dr; ! dvec3 tmp3 = dj + (-9.0*alpha) * tmp2 + (-9.0*beta) * tmp1 + (-3.0*gamma) * dr;! ! acc += mri3 * dr;! jrk += mri3 * tmp1;! snp += mri3 * tmp2;! crk += mri3 * tmp3;! } 実装例 ²  書き散らかしたの置いたので見てね ³  https://github.com/nitadori/ Hermite/blob/master/SRC/ hermite8.h ³  誰か.ignoreその他教えてください ³  AVX/MIC/K版があります ³  積和が多いと嬉しいね
  • 10. 独立時間刻み法 ²  重力のN体計算では近接遭遇が多発 ³  いちいち全部の粒子の時間刻みを最小のものに切り 揃えていては無駄が多い ³  粒子ごとにadaptiveに刻み幅を下げることを考える ®  とりあえず2の冪に ®  他の粒子の座標には「予測子」を使う 1/1   1/2   1/4   1/8   •  同時にNact個のactive粒子をアップデート •  全N粒子の予測子を計算:O(N) •  Nact個の粒子の加速度を計算:O(NactN) •  力を積分して修正子:O(Nact) •  <Nact>∼N2/3
  • 11. 続き(ちょっと物理数学) ²  単位箱にN個の粒子をランダムに置いたときの平均粒子間距 離はN -1/3 ³  これはまあいいでしょう ²  そのときの最小の粒子ペア距離の期待値はN -2/3 ³  これを示すのは大変(誰かhelp!) ²  結果共有時間刻みではN個の粒子を同時に積分できたのが、 独立時間刻みではN2/3個に ³  時間刻みは最近接粒子との距離に比例すると仮定 ³  N=1000に対し<Nact>=50ぐらい(系の中心集中度や積分次数 にも依ります) ³  大幅に高速化したのはいいがi-粒子の並列度がそのまま食われて しまった
  • 12. 時間刻みの決め方 ²  Hermite補間の際に得られた加 速度の時間微分から次の時間刻 みを決定 ³  経験的な公式 ³  pは積分次数、ηは精度パラメタ ²  1/6乗や1/10乗が発生するのが ちょっと嫌 ³  しかも結果は2の冪に丸められる ³  というわけで最適化 ³  これでlibmathいらず template <int N> ! double pow_one_nth_quant(! const double x)! {! assert(x > 0.0); ! union{ double d;! unsigned long l; ! } m64; ! m64.d = x;! const int dec = 1023 % N;! const int inc = 1023 - 1023 / N; m64.l >>= 52; m64.l -= dec;! m64.l /= N; ! m64.l += inc;! m64.l <<= 52;! return m64.d;! }
  • 13. 1ステップの手続き 1.  積分する粒子を選ぶ:O(Nact) or O(logN) (serial) 2.  全粒子の予測子を計算:O(N) (parallel) 3.  重力を計算:O(NactN) (parallel) 4.  修正子と新しい時間刻みを計算:O(Nact) (parallel) 5.  粒子を時間刻み順にソート:O(NactlogNact) (serial)
  • 14. そろそろXeon Phiの話 ²  Xeon Phi 5110P (Knights Corner) ³  1.053 GHz ³  60 core, 240 threads ³  512-bit FMA (16 DP flop/cycle), 1011 DP, 2022 SP Gflops ³  60 x (32KB L1I, 32KB L1D, 512KB L2) ²  32本の512-bit zmmレジスタ ³  レジスタ幅がキャッシュライン幅に追いついた(64-byte) ³  4スレッドで8KBi! ³  float x16 or double x8 ³  16-bitのマスクレジスタが8本 ³  xmmもymmもない(Pentium互換+X64+独自拡張)
  • 15. AVX-512の概観(ぱっと見) ²  次世代KNL (Knights Landing)から ³  普通のXeon/Core iにも搭載されるのだろうか? ²  XMM/YMMが復活、ZMMと共に32本 ³  マスクレジスタ、swizzle、bcastもサポート ²  EVEX prefix ³  62hからの4-byte ²  KNC(現行のPhi)のベクトル命令をベースにSSE/ AVXと下位互換を取るように整理したもの、といった 感じ ³  数学関数の取り扱いが若干変わった
  • 16. プログラミングモデル ²  Native mode ³  Phiのカード上でLinuxが動いていてsshで入れる ³  ホストのディレクトリをNFS経由でマウントできる ®  icc -mmic hello.c ssh mic0 ./a.out ³  コードはintrinsicsとOpenMPで書いておく ®  zmmintrin.h (included from immintrin.h), micvec.h (for C++) ²  Offload mode ³  ホスト実行のコードの一部を#pragma offloadで切り出す ³  GPU的な使い方(生産性は高いとの主張) ³  似鳥は試したことないのでよくわかりません、 講習会とかもやってるっぽい
  • 17. ニーモニック ²  vaddpd zmm1{k1}, zmm2, zmm3/mem ³  zmm1 = zmm2 + zmm3/mem ³  k1: マスクレジスタで結果代入をマスクできる ³  zmm3: swizzleが使える! ®  dcba-> dcba (no swizzle), cdab (swap inner), badc (swap outer), dacb (cross prod), aaaa, bbbb, cccc, dddd (bcast) ³  mem: 放送と型変換(upconv)ができる! ®  DP: 8to8, 4to8, 1to8 ®  SP: 16to16, 4to16, 1to16 ®  適切にalignされていること
  • 18. load/store ²  ZMMレジスタとキャッシュラインサイズが64 byteで一致 ²  Aligned load/store ³  単にvmovapd ³  no-read, no-global-orderingのstreaming store命令も存在 ²  Unaligned load/store ³  2ライン触るので2命令 ®  v1  =  _mm512_loadunpacklo_pd(v1,  mt);   ®  v1  =  _mm512_loadunpackhi_pd(v1,  mt+64);   ®  warning  (uninitialized  v1)を消す方法ありませんか?   ²  Gather/Scatter ³  速度はともかく、命令が存在する ³  コストは触ったライン数に依存とのこと
  • 19. 積和命令 ²  VFMADD{132¦213¦231}PD zmm1, zmm2, zmm3 ³  zmm1 = zmm1 * zmm3 + zmm2 ³  zmm1 = zmm2 * zmm1 + zmm3 ³  zmm1 = zmm2 * zmm3 + zmm1 ²  あと符号で4種類(*́д`*) ²  swizzle/メモリオペランドは第3opのみ使える ²  まあ、mulとadd/subで書いとけばコンパイラがやってくれ るんだけど ²  intrinsicsは4オペランド形式 ²  swizzleと混ぜるときはmovの数が最小になるといいですね
  • 20. swizzle万歳 ²  レジスタ1本で4つの定数を格納できる ²  C++ラッパのほうが見た目がasmに近い ³  ただしswizzleメソッドがconstになってないというバグ仕様 ³  サンプルのasmはAT&T形式です、すみません #include <micvec.h>! ! F64vec8 poly3(F64vec8 x, F64vec8 coef){! return coef.aaaa() + x*(coef.bbbb() + x*(coef.cccc() + x*(coef.dddd())));! }! F64vec8 poly3(F64vec8 x, const double *coef){! return F64vec8(coef[0]) + x*(F64vec8(coef[1]) + x*(F64vec8(coef[2]) + x*(F64vec8(coef[3]))));! }! poly3(F64vec8, F64vec8):! vmovdqa64 %zmm1{dddd}, %zmm2 ! vfmadd213pd %zmm1{cccc}, %zmm0, %zmm2 ! vfmadd213pd %zmm1{bbbb}, %zmm0, %zmm2 ! vfmadd213pd %zmm1{aaaa}, %zmm2, %zmm0 ! ret poly3(F64vec8, double const*):! vbroadcastsd 24(%rdi), %zmm1 vfmadd213pd 16(%rdi){1to8}, %zmm0, %zmm1 vfmadd213pd 8(%rdi){1to8}, %zmm0, %zmm1 vfmadd213pd (%rdi){1to8}, %zmm1, %zmm0 ret
  • 21. Shuffle系の命令 ²  mask_blendとswizzleでかなりのことができる ³  vblendmps, vblendmpd ³  引数のマスクレジスタで要素を選択 ³  組み込み関数からだと即値指定(imm16/imm8)も可能だけど、 実際は汎用レジスタ経由でマスクレジスタに飛ばされる ²  4語(単精度で128-bit、倍精度で256-bit)の単位をまたい でshuffleしたい場合 ³  vpermf32x4 zmm1{k1}, zmm2/mt, imm8 ®  128-bitが4つあるのを、imm8で並び替え ³  vpermd zmm{k1}, zmm2, zmm3/mt ®  32-bitが16語あるのを任意に並び替え ®  indicatorはimmではなくてzmm2の各語下位4-bit
  • 22. 応用:4x4行列転置 ²  上4語と下4語で同時に static  inline  void  transpose_4zmm_pd(F64vec8  &v0,  F64vec8  &v1,  F64vec8  &v2,  F64vec8  &v3){          F64vec8  c1c0a1a0  =  _mm512_mask_blend_pd(0xaa,  v0,  v1.cdab());          F64vec8  c3c2a3a2  =  _mm512_mask_blend_pd(0xaa,  v2,  v3.cdab());          F64vec8  d1d0b1b0  =  _mm512_mask_blend_pd(0x55,  v1,  v0.cdab());          F64vec8  d3d2b3b2  =  _mm512_mask_blend_pd(0x55,  v3,  v2.cdab());                    F64vec8  aaaa  =  _mm512_mask_blend_pd(0xcc,  c1c0a1a0,  c3c2a3a2.badc());          F64vec8  bbbb  =  _mm512_mask_blend_pd(0xcc,  d1d0b1b0,  d3d2b3b2.badc());          F64vec8  cccc  =  _mm512_mask_blend_pd(0x33,  c3c2a3a2,  c1c0a1a0.badc());          F64vec8  dddd  =  _mm512_mask_blend_pd(0x33,  d3d2b3b2,  d1d0b1b0.badc());                    v0  =  aaaa;                                                                                                                                                    v1  =  bbbb;                                                                                                                                                    v2  =  cccc;                                                                                                                                                    v3  =  dddd;                                                                                                                                             }     ²  マスクレジスタを4本消費 ³  もっといい方法あったら教えてください
  • 23. 用途 ²  インテルさんはSoA推奨だけど ³  x[N], y[N], z[N], m[N]みたいの ²  AoSにしたいこともよくあるわけです ³  {x, y, z, m}[N]みたの ³  高次積分のN体だともっとメンバ多いし ²  今回のN体コードの実装 ³  i-粒子4並列、j-粒子2並列で8-way SIMD ³  i-粒子:{x0, x1, x2, x3, x0, x1, x2, x3} ®  yとzも同様 ®  さっきの転置で作っておく ³  j-粒子:{x0, y0, z0, m0, x1, y1, z1, m1} ®  swizzleで放送
  • 24. コードはこんな感じ ²  vsubrpdという新命令で-(lhs-rhs)を計算 ³  rhsしかswizzleできないので痒い所に手が届く ³  別にこう書かなくてもコンパイラがやってくれるけど for(int j=jbeg; j<jend; j+=2){! const double *jptr = (double *)(&pred[j/2]);! _mm_prefetch((char *)(jptr + 16), _MM_HINT_T0);! _mm_prefetch((char *)(jptr + 24), _MM_HINT_T0);! F64vec8 jxbuf = *(__m512d *)(jptr + 0); ! F64vec8 jvbuf = *(__m512d *)(jptr + 8); ! ! const F64vec8 dx = -(xi - jxbuf.aaaa());! const F64vec8 dy = -(yi - jxbuf.bbbb());! const F64vec8 dz = -(zi - jxbuf.cccc());! const F64vec8 dvx = -(vxi - jvbuf.aaaa());! const F64vec8 dvy = -(vyi - jvbuf.bbbb());! const F64vec8 dvz = -(vzi - jvbuf.cccc());! ...! } •  j-粒子のL1への手動プリ フェッチは有効であった •  ハードもコンパイラもL1へは 無闇にPFするわけにもいかな いため
  • 25. 60コア240スレッドの使い方 ²  単純i-並列/j-並列で使うには多すぎる ³  今回の実装では、コア内4スレッドをi-並列に 60コアをj-並列にしてみた ®  環境変数KMP_AFFINITY=compactとしておくと、コ ア内4スレッドが連番に ®  OpenMPでは0から239のスレッド番号が取得できる ®  j-粒子が分割キャッシュに乗るという目論見 ®  affinityを切ると若干の性能低下 ®  部分力[Nact][60]はメモリに書き出して後から総和を 取る
  • 26. 性能 ²  コードは倍精度の4/6/8次積分法 ³  相互作用あたり60/97/144演算とした ³  横軸は粒子数N ²  比較用:Haswell i7 4C8T 3.40 GHz ³  217.6 Gflops peak ³  AVXで開発済みだったコードをGCC 4.81で -O2 -march=core-avx2(積和化された)
  • 29. 同期が遅い! ²  omp barrierで20μs、omp parallel {}で30μsぐらい 持っていかれる(実測) ³  Opteron 4 socket, 8 die, 64 coreのマシンより遅い ³  ステップあたり5回同期していたので納得できる ²  粒子ソートもHaswellの50倍ぐらい遅かった ³  同期と同様馬鹿にならない時間がかかっていた ²  Xeon Phiのボトルネック ³  個々のコアが貧弱(これは仕方ないかもだけど) ³  コア間通信が遅い(キャッシュが分散しているため) ®  ランタイムの改良で若干改善できるかも(同期の階層化) ²  なんか、殆どGPUだよね(今日のPhiの話はここまで)
  • 30. カットオフ関数がある計算 ²  宇宙論的なN体計算だと ³  遠方から(低周波)の重力は一様メッシュとFFTで ³  近距離(高周波)の重力は粒子から直接計算する方 法がよく使われる ®  このとき到達距離が数メッシュ間隔ぐらいのカットオフ関数 が掛かる ²  SSE/AVXで無理矢理テーブル参照で実装 ²  「京」でのGB賞ではこの関数を直接計算した
  • 31. 具体的なかたち ²  教科書にあったもの ²  分岐を排除したもの ³  「京」ではこれを直接計算した なく、S2 分布に対する厳密解であることには注意。 P3 M 法の PP パート(つまりは S2 soften された PM force の Newton 重力からの残 差)での重力相互作用へのカットオフ関数  ai = j=i mj(rj − ri) |rj − ri|3 gP3M(|rj − ri|)/η), (3) として表現する場合は、  gP3M(R) =    1 − 1 140 ` 224R3 − 224R5 + 70R6 + 48R7 − 21R8 ´ (0 ≤ R ≤ 1) 1 − 1 140 ` 12 − 224R2 + 869R3 − 840R4 + 224R5 + 70R6 − 48R7 + 7R8 ´ (1 ≤ R ≤ 2) 0 (2 ≤ R) , (4) とあらわせる。 2 φ(R) =   1 140 ˆ 208 − 112R2 + 56R4 − 14R5 − 8R6 + 3R7 ˜ (0 ≤ R ≤ 1) 1 140 » 12 R + 128 + 224R − 448R2 + 280R3 − 56R4 − 14R5 + 8R6 − R7 – (1 ≤ R ≤ 2) 1 R (2 ≤ R) . (5) 3 Optimization このままでは演算量も多く分岐もあるため、PP 相互作用の度にこれを計算するのはさ すがに無視できないコストとなる。そこでモダンな汎用計算機のための効率的な式変形を 試みてみよう。 S ≡ max(0, R − 1), (6) として、 gP3M(R) = 1 + R3 − 8 5 + R2 8 5 + R − 1 2 + R − 12 35 + R 3 20 − S6 3 35 + R 18 35 + R 1 5 (0 ≤ R ≤ 2) (7) ポテンシャルも写経: φ(R) =    1 140 ˆ 208 − 112R2 + 56R4 − 14R5 − 8R6 + 3R7 ˜ 1 140 » 12 R + 128 + 224R − 448R2 + 280R3 − 56R4 − 14R5 1 R 3 Optimization このままでは演算量も多く分岐もあるため、PP 相互作用の度に すがに無視できないコストとなる。そこでモダンな汎用計算機のた 試みてみよう。 S ≡ max(0, R − 1), として、
  • 33. テーブル参照で関数を評価 ²  普通に考えれば(int)(scale * r)でindexを 生成して適当な次数で補間してf(r)を計算 ²  しかし、r2 → f(r)/r3 を一発で評価するのが 最速に思える ³  サンプル間隔も最適に近い物を選びたい ³  何をindexに使うか、どうやって得るか? ³  若干トリッキーな方法をとった
  • 34. indexの生成 ²  座標は適当にスケールしておく ²  s = 2.0f + r2を計算 ²  指数部の下位4-bitと仮数部の上位6-bitを用いる ³  17-bit右シフトだけでいい ³  あとは1次補間で必要な精度に smax À 2 smax À 2 ’ 1 ð2F þ bFÞ1=2 2bEþ1 =2Fþ2 smax À 2 !1=2 ; ð5Þ where we also assume bE ) 1 and F ) 1 for the last approximation. Therefore, the sampling points with the same fraction bits are dis- tributed uniformly in logarithmic scale, and those with the same exponent bits are aligned uniformly in linear scale unless the frac- tion bit is small. As an example, we illustrate how the sampling points of the look-up table depend on the pre-defined integers E and F in Fig. 4. We first see the cases in which either of E and F is zero, in Table 4 s-values, their exponent and fraction bits in the IEEE754 expressions, and their indices in the table for r ¼ 0, rcut=2 and rcut in the case of E ¼ 4 and F ¼ 6 (underlined portion of exponent and fraction bits). r s Exponent bits Fraction bits Index 0 2 (smin) 10000000 00000000000000000000000 0 rcut=2 3:2514 Â 104 10001101 11111100000001100000000 895 rcut 1:3005 Â 105 10001111 11111100000000000000000 1023 (smax) 10 -2 10 -1 10 0 10 1 10 2 10 3 10 4 f(r)rcut 3 /r Conventional 10 -2 10 -1 10 0 10 1 10 2 10 3 10 4 10 -3 10 -2 10 -1 10 0 f(r)rcut 3 /r r / rcut Presented A. Tanikawa et al
  • 35. AVXでのテーブル参照 ²  GatherはAVX2から(しかも遅い) ²  テーブルの実体は補間用の係数を含めてfloat table[1024][2]; ²  indexはpextrwないしL1経由で汎用レジス タに転送 ²  gatherの代わりに(movlps, movhps)^2, vinsertf128 ²  あとは適当にシャッフル
  • 36. 適当にシャッフル d5 f5 d4 f4 d1 f1 d0 f0 d7 f7 d6 f6 d3 f3 d2 f2 f0f1f2f3f4f5f6f7 d0d1d2d3d4d5d6d7 vshufps 0x88 vshufps 0xdd 0x88 = 2020(4), 0xdd = 3131(4)
  • 37. AVX2のコード(GCC) for(j=0; j<nj; j+=2){! v8sf xj = __builtin_ia32_shufps256(jp, jp, 0x00);! v8sf yj = __builtin_ia32_shufps256(jp, jp, 0x55);! v8sf zj = __builtin_ia32_shufps256(jp, jp, 0xaa);! v8sf mj = __builtin_ia32_shufps256(jp, jp, 0xff);! jp = *(v8sf *)(jpdata+=2);! ! v8sf dx = xj - xi, dy = yj - yi, dz = zj - zi;! v8sf r2 = ((two + dx*dx) + dy*dy) + dz*dz;! r2 = __builtin_ia32_minps256(r2, r2cut);! v8si r2_sr = __builtin_ia32_psrldi256((v8si)r2, 23-FRC_BIT);! v8si r2_sl = __builtin_ia32_pslldi256(r2_sr, 23-FRC_BIT);! unsigned int idx[8] __attribute__((aligned(32)));! *(v8si *)idx = r2_sr;! const long long *ptr = (long long *)fcut;! v4di tbl_0145 = {ptr[idx[0]], ptr[idx[1]], ptr[idx[4]], ptr[idx[5]]};! v4di tbl_2367 = {ptr[idx[2]], ptr[idx[3]], ptr[idx[6]], ptr[idx[7]]};! ! v8sf ff = __builtin_ia32_shufps256((v8sf)tbl_0145, (v8sf)tbl_2367, 0x88);! v8sf df = __builtin_ia32_shufps256((v8sf)tbl_0145, (v8sf)tbl_2367, 0xdd);! v8sf dr2 = r2 - (v8sf)r2_sl;! ff += dr2 * df;! ! v8sf mf = mj * ff;! ax += mf * dx; ay += mf * dy; az += mf * dz;! }! 配列初期化子任せ shufpsで放送 粒子のプリロード 積和算 256-­‐bit整数命令 L1を経由 1次補間
  • 38. 逆数平方根 ²  近似命令から収束公式だね! ³  Newton重力の計算を大幅に高速化 ²  2次収束を繰り返すだけが能じゃない ³  例:rsqrtpsは12-bit精度、53-bitの倍精度に近づけたければ ®  2次収束を3回 ®  単精度で2次収束をかけて倍精度で3次収束 ®  5次収束一発 ³  積和算一回につき1次増やせる ®  係数のレジスタ圧迫は問題 ³  任意のx-n/mに拡張できる ®  h = 1 ‒ xnym ®  y *= taylor[(1 ‒ h)-1/m]
  • 39. ハードのサポート状況 ²  3DNow! (忘れないでね) ³  pfrsqrt, pfrsqrti1, pfrsqrti2 ³  15-bitの近似と、収束補助命令 ²  SSE/AVX ³  rsqrtps ³  12-bitの近似命令 ³  y *= (1.5f - (0.5f*x)*y*y)ないしy += y*(0.5f - (0.5f*x)*y*y)でほぼ単精度 ³  倍精度からだと型変換が煩わしい ²  Xeon Phi (KNC) ³  vrsqrt23ps ³  23-bit、なんと単精度なら生でいい ³  倍精度なら3次収束をかける ²  AVX-512 ³  vrsqrt{14¦28}{ss¦ps¦sd¦pd} ³  14-bitと、オプション(?)で28-bitになった ³  倍精度から直接呼べるというのが何より嬉しい、2次収束一発でいい ²  HPC-ACE (Sparc64, K computer extension) ³  倍精度2語に対して8-bit精度 ³  高級言語からはコンパイラが2次収束を3回吐く(組み込み関数で明示も可能)
  • 40. 周期境界の補正 ²  周期境界では、絶対座標は0≤x<1、 相対座標は−0.5<Δx≤0.5のようにしたい ³  じゃあ整数で、という人もここには多いでしょうが、、、 ³  境界の開閉はこだわらないことにする ®  ここだけの話、倍精度から単精度の変換で絶対座標が1.0fになってしまうバグ出したこ とある ³  x -= round(x)みたく補正できばOK ®  call無し、分岐無し、ハードで SIMDでやりたいよね ®  roundpsとかなくても演算器の 後には丸めユニットがあります double myround(double x){! // returns! // -1 for -1.5 < x <= -0.5! // 0 for -0.5 < x <= 0.5! // 1 for 0.5 < x <= 1.5! x += (double)(1 + (1LL << 52));! x -= (double)(1 + (1LL << 52));! return x;! }!
  • 41. Morton曲線とPeano-Hilbert曲線 ²  Octree構造と密接な関係 ³  Morton/PH keyを作ってソートしておくツリーがで きたも同然 ³  キャッシュヒットの改善、並列化のための領域分割に も使われる ³  2次元でのMorton ordering(左)と Hilbert ordering(右)
  • 42. Morton keyの実装 ²  x, y, zをそれぞれ21- bit整数にしたらビッ トシャッフルするだ け ³  ...cba(2) -> ...00c00b00a(2) uint64 gen_morton(unsigned x, unsigned y, unsigned z){! uint64 key = 0;! for(int ish=20; ish>=0; ish--){! unsigned ix = (x>>ish)&1;! unsigned iy = (y>>ish)&1;! unsigned iz = (z>>ish)&1;! unsigned idx = 4*iz | 2*iy | ix;! key = (key<<3) | idx;! }! return key;! } Then we can apply bit-based dilate primitives to compute the Morton key (List.1, [44]). This dilate primitive converts the first 10 bits of an integer to a 30 bit representation, i.e. 0100111011 ! 000 001 000 000 001 001 001 000 001 001: List 1: The GPU code which we use to dilate the first 10-bits of an integer. 1 int dilate(const int value) { 2 unsigned int x; 3 x = value & 0x03FF; 4 x = ((x << 16) + x) & 0xFF0000FF; 5 x = ((x << 8) + x) & 0x0F00F00F; 6 x = ((x << 4) + x) & 0xC30C30C3; 7 x = ((x << 2) + x) & 0x49249249; 8 return x; 9 } こんな実装もあります
  • 43. Peano-Hilbertはもう少し難しい ²  3次元だと作り方が一意ではないのに注意 ²  自分の周囲に被害者数名 「素晴らしい本で,少し でもこのテーマに興味あ るすべての人に全面的に お勧めである.」 •  これはみんなもってる?   •  2次元の場合の実装に関する   詳細な記述 •  読んだら3次元の実装ができる   とは限りません   •  それでも数学好きにはお勧め
  • 44. 先ずはGray code Incremental Gray  code 000! 000 001 001 010 011 011 010 100 110 101 111 110 101 111 100 zyx ^= zyx>>1; zyx ^= (zyx>>1) ^ (zyx>>2); •  一番上の階層はこれでいい   •  あとは部品の回転/反転
  • 45. namespace{! const uint64 xmask = 0111111111111111111111;! const uint64 ymask = 0222222222222222222222;! const uint64 zmask = 0444444444444444444444;! ! inline uint64 swap_xy(uint64 key){! return ((key&xmask)<<1 | (key&ymask)>>1 | (key&zmask));! }! inline uint64 swap_yz(uint64 key){! return ((key&xmask) | (key&ymask)<<1 | (key&zmask)>>1);! }! inline uint64 swap_zx(uint64 key){! return ((key&xmask)<<2 | (key&ymask) | (key&zmask)>>2);! }! inline uint64 key_shuffle(uint64 key, int idx){! switch(idx/2 + idx%2){! case 4: // idx = 7! key ^= (xmask | zmask); // fall-through! case 0: // idx = 0! key = swap_zx(key);! break;! case 3: // idx = 5,6! key ^= (ymask | zmask); // fall-through! case 1: // idx = 1,2! key = swap_yz(key);! break;! case 2: // idx = 3,4! key ^= (xmask | ymask);! break;! }! return key;! }! }! uint64 morton_to_ph(uint64 key){! uint64 ret = 0;! for(int ish=60; ish>=0; ish-=3){! unsigned idx = (key>>ish) & 7;! idx = (idx>>2) ^ (idx>>1) ^ (idx);
 // from Gray code! key = key_shuffle(key, idx);! ret = (ret<<3) | idx;! }! return ret;! }! uint64 ph_to_morton(uint64 key){! uint64 tmp = key;! tmp ^= (tmp&(zmask|ymask)) >> 1;
 // to Gray code! for(int jsh=3; jsh<=60; jsh+=3){! unsigned idx = (key>>jsh) & 7;! uint64 sfl = key_shuffle(tmp, idx);! uint64 mask = ((uint64)1<<jsh) - 1;! tmp &= ~mask;! tmp |= sfl&mask;! }! return tmp;! }! ご自由に最適化ください(終)