Cerium による文字列処理の並列処理
|
Masataka Kohagura,Shinji Kono,
|
文字列処理の並列処理
世界中のサーバには様々な情報や Log が保管されており、それらのテキストファイル全体のデータサイズを合計すると TB 単位ととても大きなサイズになると予想される。
それらの中から特定の文字列や正規表現によるパターンマッチングを探すなどの文字列処理には膨大な時間がかかる。
検索時間を短縮するためには、ファイルの読み込み時間を軽減し、プログラムの並列度をあげる必要がある。
Cerium は並列プログラミングフレームワークであり当研究室で開発している。本研究では、
-
ファイル読み込みの改良
-
Cerium 上での文字列処理の並列処理の実装(Word Count、Boyer-Moore String Search、正規表現)
を行なった。
文字列処理だけでなくファイルの読み込みまでを含む文字列処理を考慮した並列処理を実装し、処理全体の速度を上げるような実装を行なった。
Cerium Task Manager
-
Cerium は、本研究室で開発している並列プログラミングフレームワークで、C/C++ で実装されている。
-
Cerium は当初 Sony Computer Entertainment 社の PlayStation3 に搭載されいた Cell 向けに開発されていた。現在では Linux、MacOSX 上で動作する。
-
Cerium は当初 Sony Computer Entertainment 社の PlayStation3 に搭載されいた Cell 向けに開発されていた。現在では Linux、MacOSX 上で動作する。
-
本研究では汎用計算フレームワークの TaskManager を利用して文字列処理の並列処理を実装した。
mmap の特徴
これまで Cerium での文字列処理の例題では File 読み込みを mmap にて行なっていた。
-
mmap は、仮想メモリ空間にファイルの中身を対応させ、そのメモリ空間に
アクセスされたら、 OS が読み込みを行う。
-
code の記述はシンプルだが、スレッドが読み込み終わるまで待たされる。
-
読み込みが OS 依存となるので、環境に左右されやすく、読み込みを細かく制御することが難しい。
読み込みながら文字列処理を行う Blocked Read
mmap を使用せずに、読み込みを独立したスレッドで実行させる。そして、読み込んだ部分に対して Task を並列に起動する。
- ファイルを一度に全て読み込むのではなく、ある程度の大きさに分けて読み込みを行う。
- 読み込みが終わったら文字列処理の Task を起動する。
-
ファイルが読み込まれていない領域に対して文字列処理が行われないように依存関係を設定する。
I/O 専用 threadの追加
Blocked Read は読み込みを含む処理なので、処理時間が大きくなる。
Cerium では読み込みや文字列処理の Task に対してデバイスを設定することができる。SPE_ANY 設定を利用すると Cerium 側が自動的に割り振りを行う。
自動的にデバイスを割り振ると、Blocked Read Task 間に Task が割り込まれる可能性があり、読み込みが遅延する恐れがある。
デバイスの設定に I/O専用 thread の IO_0 を追加して、他の Task に割り込まれないようにした。
文字列処理の並列処理
ファイルをある程度の大きさに分割する。
分割したファイルに対してそれぞれに文字列処理を行う。
結果の集計後、Print Task にて結果を表示する。
ファイルの分割部分で結果の整合性が取れない場合がある。その場合は例題によって様々な方法をとって整合を取る。
Word Count
Word Count は読み込んだファイルの単語数を数える。
改行が読み込まれたら行数のカウントを増やし、空白または改行が読み込まれたら単語数のカウントを増やす。
1つ目の分割されたファイルは空白または改行が 1 つしか無いため、単語数 1 となってしまっている。
ファイルの先頭の空白または改行の場合、単語数はカウントされない。
このように分割された場合、分割されたファイルの一つ目の末尾が文字で終わり、二つ目のファイルの先頭が改行または空白で始まった場合はそれぞれの単語数の合計数に1加えることにより整合性を取ることができる。
Boyer-Moore String Search
- pattern に含まれていない文字で不一致した場合は、 pattern の長さだけ後ろにずらす。
- pattern に含まれている文字の場合は、pattern の長さから pattern に含まれている文字の位置を引いた数だけ後ろにずらす。
- pattern に含まれている文字でその文字が pattern に複数含まれている場合は後ろにずらす量も複数現れる。その中の最小の値だけ後ろにずらす。
正規表現マッチャ(Cerium Grep)の実装
- 与えられた正規表現を構文解析し、正規表現木に変換する。
- 正規表現木から非決定性オートマトン(以下、NFA)か決定性オートマトン(以下、DFA)に変換する。
- Subset Construction による NFA から DFA への変換をおこなう。
- DFA を元に文字列検索を行ない結果を返す。
parser
連接
| の接続
* の組み合わせ
| * の接続
正規表現の連接
正規表現木をオートマトンの状態遷移に沿って状態割当
DFA
NFA
1入力で複数の状態遷移先があれば、その状態をまとめる
文字クラスの構造
typedef struct utf8Range {
unsigned long begin;
unsigned long end;
} RangeList , *RangeListPtr;
typedef struct condition {
RangeList range;
} Condition, *ConditionList;
typedef struct charClass {
struct charClass *left;
struct charClass *right;
Condition cond;
int stateNum;
BitVector nextState;
} CharClass, *CharClassPtr;
cc tree merge pattern
Subset Construction
Bit Pattern での状態の表現
State Array
正規表現の整合性
実験概要
実験環境
- OS:MacOS 10.10.5
- CPU:2*2.66GHz 6-Core Intel Xeon
- HDD : 1TB 7200 rpm SATA 3.0 Gbps
実験1:Word Count
- FileSize : 500MB
- 単語数 : 約8500万
- ファイル読み込みを含む時間
CPU Num\実行方式 |
|
Mac(wc) |
mmap |
Blocked Read |
1 |
|
10.59 |
9.96 |
9.33 |
4 |
|
--- |
8.63 |
8.52 |
8 |
|
--- |
10.35 |
8.04 |
12 |
|
--- |
9.26 |
7.82 |
- FileSize : 500MB
- 単語数 : 約8500万
- ファイル読み込みを含まない時間
実行方式 |
|
実行速度(s) |
Mac(wc) |
|
4.08 |
Cerium Word Count(CPU 1) |
|
3.70 |
Cerium Word Count(CPU 4) |
|
1.00 |
Cerium Word Count(CPU 8) |
|
0.52 |
Cerium Word Count(CPU 12) |
|
0.40 |
実験2 : Boyer-Moore String Search
- FileSize : 500MB
- 単語数 : 約8500万
- 検索文字列 : Pakistan
- マッチ数 : 約400万
- ファイル読み込みを含まない
CPU Num\実行方式 |
|
力任せ法 |
Boyer-Moore String Search |
1 |
|
3.17 |
1.70 |
4 |
|
0.87 |
0.49 |
8 |
|
0.47 |
0.27 |
12 |
|
0.33 |
0.21 |
実験3:正規表現
- FileSize : 500MB
- 単語数 : 約8500万
- 正規表現 : ‘[A-Z][A-Za-z0-9]*s’
- マッチ数 : 約536万
- ファイル読み込みの有無
実行方式 |
|
ファイル読み込み有 |
ファイル読み込み無 |
single thread grep |
|
21.17 |
16.15 |
CeriumGrep(CPU 12) mmap |
|
18.00 |
5.12 |
CeriumGrep(CPU 12) bread |
|
15.76 |
5.18 |
egrep |
|
59.51 |
59.51 |
- ファイルサイズ : 500MB(約8500万単語)
- 正規表現 : ‘[A-Z][A-Za-z0-9]*s’
- ファイルサイズを変更してみる
実行方式\ FileSize(Match Num) |
|
50MB(54万) |
100MB(107万) |
500MB(536万) |
1GB(1072万) |
single thread grep |
|
4.51 |
9.42 |
20.62 |
40.10 |
CeriumGrep(CPU 12) mmap |
|
8.97 |
10.79 |
18.00 |
29.16 |
CeriumGrep(CPU 12) bread |
|
7.75 |
10.49 |
15.76 |
26.83 |
egrep |
|
6.42 |
12.80 |
59.51 |
119.23 |
- ファイルサイズ : 500MB(約2400万単語)
- ファイル読み込みを含む
- 正規表現の状態数を増やしてみる
正規表現 |
|
状態数 |
subset後の状態数 |
マッチ数 |
CeriumGrep(CPU12) bread |
egrep |
’(a|b)*a(a|b)(a|b)z’ |
|
5 |
12 |
約10万 |
26.58 |
70.11 |
’(a|b)*a(a|b)(a|b)(a|b)z’ |
|
6 |
21 |
約8万 |
27.89 |
76.78 |
’(a|b)*a(a|b)(a|b)(a|b)(a|b)z’ |
|
7 |
38 |
約4万 |
28.86 |
81.88 |
’(a|b)*a(a|b)(a|b)(a|b)(a|b)(a|b)z’ |
|
8 |
71 |
約2万 |
29.15 |
86.93 |
- ファイルサイズ : 500MB(約2400万単語)
- 正規表現 : (W|w)ork
- ab が並んでいるファイルに対して全くマッチングしない正規表現を与える
- ファイル読み込みを含む
実行方式 |
|
time(s) |
single thread grep |
|
27.13 |
CeriumGrep(CPU12) mmap |
|
21.58 |
CeriumGrep(CPU12) bread |
|
19.99 |
egrep |
|
28.33 |
結論
- I/O と Task を分離し、同時に動くように改良し、どの環境でも安定した速度が出た。
- I/O 専用の Thread の追加
-
mmap でも一度に読み込む大きさを小さくすれば、Blocked Read とほぼ同じ速度が出る。
今後の課題
- Cerium の API として実装
-
様々な実装の試み
(I/O threads を 2つ使用したプログラム、分割 mmap)
-
様々な環境での測定
-
grepの実装
状態をまとめる