# HG changeset patch # User Masataka Kohagura # Date 1455850169 -32400 # Node ID 8223a72a80e5ff0a6e53ebb2b1ff3193070b2a5f # Parent 04101fb51bd752fae5d394a045be583ba5de0979 fix diff -r 04101fb51bd7 -r 8223a72a80e5 paper/c4.tex --- a/paper/c4.tex Fri Feb 19 03:14:25 2016 +0900 +++ b/paper/c4.tex Fri Feb 19 11:49:29 2016 +0900 @@ -762,7 +762,7 @@ } CharClass, *CharClassPtr; \end{lstlisting} %ソースコードの説明 OK -ソースコード\ref{src:cc}は文字クラスの構造体である。正規表現木の各ノードそれぞれにこの構造体を持っている。 +ソースコード\ref{src:cc}は文字クラスの構造体である。正規表現木の文字ノード、文字クラスノードはそれぞれこの構造体を持っている。 文字クラスは二分木で構築されている。 文字クラスの範囲は Condition 内の RangeList の begin と end に設定される。 それぞれの二分木に文字の範囲である Condition を持っている。 diff -r 04101fb51bd7 -r 8223a72a80e5 paper/c6.tex --- a/paper/c6.tex Fri Feb 19 03:14:25 2016 +0900 +++ b/paper/c6.tex Fri Feb 19 11:49:29 2016 +0900 @@ -5,10 +5,7 @@ 本研究では文字列処理の並列処理の例題として、WordCount、Boyer-Moore String Search 、正規表現を実装した。 それぞれの例題によって結果の整合性を取る必要があるが、どのように整合性を取るかは問題によって考慮する必要がある。 -本研究で実装した正規表現は、正規表現から正規表現木を生成し、その正規表現木に状態を割り振りながらNFA や DFA を生成する。 -もし NFA が存在した場合は Subset Construction で DFA に変換する。 -DFA に変換後、その DFA を元に与えられたファイルに対してマッチングさせる。 -その結果、ファイル読み込みを含め egrep と比較して最大 66 \% 速度がでる。 +ファイル読み込みを含め egrep と比較して最大 66 \% 速度がでる。 \section{今後の課題} diff -r 04101fb51bd7 -r 8223a72a80e5 paper/images/regex/bitvector.bb --- a/paper/images/regex/bitvector.bb Fri Feb 19 03:14:25 2016 +0900 +++ b/paper/images/regex/bitvector.bb Fri Feb 19 11:49:29 2016 +0900 @@ -1,5 +1,5 @@ %%Title: images/regex/bitvector.pdf %%Creator: extractbb 20150315 %%BoundingBox: 0 0 672 552 -%%CreationDate: Thu Feb 18 19:38:59 2016 +%%CreationDate: Fri Feb 19 09:07:40 2016 diff -r 04101fb51bd7 -r 8223a72a80e5 slide/s6/index.html --- a/slide/s6/index.html Fri Feb 19 03:14:25 2016 +0900 +++ b/slide/s6/index.html Fri Feb 19 11:49:29 2016 +0900 @@ -132,7 +132,7 @@ ファイル読み込みの改良
  • - Cerium 上での文字列処理の並列処理の実装(Word Count、Boyer-Moore String Search、正規表現) + Cerium 上での文字列処理の並列処理の実装(Word Count、Boyer-Moore Search、正規表現)
  • を行なった。 @@ -149,10 +149,7 @@ Cerium は、本研究室で開発している並列プログラミングフレームワークで、C/C++ で実装されている。
  • - Cerium は当初 Sony Computer Entertainment 社の PlayStation3 に搭載されいた Cell 向けに開発されていた。現在では Linux、MacOSX 上で動作する。 -
  • -
  • - Cerium は当初 Sony Computer Entertainment 社の PlayStation3 に搭載されいた Cell 向けに開発されていた。現在では Linux、MacOSX 上で動作する。 + Cerium は当初 Sony Computer Entertainment 社の PlayStation3 に搭載されいた Cell 向けに開発されていた。現在では Linux、MacOSX、GPU 上で動作する。
  • 本研究では汎用計算フレームワークの TaskManager を利用して文字列処理の並列処理を実装した。 @@ -190,10 +187,20 @@
    @@ -220,6 +227,7 @@

    文字列処理の並列処理


    +
    • ファイルをある程度の大きさに分割する。
    • @@ -232,6 +240,48 @@
    • ファイルの分割部分で結果の整合性が取れない場合がある。その場合は例題によって様々な方法をとって整合を取る。
    • +
    +

    + ファイルを読み込んで文字列処理をする流れを 1 つのクラスとして Cerium 内に組み込んだ。 + このクラスは、ファイルをマッピングし処理をすることで小さいデータの集合を出力することから FileMapReduce と名付けた。 +

    +
    + +
    +

    FileMapReduce

    +
    +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->division_out_size = sizeof(unsigned long long)*4;
    +    task_init();
    +    fmp->run_start(manager, filename);
    +    return 0;
    +}
    +
    +
      +
    • TASK_EXEC : 計算を行う Task
    • +
    • TASK_EXEC_DATA_PARALLEL : GPU にて計算を行う Task
    • +
    • TASK_PRINT : 結果を集計する Task
    • +
    +

    + fmp->init で cpu の数の設定や読み込み方法(mmap or Blocked Read)のオプションを解釈する。 +

    +

    + fmp->division_out_size で計算を行う Task の出力されるデータ数を設定できる。 +

    +

    + run_start で計算を行う Task とファイル読み込みを行う Task が生成される。さらに依存関係が設定される。 +

    +

    +計算を行う Task と結果の整合や表示を行う Print Task をそれぞれ決められたフォーマットに沿って記述すればよい。 +

    @@ -257,87 +307,255 @@
    -

    Boyer-Moore String Search

    -
    -
    -
    +

    Boyer-Moore Search

    +

    + 文字列検索を高速に行うアルゴリズム +力任せ法との大きな違いは、text と pattern を先頭から比較するのではなく、 pattern の末尾から比較していくことである。 +

    • pattern に含まれていない文字で不一致した場合は、 pattern の長さだけ後ろにずらす。
    • pattern に含まれている文字の場合は、pattern の長さから pattern に含まれている文字の位置を引いた数だけ後ろにずらす。
    • pattern に含まれている文字でその文字が pattern に複数含まれている場合は後ろにずらす量も複数現れる。その中の最小の値だけ後ろにずらす。
    +
    +
    +
    -

    正規表現マッチャ(Cerium Grep)の実装

    -
    +

    正規表現マッチャの実装

      -
    • 与えられた正規表現を構文解析し、正規表現木に変換する。
    • -
    • 正規表現木から非決定性オートマトン(以下、NFA)か決定性オートマトン(以下、DFA)に変換する。
    • -
    • Subset Construction による NFA から DFA への変換をおこなう。
    • -
    • DFA を元に文字列検索を行ない結果を返す。
    • +
    • 与えられた正規表現を構文解析し、正規表現木に変換
    • +
    • 正規表現木への状態の割当
    • +
    • Subset Construction による状態の変換
    • +
    • 正規表現マッチャの並列処理の実装
    - -
    - - -
    -

    parser

    -
    -
    - -
    -

    連接

    -
    -
    +

    サポートする正規表現の演算子

    + + + + + + + + + + + + + + + + + + + + + + + +
    AB連続した文字(連接)
    A*直前の文字の 0 回以上の繰返し
    A|BA または B(選択)
    [A-Z]AからZの範囲内のうち任意の一文字(文字クラス)
    ( )演算の優先度の明示(グループ)
    -

    | の接続

    -
    +

    正規表現から正規表現木の生成

    +
    +
    +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;
    +}
    +
    +
      +
    • +正規表現木を二分木で生成する。 +
    • +
    • +文字列を token で一文字ずつ読み込み、文字によってノードの結合方法が変わる。 +
    • +
    • +regexAtom で文字を一文字読み込む。 +
    • +
    • +'*' が読み込まれたら左ノードに接続する。 +
    • +
    • +'|' が読み込まれたら左ノードに接続し、右ノードは再帰で返されたノードを接続する。 +
    • +
    • +それ以外(文字か文字クラス)が読み込まれたら左ノードに接続する。そして右ノードは regexAtom で返されたノードを接続する。 +
    • +
    +
    -

    * の組み合わせ

    -
    +

    正規表現木をオートマトンの状態遷移に沿って状態割当

    +
    + +
    +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;
    +    }
    +}
    +
    + +
      +
    • + tgv は +
    • +
    • +
    • +
    • +
    • +
    • +
    • +
    -

    | * の接続

    -
    -
    - -
    -

    正規表現の連接

    -
    +

    1入力で複数の状態遷移先があれば、その状態をまとめる

    +
    +
      +
    • +1 入力に対して遷移先が複数存在している場合は、文字によって場合分けをする必要がある。 +
    • +
    • +状態 4 は [a-z] が入力されると状態 4 に遷移し、b が入力されると状態 2 に遷移する。このとき、b が入力されると状態 2 か状態 4 のどちらかに遷移することになる。 +
    • +
    +
    +
      +
    • +1 入力に対して遷移先が複数存在している場合は、文字によって場合分けをする必要がある。 +
    • +
    • +このとき、状態 2 と 4 を組み合わせて一つの状態を新しく作り、その状態に遷移させる。新しく作られる状態の数は状態の組み合わせなので、その状態の組み合わせの和をとっている。 +
    • +
    • +このような変換をすることによって、入力によって遷移先が一意に決定されるようになる。 +
    • +
    -

    正規表現木をオートマトンの状態遷移に沿って状態割当

    -
    -
    - -
    -

    DFA

    -
    +

    Bit Pattern での状態の表現

    +
    +
      +
    • +状態の表現に BitVector を用いる。 +
    • +
    • +1つの Bit が正規表現に割り振られた Base 状態に対応する。 +
    • +
    • +組み合わされた状態は、複数の Bit が立っていることにより表される。 +
    • +
    • +状態の組み合わせは、BitVector の論理和によって簡単に計算される。 +
    • +
    -

    NFA

    -
    -
    - - -
    -

    1入力で複数の状態遷移先があれば、その状態をまとめる

    -
    -
    -
    - -
    -

    文字クラスの構造

    +

    文字クラスの構造体

     typedef struct utf8Range {
         unsigned long begin;
    @@ -346,6 +564,7 @@
     
     typedef struct condition {
         RangeList range;
    +    Word w;
     } Condition, *ConditionList;
     
     typedef struct charClass {
    @@ -356,33 +575,45 @@
         BitVector nextState;
     } CharClass, *CharClassPtr;
     
    +
      +
    • + 正規表現木の文字ノードもしくは文字クラスノードこの構造体を持っている。 +
    • +
    • + 文字クラスは二分木で構築されている。 +
    • +
    • + 文字クラスの範囲は Condition 内の RangeList の begin と end に設定される。 +
    • +
    • + その Condition の範囲内の文字の入力があれば、次の状態 nextState に遷移する。 +
    • +
    -

    cc tree merge pattern

    -
    -
    - - -

    Subset Construction


    -
    - - -
    -

    Bit Pattern での状態の表現

    +
      +
    • +組み合わされた状態からそれぞれの状態の場合分けをたどって、さらに別な組み合われた状態が生成される。 +
    • +
    • +新しい状態の組み合わせが出てこなくなるまでこれを繰り返す。 +
    • +
    + +
    +

    正規表現の整合性

    +
    +

    実験概要

    @@ -392,6 +623,9 @@
  • CPU:2*2.66GHz 6-Core Intel Xeon
  • HDD : 1TB 7200 rpm SATA 3.0 Gbps
  • +

    +mmapとbread はファイルの読み込み方式である。bread は Blocked Read を用いたときの結果である。 +

    @@ -407,8 +641,8 @@ CPU Num\実行方式 Mac(wc) - mmap - Blocked Read + Cerium wc (mmap) + Cerium wc (bread) 1 @@ -440,6 +674,11 @@ +

    +wc は 10.59秒で実行され、bread を用いた Cerium Word Count は CPU 12 のとき 7.82 秒となる。 +Cerium wc が最大 1.4 倍速くなった。 +

    +
    -

    実験2 : Boyer-Moore String Search

    +

    実験2 : Boyer-Moore Search

    -

    実験3:正規表現

    +

    実験3:正規表現(1/2)

    +
    +

    実験3:正規表現(2/2)

    + +

    結論

    今後の課題

    -
    - - -
    -

    状態をまとめる