「Cell SPUのスカラ演算、整数演算、分岐」の編集履歴(バックアップ)一覧はこちら
追加された行は緑色になります。
削除された行は赤色になります。
比較対象がないと速いか遅いかを論じるのは意味なし。
なので結論は出さず。
最初に参考リンク
- [[SPEにおけるスカラ演算 (フィックスターズ)>http://cell.fixstars.com/ps3linux/index.php/4.5%E3%80%80SPE%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%82%B9%E3%82%AB%E3%83%A9%E6%BC%94%E7%AE%97]]
- [[何で私のスカラーコードはこんなに遅いの? (IBM developer Works)>http://www.ibm.com/developerworks/jp/power/library/pa-tacklecell3/index.html]]
- [[相乗演算処理装置の紹介 (IBM developer Works)>www.ibm.com/developerworks/jp/linux/library/pa-linuxps3-3/index.html]]
目次
#contents()
----
*SPUの整数演算は遅いか?
整数演算の性能は次の通り
- 128bit x1 論理演算
- 32bit x4 四則演算、論理演算
- 16bit x4 積和演算
- 16bit x8 四則演算、論理演算
- 8bit x16 特殊演算
が毎サイクル実行可能、レイテンシは2、または4サイクル。
ちなみに浮動少数演算の性能は次の通り
- float x4 積和演算 が毎サイクル実行可能、レイテンシが6サイクル
- double x2 積和 が7サイクルで実行可能、レイテンシが13サイクル
*SPUの分岐は遅いか?
パイプラインが26段と深いため、分岐予測が外れた場合のペナルティは17~18サイクルと大きい。
ハードウエアで動的分岐予測機構を持たないが、ソフトウェア的に分岐ヒント命令と条件選択命令を持つ。
分岐ヒントの予測が正しければ分岐のペナルティは0。
また2値のいずれかの選択だけの分岐であるなら、投機的に2値をどちらも計算した上で条件選択命令を使うことで
分岐自体をなくすことが可能。
*SPUのスカラ演算は遅いか?
SIMD演算器しかないのでスカラ演算でもそこで行う。
なので計算の速さはスカラでもベクタでも同じ。
ただしスカラの場合は、上記フィックスターズの記事にあるとおりLSからのロード、LSへのストアで
無駄が発生することが多い。
とは言っても128bitレジスタが128本あるので可能な限りオンレジスタで演算させるのがSPU流なので、
LSへのアクセスも必要最小限にとどまると思われる。
**ロード
#highlight(linenumber){
# アライメントがとれていないbyteをロードする
# $ra : アドレス
# $rb : 結果をいれる
# $raの下位4bitは無視されるため自動的に16バイトアラインでロードされる
lqd $rb, 0($ra)
# $raの下位4bitを使って$rtをバイト単位でローテートすることでMSBに移動させる
rotqby $rb, $rb, $ra
# プリファードスロットへさらにローテート
rotqbyi $rb, $rb, -3
}
byte、halfwordの場合だけ12.のローテートが必要。
アライメントがとれていれば6.の1命令だけでいい。
**ストア
#highlight(linenumber){
# byteをストアする
# $ra : アドレス
# $rb : バイトデータ
# $rc, rd, re : テンポラリ
# まずストア位置のデータをロードする
lqd $rc, 0($ra)
# バイト挿入マスクの生成
cbd $rd, 0($ra)
# シャッフル
# rbのプリファードスロットとrcのプリファードスロット以外とを合成する
shufb $re, $rb, $rc, $rd
# ストアする
stqd $re, 0($ra)
}
ストアはアライメントがとれてる/とれていないにかかわらず基本的に上記の手順が必要。
クアッドワードならもちろん1命令で可能。
*32bitの乗算がないってほんと?
まじで32bitの整数乗算をするインストラクションはない。
16bitの乗算命令(出力は32bit)を組み合わせて実現する。
一般的に5つのインストラクションが必要。
例
#highlight(linenumber){{
int32_t mul_s32x2_to_s32(int32_t a, int32_t b)
{
return a * b;
}
}}
次のようにコンパイルされる
#highlight(linenumber){
# $3 : a
# $4 : b
# aの上位ハーフワードとbの下位ハーフワードを乗算
mpyh $6,$3,$4
# bの上位ハーフワードとaの下位ハーフワードを乗算
mpyh $5,$4,$3
# aの下位ハーフワードとbの下位ハーフワードを符号無しで乗算
mpyu $3,$3,$4
# 以上をすべて足し合わせる
# 32bitに収まることが前提なので上位ハーフワード同士の乗算は行わない
a $2,$6,$5
a $3,$2,$3
# リターン
bi $0
}
*LSはL1並に速いか?
load/store のレイテンシは6サイクル
----
比較対象がないと速いか遅いかを論じるのは意味なし。
なので結論は出さず。
最初に参考リンク
- [[SPEにおけるスカラ演算 (フィックスターズ)>http://cell.fixstars.com/ps3linux/index.php/4.5%E3%80%80SPE%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%82%B9%E3%82%AB%E3%83%A9%E6%BC%94%E7%AE%97]]
- [[何で私のスカラーコードはこんなに遅いの? (IBM developer Works)>http://www.ibm.com/developerworks/jp/power/library/pa-tacklecell3/index.html]]
- [[相乗演算処理装置の紹介 (IBM developer Works)>http://www.ibm.com/developerworks/jp/linux/library/pa-linuxps3-3/]]
目次
#contents()
----
*SPUの整数演算は遅いか?
整数演算の性能は次の通り
- 128bit x1 論理演算
- 32bit x4 四則演算、論理演算
- 16bit x4 積和演算
- 16bit x8 四則演算、論理演算
- 8bit x16 特殊演算
が毎サイクル実行可能、レイテンシは2、または4サイクル。
ちなみに浮動少数演算の性能は次の通り
- float x4 積和演算 が毎サイクル実行可能、レイテンシが6サイクル
- double x2 積和 が7サイクルで実行可能、レイテンシが13サイクル
*SPUの分岐は遅いか?
パイプラインが26段と深いため、分岐予測が外れた場合のペナルティは17~18サイクルと大きい。
ハードウエアで動的分岐予測機構を持たないが、ソフトウェア的に分岐ヒント命令と条件選択命令を持つ。
分岐ヒントの予測が正しければ分岐のペナルティは0。
また2値のいずれかの選択だけの分岐であるなら、投機的に2値をどちらも計算した上で条件選択命令を使うことで
分岐自体をなくすことが可能。
*SPUのスカラ演算は遅いか?
SIMD演算器しかないのでスカラ演算でもそこで行う。
なので計算の速さはスカラでもベクタでも同じ。
ただしスカラの場合は、上記フィックスターズの記事にあるとおりLSからのロード、LSへのストアで
無駄が発生することが多い。
とは言っても128bitレジスタが128本あるので可能な限りオンレジスタで演算させるのがSPU流なので、
LSへのアクセスも必要最小限にとどまると思われる。
**ロード
#highlight(linenumber){
# アライメントがとれていないbyteをロードする
# $ra : アドレス
# $rb : 結果をいれる
# $raの下位4bitは無視されるため自動的に16バイトアラインでロードされる
lqd $rb, 0($ra)
# $raの下位4bitを使って$rtをバイト単位でローテートすることでMSBに移動させる
rotqby $rb, $rb, $ra
# プリファードスロットへさらにローテート
rotqbyi $rb, $rb, -3
}
byte、halfwordの場合だけ12.のローテートが必要。
アライメントがとれていれば6.の1命令だけでいい。
**ストア
#highlight(linenumber){
# byteをストアする
# $ra : アドレス
# $rb : バイトデータ
# $rc, rd, re : テンポラリ
# まずストア位置のデータをロードする
lqd $rc, 0($ra)
# バイト挿入マスクの生成
cbd $rd, 0($ra)
# シャッフル
# rbのプリファードスロットとrcのプリファードスロット以外とを合成する
shufb $re, $rb, $rc, $rd
# ストアする
stqd $re, 0($ra)
}
ストアはアライメントがとれてる/とれていないにかかわらず基本的に上記の手順が必要。
クアッドワードならもちろん1命令で可能。
*32bitの乗算がないってほんと?
まじで32bitの整数乗算をするインストラクションはない。
16bitの乗算命令(出力は32bit)を組み合わせて実現する。
一般的に5つのインストラクションが必要。
例
#highlight(linenumber){{
int32_t mul_s32x2_to_s32(int32_t a, int32_t b)
{
return a * b;
}
}}
次のようにコンパイルされる
#highlight(linenumber){
# $3 : a
# $4 : b
# aの上位ハーフワードとbの下位ハーフワードを乗算
mpyh $6,$3,$4
# bの上位ハーフワードとaの下位ハーフワードを乗算
mpyh $5,$4,$3
# aの下位ハーフワードとbの下位ハーフワードを符号無しで乗算
mpyu $3,$3,$4
# 以上をすべて足し合わせる
# 32bitに収まることが前提なので上位ハーフワード同士の乗算は行わない
a $2,$6,$5
a $3,$2,$3
# リターン
bi $0
}
*LSはL1並に速いか?
load/store のレイテンシは6サイクル
----