flushについては、必要な状況が2つあります。
1. カーネルを抜ける直前
2. カーネル内で、あるスレッドが変更した値をほかのスレッドに反映させる場合
以下のようなカーネルコードを考えたとき、
void pzc_add_mul(double* a, double* b, int num)
{
int pid = get_pid();
int tid = get_tid();
int gid = pid * get_maxtid() + tid;
if(gid == 0) {
for(int i = 0; i < num; ++i) {
a[i] *= 100;
}
}
flush();
for(int i = gid; i < num; i += 8192) {
a[i] = a[i] + b[i];
}
flush();
}
スレッド0で配列aの中身に100を乗じ、全スレッド配列aに配列bを加算するようなコードですが、最初のflushは2のケースで、他スレッドに反映させる(ならびにスレッド間の同期) を取っています。
加算が終わった後のflushは、1のケースによって必要なものです。
また、手持ちループを1回回す場合は不要、3回回す場合は必要となるようです。というのが、3回のカーネルキック、あるいは、以下のようなコードの場合
for(int j = 0; j < 3; ++j) {
for(int i = gid; i < num; i += 8192) {
a[i] = a[i] + b[i];
}
}
jのループに対して、flushが必要になります。これは2のケースで、キャッシュの整合性を取るために行われます。なので、正しくは以下のようになります。
for(int j = 0; j < 3; ++j) {
for(int i = gid; i < num; i += 8192) {
a[i] = a[i] + b[i];
}
flush(); // これが必要
}