Cerium による並列処理向け I/O の設計と実装

Masataka Kohagura 12th, February

担当教官 : 河野 真治

研究背景と目的

近年のCPUのほとんどはマルチコアであり、それらの性能を引き出すためには並列プログラミングが必須となっている。 そこで当研究室では、並列プログラミング用フレームワーク、Cerium 及び Cerium Task Manager の開発を行い、提供することによって並列プログラミングを容易にしている。

先行研究では Task の並列化によって、プログラム全体の処理速度は向上している。しかし、ファイル読み込み等の I/O処理 と Task が並列に動作するようにはされていない。

本研究では I/O処理 と Task が並列に動作するような設計、実装によってプログラム全体の並列度、及び処理速度を上げていく。

Cerium Task Manager について

用語の定義

並列処理向け I/O の 設計と実装


I/O を含む Task の説明


  1. file を実メモリに格納後、file をある一定の大きさに分割する
  2. 分割した file に対して、それぞれ計算を行う
  3. 計算した結果を集計する

mmap の特徴

  • mmap は、C 及び C++ で使用できるAPIであり、ファイルを仮想メモリに mapping する。
  • code がシンプル
    (実メモリを自分自身で malloc せず、read を書いて読み込まなくていいため)
  • 実メモリより大きなファイルは開けない

mmapでの実装の問題点

Blocked Read の設計



Blocked Read の実装



I/O 専用の therad を追加 (1/2)


I/O 専用の therad を追加 (2/2)


ベンチマーク(1/2)


実験環境

ベンチマーク(2/2)


結果

read mode cpu num min time(s) MAX time(s) ave time(s)
mmap 4 135.2 148.9 142.3
BRead 4 94.5 109.2 98.8
mmap 12 147.0 181.8 154.6
BRead 12 91.6 117.5 99.2

まとめ


Blocked Read の有効性


研究計画


マルチコアソフトウェアシンセサイザーの設計


仮想メモリと実メモリ


Cerium Task の生成の例(1)

(例題) multiply : 2つの数を掛け算するプログラム

main.cc の記述

float* A, B, C;
// Task の宣言
HTaskPtr multiply = manager->create_task(MULTIPLY_TASK);
// Task を実行する デバイスの設定
multiply->set_cpu(SPE_ANY);
// Task に入力データのアドレスを追加
multiply->set_inData(0, (memaddr)A, sizeof(float)*length);
multiply->set_inData(1, (memaddr)B, sizeof(float)*length);
// Task に出力データのアドレスを追加
multiply->set_outData(0, (memaddr)C, sizeof(float)*length);
// Task へ値を1つだけ渡す
multiply->set_param(0,length);
// Task を TaskList に set する
multiply->spawn(); 

Cerium Task の生成(2)


Task の記述

static int
multiply(SchedTask *s,void *rbuf, void *wbuf)
{
    float *A,*B,*C
    // 登録した inData を取得
    A = (float*)s->get_input(rbuf,0);
    B = (float*)s->get_input(rbuf,1);
    // 登録した outData を取得
    C = (float*)s->get_output(wbuf,0);
    // 登録した param を取得
    long  length=(long)s->get_param(0);
    for (int i=0;i < length;i++) {
        C[i] = A[i] * B[i];
    }
    return 0;
} 

mmap での I/O の実装


mmap の記述

mmap(SchedTask *s, void *in, void *out)
{
    // FileReadPtr : File情報などを格納している構造体
    FileReadPtr fr = (FileReadPtr)in;
    int map = MAP_PRIVATE;

    fr->read_text =
        (char*)mmap(NULL,fr->filesize,PROT_READ,map,fr->fd,(off_t)0);
}

Block Read の実装(1/2)


Block Read の実装

HTaskPtr t_read = manager->create_task(READ_TASK);
t_read->set_cpu(read_spe_cpu);
// 読み出すファイルの格納場所を設定
t_read->set_outData(0,
                    w->file_mmap + w->task_spawned * w->division_size,
                    w->task_blocks * w->division_size);
// ファイルディスクリプタの受け渡し
t_read->set_param(0,w->fd);
// ファイル読み込みの始点
t_read->set_param(1,w->task_spawned*w->division_size);

// run_tasks(manager,w, w->task_blocks, t_read, t_next, w->division_size + w->extra_len);
// ここで、ファイルに対して何らかの計算を掛けるような Task を設定する
run_tasks(manager,w, w->task_blocks,・・・ );

// ファイル読み込みの終点
t_read->set_param(2,w->task_spawned*w->division_size + w->extra_len);

t_read->spawn();

Block Read の実装(2/2)


Block Read の記述

static int
read_task(SchedTask *s, void *rbuf, void *wbuf)
{
    long fd = (long)s->get_param(0);
    long start_read_position = (long)s->get_param(1);
    long end_read_position = (long)s->get_param(2);
    char *read_text = (char*)s->get_output(wbuf,0);
    long read_size = end_read_position - start_read_position;

    pread(fd, read_text, read_size , start_read_position);
    return 0;
}