flush()が必要な状況

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(); // これが必要
}

 

カテゴリー: Tips

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です