pd-mark RWCP Omni OpenMP Compiler Implmentation Notes

概要・構成
Start off
ompcc実行時ライブラリ libompc.a インタフェース

ompccの概要・構成

Omni OpenMPコンパイラは、Omni Compiler Tool kitの以下の二つのプログラ ムによって構成されている。 変換されたプログラムは、実行時ライブラリ呼出を含むCプログラムに変換さ れ、バックエンドコンパイラによりコンパイル、実行時ライブラリとリンクさ れ、実行ファイルが生成される。

Start off


Omni OpenMP 実行時ライブラリ libompc.a インタフェース

_ompc_main
ユーザーのメインプログラムのエントリポイント。
_ompc_do_parallel(cfunc f, void *args)
_ompc_num_threads個(環境変数OMP_NUM_THREADSまたは、実行時ルーチン ompc_set_num_threads()で指定)のスレッドで、argsを引数にして、関数fを実 行する。fは、
 (*f)(args,実行するスレッドへのポインタ)
で呼び出される。現在、第二引数は使われていない。 必要なスレッドが作れない場合には、使えるスレッド分だけ のスレッドで実行される。例えば、nestされた場合、外側のループで全てのス レッドが使われた時、内側のスレッドは1つのスレッドで実行される。 このルーチンは、OpenMPのparallel regionを実行するために使われる。 コンパイラによって、parallel regionが一つの関数に変換され、共有するロー カル変数へのポインタをargsで引き渡される。 例を示す:
foo()
{
    int x,xx;
    x = 1;
#pragma omp parallel private(xx)
    {
	xx = x;
    }
}
は以下のように変換される:
void __ompc_func_0(__ompc_args)
void **__ompc_args;
{
   auto int _p_xx;
   auto int *_pp_x;
   (_pp_x)=(((int *)*((__ompc_args)+(0))));
   (_p_xx)=(*_pp_x);
}

int foo()
{
    auto int x;
    auto int xx;
   (x)=(1);
   { auto void *__ompc_argv[1];
      (*((__ompc_argv)+(0)))=(((void *)&x));
      _ompc_do_parallel(__ompc_func_0,__ompc_argv);
   }
}
_ompc_do_parallel_if(int cond,cfunc f, void *args)
上記の_ompc_do_parallelと同じだが、condが0の時には、マスタスレッ ドのみで、関数fを実行する。
_ompc_barrier()
team内のスレッドでバリア同期を行う。
_ompc_default_sched(int *lb, int *ub, int *step)
schedulingの方法が指定されていない場合のfor構文のスケジューリング を行う。ループ変数の下限値lb、上限値ub、刻幅stepを格納した変数を与え、 実行中のスレッドの担当範囲をえる。この後、各スレッドは
   _ompc_default_sched(&lb, &ub, &step);
    for(v = lb; v op ub; v += step) body
を実行する。現在libompc.aでは、_ompc_static_bschedと同じになっている。
_ompc_static_bsched(int *lb, int *ub, int *step)
schedule(static)の場合にループのイタレーションを等分割したスケジュー リングを行う。各スレッドは、
    _ompc_static_bsched(&lb, &ub, &step);
     for(v = lb; v op ub; v += step) body
を実行する。
_ompc_static_csched(int *lb, int *up, int *step)
schedule(static,1)の場合(chunk sizeが1)のスケジューリングを行う。 各スレッドは、
    _ompc_static_csched(&lb, &ub, &step);
    for(v = lb; v op ub; v += step) body
を実行する。
_ompc_static_sched_init(int lb, int ub, int step, int chunk_size)
schedule(static,chunk_size)の場合にstaticスケジューリングをするた めの初期化を行う。下限値lb、上限値ub、刻幅step, chunk_sizeを与える。 _ompc_static_sched_nextで、各スレッドの担当の範囲をえる。
_ompc_static_sched_next(int *lb, int *ub)
schedule(static,chunk_size)の場合に、各スレッドが実行するイタレー ションの範囲を得る。担当範囲の実行が終了した場合には、0を返す。 for構文は以下のように展開される。
    _ompc_static_sched_init(lb,ub,step,chunk_size);
    while(_ompc_static_sched_next(&lb,&ub))
        for(v = lb; v op up; v += step) body
_ompc_dynamic_sched_init(int lb, int up, int step, int chunk_size)
schedule(dynamic,chunk_size)の場合にdynamicスケジューリングをするた めの初期化を行う。下限値lb、上限値ub、刻幅step, chunk_sizeを与える。 _ompc_dynamic_sched_nextで、各スレッドの担当の範囲を得る。
_ompc_dynamic_sched_next(int *lb, int *ub)
schedule(dynamic,chunk_size)の場合に、各スレッドが実行するイタレー ションの範囲を得る。実行するべきイタレーションがない場合には、0を返す。 for構文は以下のように展開される。
    _ompc_dynamic_sched_init(lb,ub,step,chunk_size);
    while(_ompc_dynamic_sched_next(&lb,&ub))
        for(v = lb; v op ub; v += step) body
