Mercurial > hg > Papers > 2016 > masa-master
diff slide/s6/index.html @ 108:199561d48b97
add poster
author | Masataka Kohagura <kohagura@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sat, 20 Feb 2016 18:32:23 +0900 |
parents | efdc04a5746c |
children |
line wrap: on
line diff
--- a/slide/s6/index.html Fri Feb 19 14:30:11 2016 +0900 +++ b/slide/s6/index.html Sat Feb 20 18:32:23 2016 +0900 @@ -161,7 +161,8 @@ <div class='slide'> <h2>mmap の特徴</h2> これまで Cerium での文字列処理の例題では File 読み込みを mmap にて行なっていた。 - <object data="images/cerium/mmap.svg" width="50%" type="image/svg+xml"></object><br> + <br> + <object data="images/cerium/mmap.svg" width="40%" type="image/svg+xml"></object><br> <br> <ul> @@ -245,76 +246,23 @@ ファイルを読み込んで文字列処理をする流れを 1 つのクラスとして Cerium 内に組み込んだ。 このクラスは、ファイルをマッピングし処理をすることで小さいデータの集合を出力することから FileMapReduce と名付けた。 </p> + <p>FileMapReduce を利用するメリット</p> + <ul> + <li> + cpu の数の設定や読み込み方法(mmap or Blocked Read)のオプションを解釈する。 + </li> + <li> + 計算を行う Task とファイル読み込みを行う Task が生成される。さらに依存関係が設定される。 + </li> + <li> +計算を行う Task と結果の整合や表示を行う Print Task をそれぞれ決められたフォーマットに沿って記述すればよい。 + </li> + <p></p> </div> - <div class='slide'> - <h2>FileMapReduce</h2> -<pre> -TMmain(TaskManager *manager, int argc, char *argv[]) -{ - char *filename = 0; - FileMapReduce *fmp = - new FileMapReduce(manager,TASK_EXEC,TASK_EXEC_DATA_PARALLEL,TASK_PRINT); - filename = fmp->init(argc, argv); - - - if (filename < 0) { - return -1; - } - - fmp->w->global = (void*)DATA; - fmp->division_out_size = sizeof(unsigned long long)*DATA_NUM; - - task_init(); - fmp->run_start(manager, filename); - return 0; -} -</pre> - <ul> -<li> TASK_EXEC : 計算を行う Task</li> -<li> TASK_EXEC_DATA_PARALLEL : GPU にて計算を行う Task</li> -<li> TASK_PRINT : 結果を集計する Task</li> - </ul> - <p> - fmp->init で cpu の数の設定や読み込み方法(mmap or Blocked Read)のオプションを解釈する。 - </p> - <p> - fmp->division_out_size で計算を行う Task の出力されるデータ数を設定できる。 - </p> - <p> - run_start で計算を行う Task とファイル読み込みを行う Task が生成される。さらに依存関係が設定される。 - </p> - <p> - Task にデータを渡したい場合、fmp->w->global にセットすればよい。 - </p> - <p> -計算を行う Task と結果の整合や表示を行う Print Task をそれぞれ決められたフォーマットに沿って記述すればよい。 - </p> - </div> - +<!-- <div class='slide'> <h2>FileMapReduce を利用した Task の記述 </h2> -<pre> -SchedDefineTask1(Exec,task_exec); - -static int -task_exec(SchedTask *s, void *rbuf, void *wbuf) -{ - //get_input - unsigned char *i_data = (unsigned char *)s->get_input(0); - int length = (int)s->get_inputSize(0); - MapReduce *w = (MapReduce*)s->get_param(4); - - (STRUCTPtr) DATA = (STRUCTPtr)w->global; - - // Word Count, Boyer-Moore Search, grep - - o_data[0] = SET_RESULT0; - o_data[1] = SET_RESULT1; - - return 0; -} -</pre> <p> Task の生成で渡された DATA を w->global で受け取ることができる。 </p> @@ -325,21 +273,6 @@ <div class='slide'> <h2>Print の記述 </h2> -<pre> -SchedDefineTask1(Print,run_print); - -static int -run_print(SchedTask *s, void *rbuf, void *wbuf) -{ - MapReduce *w = (MapReduce*)s->get_input(0); - int out_size = w->division_out_size / sizeof(unsigned long long); - int out_task_num = w->task_num; - - // printf(w->o_data[i*out_size+0]); - - return 0; -} -</pre> <p> Task の o_data で渡されたデータを Print Task で集計する。 </p> @@ -347,10 +280,11 @@ 例題によって分割された部分の処理が必要である。その処理もここに記述する。 </p> </div> +--> <div class='slide'> - <h2>Word Count</h2> + <h2>文字列処理の例題 : Word Count</h2> <object data="images/example/wordcount.svg" width="70%" type="image/svg+xml"></object><br> <li> Word Count は読み込んだファイルの単語数を数える。 @@ -372,7 +306,7 @@ </div> <div class='slide'> - <h2>Boyer-Moore Search</h2> + <h2>文字列処理の例題 : Boyer-Moore Search</h2> <p> 文字列検索を高速に行うアルゴリズム 力任せ法との大きな違いは、text と pattern を先頭から比較するのではなく、 pattern の末尾から比較していくことである。 @@ -428,61 +362,9 @@ <h2>正規表現から正規表現木の生成</h2> <p>正規表現木を二分木で構成する。</p> <object data="images/regex/parser.svg" width="50%" type="image/svg+xml"></object><br> -<pre> -static -NodePtr regexAtom(RegexInfoPtr ri) { - - NodePtr n = NULL; - if (ri->tokenType == 'c') n = charClass(ri); - else if (ri->tokenType == 'a') n = literal(ri); - else if (ri->tokenType == '(') { - n = regex(ri); - if (ri->tokenType != ')') { - // error - fprintf(stderr,"unclosed ')' before %s \n", ri->ptr); - return createNode(ri,0,0,0,0); - } - token(ri); - } - if (ri->tokenType == '*') { - n = createNode(ri,'*',0,n,0); - token(ri); - } - return n; -} - -NodePtr regex(RegexInfoPtr ri) { - token(ri); - NodePtr n = regexAtom(ri); - while (ri->tokenType) { - if (ri->tokenType == '*') { - n = createNode(ri,'*',0,n,0); - token(ri); - return n; - } else if (ri->tokenType == '|') { - n = createNode(ri,'|',0,n,0); - NodePtr n1 = regex(ri); - n->right = n1; - } else if (ri->tokenType == ')') { - return n; - } else if (ri->tokenType == ']') { - // error - return n; - } else { - n = createNode(ri,'+',0,n,0); - NodePtr n1 = regexAtom(ri); - n->right = n1; - } - } - return n; -} -</pre> <ul> <li> -文字列を token で一文字ずつ読み込み、文字の種類によってノードの結合方法を変える。 -</li> -<li> -regexAtom で文字を一文字読み込む。 +文字列を一文字ずつ読み込み、文字の種類によってノードの結合方法を変える。 </li> <li> '*' が読み込まれたら左ノードに接続する。 @@ -491,7 +373,7 @@ '|' が読み込まれたら左ノードに接続し、右ノードは再帰で返されたノードを接続する。 </li> <li> -それ以外(文字か文字クラス)が読み込まれたら左ノードに接続する。そして右ノードは regexAtom で返されたノードを接続する。 +それ以外(文字か文字クラス)が読み込まれたら左ノードに接続する。そして右ノードはその後に続く文字を接続する。 </li> </ul> @@ -520,7 +402,7 @@ </pre> <ul> <li> - 正規表現木の文字ノードもしくは文字クラスノードこの構造体を持っている。 + 正規表現木の文字ノード、文字クラスノードそれぞれが charClass 構造体を持っている。 </li> <li> 文字クラスは二分木で構築されている。 @@ -538,86 +420,15 @@ <h2>正規表現木をオートマトンの状態遷移に沿って状態割当</h2> <object data="images/regex/allostate.svg" width="50%" type="image/svg+xml"></object><br> -<pre> -TGValue generateTransition(NodePtr n,TGValue tgv, int pass) { - if (n->tokenType == '+') { - TGValue tgvLeft = tgv; - tgvLeft.endState = n->right->state; - tgvLeft.asterisk = NULL; - tgvLeft = generateTransition(n->left,tgvLeft,pass); - TGValue tgvRight = tgv; - if (tgvLeft.asterisk) { - n->right->state = tgv.endState; - tgvRight.startState = tgvLeft.asterisk; - tgvRight = generateTransition(n->right,tgvRight,pass); - tgvLeft.asterisk = tgvRight.asterisk; - return tgvLeft; - } - tgvRight.asterisk = NULL; - if (pass==1) { - n->right->state = tgvRight.startState = createState(tgvRight,n->right); - } else { - tgvRight.startState = n->right->state; - tgvRight.tg->stateArray[tgvRight.startState->bitState.bitContainer] = tgvRight.startState ; - } - tgvRight = generateTransition(n->right,tgvRight,pass); - if (tgv.endState && tgvRight.asterisk) tgvRight.startState->accept = tgv.endState->accept; - tgvLeft.asterisk = tgvRight.asterisk; - return tgvLeft; - } else if (n->tokenType == '|') { - TGValue tgv1 = generateTransition(n->left,tgv,pass); - tgv1.endState = tgv.endState; - TGValue tgv2 = generateTransition(n->right,tgv1,pass); - return tgv2; - } else if (n->tokenType == '*') { - TGValue tgvAstah = tgv; - tgvAstah.endState = tgvAstah.startState; - if (pass==2) tgvAstah.endState->accept = tgv.endState->accept; - tgvAstah = generateTransition(n->left,tgvAstah,pass); - tgvAstah.asterisk = tgvAstah.startState; - return tgvAstah; - } else if (n->tokenType == 'c' || n->tokenType == 'a'){ - TGValue tgv1 = tgv; - if (pass==1) { - n->stateNum = tgv.startState->stateNum; - n->state = tgv.startState; - } else { - int nextState = tgv.endState->stateNum; - n->nextStateNum = nextState; - n->nextState = tgv.endState; - BitVector bi = createBitVector(nextState); - if (n->nextState->accept) bi = bitSet(bi,1); - setState(n->cc,bi); - tgv1.startState->cc = mergeTransition(tgv1.startState,n->cc); - } - return tgv1; - } else { - return tgv; - } -} -</pre> - <ul> <li> - TGValue は asterisk、startState、endState それぞれの状態を持っている。 - </li> - <li> - 正規表現木を二度 generateTransition に通す。 - </li> - <li> - それらの状態を正規表現木に対して Tree walk しながら状態を割り振っていく。 + '+'ノードの左に'*'無かった場合は、右のノードに新しく状態を作る。 </li> <li> - '+' のとき、 + '|' のとき、左右のノードの先頭の状態に同じ状態を割り振る。 </li> <li> - '|' のとき、 - </li> - <li> - '*' のとき、 - </li> - <li> - 文字または文字クラスのとき、 + '*' のとき、先頭の状態と'*'を子にしている親ノードの後ろのノードと同じ状態にする。 </li> </ul> </div> @@ -639,7 +450,7 @@ 1 入力に対して遷移先が複数存在している場合は、文字によって場合分けをする必要がある。 </li> <li> -このとき、状態 2 と 4 を組み合わせて一つの状態を新しく作り、その状態に遷移させる。新しく作られる状態の数は状態の組み合わせなので、その状態の組み合わせの和をとっている。 +このとき、状態 2 と 4 を組み合わせて一つの状態を新しく作り、その状態に遷移させる。新しく作られる状態の数は状態の組み合わせなので、その状態の組み合わせをとる。 </li> <li> このような変換をすることによって、入力によって遷移先が一意に決定されるようになる。 @@ -685,36 +496,6 @@ <div class='slide'> <h2>並列処理時の正規表現のマッチング</h2> <pre> -static -TSValue stateNothing(TSValue tsv) { - return tsv; -} - -static -TSValue stateSkip(TSValue tsv) { - tsv.current = tsv.tg->stateStart->tState; - if (tsv.matchEnd) { - addResult(tsv,false,tsv.matchBegin,tsv.matchEnd); - tsv.matchEnd = NULL; - } - tsv.matchBegin = tsv.buff.buffptr; // next char may be matchBegin - return tsv; -} - -static -TSValue stateMatch(TSValue tsv) { - tsv.matchEnd = tsv.buff.buffptr; // next char of the match - return tsv; -} - -typedef struct ccv { - unsigned long begin; - unsigned long end; - Word w; - BitVector state; - struct tState *tState; -} CCV,*CCVPtr; - typedef struct tState { State *state; tsValue (*stateSkip)(tsValue); @@ -729,72 +510,23 @@ tState は状態を持ってる。 </li> <li> -文字クラスの Range の情報と遷移先は ccv に格納している。 +文字クラスの Range の情報と状態の遷移先は ccv に格納している。 </li> <li> ある状態が Range にマッチする文字が入力された場合は次の状態に遷移する。 </li> <li> ある状態が受理状態で Range にマッチしない文字が入力されたら、tState->stateSkip には stateSkip、tState->stateMatch には stateMatch を設定する。<br> -受理状態でない場合は、tState->stateMatch に stateNothing を設定する。 +受理状態でない場合は、tState->stateMatch には stateNothing を設定する。 </li> <li> tState は新しい状態に遷移するときに初めて生成される。<br> thread ごとに on the fly で生成されるので、使わない状態は生成されない。 </li> -<li> -文字列処理する前に初期状態からの遷移先だけは生成しておき、それを並列処理の Task に渡す。 -</li> </ul> </div> - <div class='slide'> - <h2>並列処理時の正規表現のマッチング</h2> -<pre> -TSValue tSearch(TSValue tsv) { - next: while (tsv.buff.buffptr < tsv.buff.buffend) { - tsv = tsv.current->stateMatch(tsv); - if (tsv.current->ccvSize==0) { - tsv.current = tsv.tg->stateStart->tState; - } - unsigned char c = *tsv.buff.buffptr++; - for (int i = 0; i < tsv.current->ccvSize; i++) { - CCVPtr ccv = &tsv.current->ccv[i]; - if (c<ccv->begin) { - tsv.current = tsv.tg->stateStart->tState; - tsv = tsv.current->stateSkip(tsv); - goto next; - } else if (c<=ccv->end) { - // range matched. - if (ccv->w.word) { - // match the word. - // if (not match) continue; - } - if (ccv->tState) { - tsv.current = ccv->tState; - } else { - tsv.current = nextTState(ccv->state,tsv.tg); - ccv->tState = tsv.current; - } - goto next; - } - } - tsv.current = tsv.tg->stateStart->tState; - tsv = tsv.current->stateSkip(tsv); - } - return tsv; -} -</pre> - <ul> - <li> - </li> - <li> - </li> - </ul> - </div> - - <div class='slide'> <h2>マッチング結果の Print</h2> <pre> @@ -823,14 +555,12 @@ <div class='slide'> <h2>ファイル分割時の処理</h2> -正規表現をファイル分割して並列処理をする際、本来マッチングする文章がファイル分割によってマッチングしない場合がある。 -<object data="images/regex/regexdivide.svg" width="50%" type="image/svg+xml"></object><br> <p> -並列処理時、分割されたファイルに対してパターンマッチさせるので、分割された1つ目のファイルの末尾の abb 、2つ目のファイルの先頭に bbc はマッチングしない。 -本来分割される前はマッチングする文字列だが、この場合見逃してしまう。 -それを解決するために、正規表現にマッチングし始めたファイルの場所を覚えておく。 - -そして、1つ目のファイルの末尾が状態遷移の途中で終わっていた場合(状態 1 でない場合)は、結果を集計する際に再度マッチングし始めた場所から正規表現をマッチングさせる。 +正規表現をファイル分割して並列処理をする際、本来マッチングする文章がファイル分割によってマッチングしない場合がある。 +</p> +<object data="images/regex/regexdivide.svg" width="60%" type="image/svg+xml"></object><br> +<p> +再度マッチするかどうかは Print Task で行われる。 <p> </div> @@ -1038,8 +768,7 @@ </tbody> </table> <p> -single thread grep や CeriumGrep は繰返し実行をすると実行速度が短くなる。 これは、読み込んだファイルがキャッシュに残っており、ファイル読み込みが省略されるためである。 -しかし egrep は繰返し実行しても毎回ファイルを読み込みにいく。 +egrep は繰返し実行しても、ファイルがキャッシュに入らない。毎回ファイルを読み込みにいく。 CeriumGrep(CPU 12)bread で検索すると、egrep で検索するよりも 4 倍ほど速くなる。 </p> @@ -1204,19 +933,63 @@ <div class='slide'> <h2>結論</h2> <ul> - <li>並列処理時のファイルの読み込みについて改良を行なった結果、最大13\%速くなる。</li> + <li>並列処理時のファイルの読み込みについて改良を行なった結果、最大13%速くなる。</li> <li>ファイル読み込みを含め egrep と比較して最大 66 %速度がでる。</li> </ul> <h2>今後の課題</h2> <ul> <li>文字単位に状態を割り振るのではなく、文字列単位に状態を割り振ることで状態数を抑える</li> <li>現段階の実装では、最大の状態数は 64 に制限されている</li> - <li>状態数を抑えることで、より長い正規表現を検索できるようになる。</li> + <li>状態数を抑えることで、より長い正規表現を検索できるようになる</li> + <li>このときの検索を Boyer-Moore Search で行うことでさらに高速化できることが期待される</li> </ul> - <object data="images/regex/wordstate.svg" type="image/svg+xml" width="50%"></object><br> + <object data="images/regex/wordstate.svg" type="image/svg+xml" width="30%"></object><br> </div> - + <div class='slide'> + <h2>Search 部分のソースコード</h2> +<pre> +TSValue tSearch(TSValue tsv) { + next: while (tsv.buff.buffptr < tsv.buff.buffend) { + tsv = tsv.current->stateMatch(tsv); + if (tsv.current->ccvSize==0) { + tsv.current = tsv.tg->stateStart->tState; + } + unsigned char c = *tsv.buff.buffptr++; + for (int i = 0; i < tsv.current->ccvSize; i++) { + CCVPtr ccv = &tsv.current->ccv[i]; + if (c<ccv->begin) { + tsv.current = tsv.tg->stateStart->tState; + tsv = tsv.current->stateSkip(tsv); + goto next; + } else if (c<=ccv->end) { + // range matched. + if (ccv->w.word) { + // match the word. + // if (not match) continue; + } + if (ccv->tState) { + tsv.current = ccv->tState; + } else { + tsv.current = nextTState(ccv->state,tsv.tg); + ccv->tState = tsv.current; + } + goto next; + } + } + tsv.current = tsv.tg->stateStart->tState; + tsv = tsv.current->stateSkip(tsv); + } + return tsv; +} +</pre> + <ul> + <li> + </li> + <li> + </li> + </ul> + </div> </div> <!-- presentation --> </body>