_ompc_guided_sched_init(int lb, int up, int step)
schedule(guided)の場合にguidedスケジューリングをするた めの初期化を行う。下限値lb、上限値ub、刻幅step, chunk_sizeを与える。 _ompc_guided_sched_nextで、各スレッドの担当の範囲を得る。
_ompc_guided_sched_next(int *lb, int *ub)
schedule(guided)の場合に、各スレッドが実行するイタレー ションの範囲を得る。実行するべきイタレーションがない場合には、0を返す。 for構文は以下のように展開される。
   _ompc_guided_sched_init(lb,ub,step);
   while(_ompc_guided_sched_next(&lb,&ub))
       for(v = lb; v op ub; v += step) body
_ompc_runtime_sched_init(int lb, int up, int step)
schedule(runtime)の場合にguidedスケジューリングをするた めの初期化を行う。下限値lb、上限値ub、刻幅step, chunk_sizeを与える。 ライブラリ内で、環境変数OMP_SCHEDULEの値を参照し、スケジューリング方法 を決定する。_ompc_runtime_sched_nextで、各スレッドの担当の範囲を得る。
_ompc_runtime_sched_next(int *lb, int *ub)
schedule(guided)の場合に、各スレッドが実行するイタレー ションの範囲を得る。実行するべきイタレーションがない場合には、0を返す。 for構文は以下のように展開される。
   _ompc_runtime_sched_init(lb,ub,step);
   while(_ompc_runtime_sched_next(&lb,&ub))
       for(v = lb; v op ub; v += step) body
_ompc_init_ordered(int lb,int step)
for構文に指定されたorderedを実行するための初期化を行う。 ループ変数の初期値、刻幅を与える。
_ompc_set_loop_id(int i)
実行するループのイタレーションのループ変数の値を登録する。 ordered構文を実行する_ompc_ordered_beginで参照される。 例えば、orderedが指定された場合には以下のようなコードとなる。
   _ompc_init_ordered(int lb,int step);
   _ompc_dynamic_sched_init(lb,ub,step,chunk_size);
   while(_ompc_dynamic_sched_next(&lb,&ub))
      for(v = lb; v op ub; v += step){
          _ompc_set_loop_id(v);
           body
      }
_ompc_ordered_begin(), _ompc_ordered_end()
ordered構文を実行するための同期を行う。_ompc_ordered_begin では、実行する順序が来るまで待つ。_ompc_ordered_end()は、そのイタレー ションの実行が終了したことを通知する。
_ompc_section_init(int n_sections)
sections構文を実行するための初期化を行う。 section数を与える。
_ompc_section_id()
実行中のスレッドが実行するべき、sectionの番号を返す。 sections構文は以下のように展開される。
   _ompc_section_init(n_section);
   switch(_ompc_section_id(){
    case 0:
         ...
    case 1:
         ...
   }
_ompc_is_last()
現在の実行中のスレッドが最後かを判定する。for構文、sections構文で lastprivateを実行するスレッドの場合に1を返す。それ以外は0。
_ompc_do_single()
single のblockを実行するべきかとうかを返す。既に実行されている場 合には、0を返す。
_ompc_is_master()
マスタかどうかを判定する。マスタスレッドに対しては1を返す。
_ompc_enter_critical(_ompc_lock_t *p), _ompc_exit_critical(_ompc_lock_t *p)
critical sectionの排他制御を行う。critial sectionの先頭では、 _ompc_enter_criticalを呼び、実行を終了した時点で、_ompc_exit_critical を呼び出す。現在のインプリメントでは、単にlock/unlockをしているのみ。 lock変数はコンパイラが生成する。
_ompc_flush(char *dst,int nbyte)
dstから始まるnbyteの領域をflushする。dstがNULLの場合には、全ての 共有変数に関してflushを行う。SMPでは、単にメモリバリア命令を呼び出すの み。
_ompc_get_thdprv(void ***thdprv_p,int size,void *datap)
threadprivateな変数を得る。thdprv_pは、各スレッドに対する threadprivateの変数へのテーブルへを指す変数のアドレスを与える。 sizeはthreadprivateの変数のサイズ。datapは元の大域変数へのポインタ。 この値はマスタスレッドのthreadprivateな変数となる。
_ompc_copyin_thdprv(void *datap,void *global_datap,int size)
、マスタスレッドの変数global_datapで、各スレッドのthreadprivateの 変数を初期化する。