HPC/並列プログラミングポータルでは、HPC(High Performance Computing)プログラミングや並列プログラミングに関する情報を集積・発信しています。 |
[記事一覧を見る]
インテルが開発している「インテル コンパイラー」は、インテルCPUに最適化された高速なバイナリを生成するということで知られており、Oracleなどパフォーマンスを求めるベンダーで採用されているほか、科学計算用アプリケーション、3Dグラフィックソフトなど、さまざまなソフトウェアのコンパイルに利用されている。
しかし、「インテル コンパイラーはパフォーマンスが高い」とだけ言われても、なかなかピンと来ない人も多いのではないだろうか。そこで、インテル コンパイラーでコンパイルされたバイナリをベンチマークテストし、実際どの程度の性能向上が見込まれるのかを調べてみよう。
インテル コンパイラーはCPUメーカーであるインテルが開発しているということで、Core i7などの最新CPUに搭載されているSSE 4.2といった命令セットへの対応が図られているほか、インテルおよびインテル互換CPUに向けた最適化機能や自動並列化機能、プロシージャ間の最適化(Interprocedural optimization、IPO)と呼ばれる全体最適化機能など、よりパフォーマンスの高いバイナリを生成するための機能を備えている。そのため、特に浮動小数点演算を多用する科学技術系シミュレーションや画像処理、動画/音声処理、CGといったアプリケーションとの相性が良いと言われており、実際の採用例も多い。
たとえば、日本国内でインテル コンパイラーの販売・サポートを行っているエクセルソフトのWebサイトに掲載されている「インテル製品の導入事例」では、工学系や金融系のシミュレーションアプリケーションでインテル コンパイラーを使用したところ、1.5倍~2倍以上の速度向上が見られる、という例が複数報告されている。
また、シミュレーションだけでなく音声処理でもパフォーマンス向上が報告されており、ソニーデジタルネットワークアプリケーションズ株式会社の採用例では、インテル コンパイラーの採用や並列化、パフォーマンス解析などによって最終的に3倍程度の高速化に成功している。
さらに、大手データベースベンダーであるOracleは同社製品のコンパイルにインテル コンパイラーを採用している。インテル コンパイラーの採用により、特にXeonやItanium 2などの64ビット環境で大きなパフォーマンス向上が達成できたそうだ。
このように、特に科学技術系やシミュレーションの分野で評価の高いインテル コンパイラーであるが、いっぽうで身近なオープンソースソフトウェアでも、インテル コンパイラーを利用することでパフォーマンスが向上する、というレポートが挙げられている。そのなかでも興味深いのが、MySQLの事例だ。Linux World 2005で発表された「Improving MySQL Server Performance with Intel C++ Compiler」というレポートでは、「Set Query Benchmark」というベンチマークにおいて、インテル コンパイラーを利用することでMySQLのパフォーマンスをPentium 4マシンで最大1.35倍、Itanium 2マシンで最大1.24倍、Xeon(64ビット環境)では最大2.55倍向上できた、と報告されている。
MySQLはオープンソースのリレーショナルデータベースシステムで、もともとはスウェーデンのMySQL社によって開発されていたが、現在ではサン・マイクロシステムズがその権利を所有している。MySQLにはオープンソース版の「MySQL Community Server」と、商用製品である「MySQL Enterprise」の2製品があるが、MySQL Community ServerのLinux版についてはGCCでコンパイルされたバイナリに加え、インテル コンパイラーでコンパイルされたバイナリも配布されている(ダウンロードページ)。そこでこれらのバイナリを使い、本当にこのようなパフォーマンス向上が見られるのか、比較してみよう。
データベースのベンチマーク手法には大規模なものから簡易的なものまで様々なものがあるが、今回はMySQLに付属している「sql-bench」というベンチマークツールを利用した。sql-benchはPerlで記述されたベンチマークツールで、9つのベンチマーク項目が用意されており(表1)、データベースに対してさまざまなSQLコマンドを発行してその実行時間を測定するものだ。SQLコマンドの発行はシングルスレッドで行われるので、データベースがどの程度の負荷に耐えられるかを測定する、というよりも、データベース自体の処理速度を計測する目的で利用されることが多いベンチマークである。また、SQLコマンドの種類ごとに処理にかかった時間を測定できるため、どのような処理が得意でどのような処理が苦手なのか、という傾向をつかむこともできる。
ベンチマーク項目 | 説明 |
---|---|
alter-table | テーブルに対して多数のフィールド追加/削除を行うテスト |
ATIS | 複数のテーブルに対して多数のselect文を発行するテスト |
big-tables | 巨大なテーブルに対してアクセスを行うテスト |
connect | サーバーへの接続速度を評価するテスト |
create | テーブル作成の速度を評価するテスト |
insert | テーブルへのデータのinsert速度を評価するテスト |
select | select文のパフォーマンスを評価するテスト |
transactions | トランザクションの速度を計測するテスト |
wisconsin | Wisconsinベンチマークを行うテスト。SQL文の実行速度を計測できる |
今回のベンチマークには、CPUとしてCore 2 Duo(2.33GHz)を搭載したLinuxマシンを使用した。OSにはDebian GNU/Linux 5.0を使用している(表2)。また、MySQLの設定は基本的にはデフォルトのままだが、バッファ/キャッシュサイズについては表3のように変更している。ベンチマークはそれぞれ3回ずつ実行し、その平均をベンチマーク結果とした。なお、今回のベンチマークではデータベースとしてMySQLデフォルトのMyISAMを使用しているため、トランザクションに関するベンチマークは行っていない。そのほかベンチマークの詳細な手順については、コラムを参照してほしい。
構成要素 | スペック |
---|---|
CPU | Core 2 Duo E6550(2.33GHz) |
OS | Debian GNU/Linux 5.0 |
メモリ | 2GB |
HDD(OS) | Seagate Barracuda 7200.10(250GB) |
HDD(DB) | Maxtor DiamondMax Plus 9(80GB) |
設定項目 | 値 |
---|---|
key_buffer_size | 860MB |
table_cache | 512 |
sort_buffer_size | 128MB |
read_buffer_size | 100M |
read_rnd_buffer_size | 96MB |
myisam_sort_buffer_size | 128MB |
thread_cache_size | 64 |
query_cache_size | 256MB |
今回のベンチマークは、次のような手順で行った。なお、今回のベンチマークは比較的スタンダードな設定で行っているが、ベンチマーク結果はMySQLの設定や使用するマシンのCPU、OS、搭載メモリ、ストレージなどによって大きく変動する場合がある。ベンチマークに必要なファイル等はすべてWeb上からダウンロードできるので、実際に手元で確認していただきたい。
MySQL 5.1のダウンロードページから、Linux(non RPM package)およびLinux(non RPM, Intel C/C++ compiled, glibc-2.3)版のバイナリをダウンロードし、アーカイブに含まれている「INSTALL-BINARY」ファイルの指示通りにインストールしてMySQLサーバーを起動する。なお、MySQLサーバーはオプションで使用するバッファやキャッシュのサイズを指定できるが、今回は「mysqld_safe」コマンドに次のようなオプションを付けて起動した。
$ ./mysqld_safe --user=mysql --key_buffer_size=860MB --table_cache=512 \ --sort_buffer_size=128MB --read_buffer_size=100M --read_rnd_buffer_size=96MB \ --myisam_sort_buffer_size=128MB --thread_cache_size=64 --query_cache_size=256MB
sql-benchは実行にPerlおよびDBIモジュールが必要である。今回テストに使用したDebian GNU/Linuxの場合、次のようにして必要なモジュールのインストールが行える。
# apt-get install libdbd-mysql-perl
また、実行結果はベンチマークを実行したディレクトリ以下の「output」ディレクトリ内に保存されるので、あらかじめこのディレクトリを作成し、ベンチマークを実行するユーザーが書き込めるようにパーミッションを設定しておく。
sql-benchディレクトリ中の「run-all-tests」を実行することでベンチマークが開始される。
$ cd sql-bench $ ./run-all-tests
それではベンチマーク結果を見てみよう。sql-benchには9つのベンチマークが含まれているが、それらを起動してから実行完了するまでにかかった時間を比較したものが表4だ。
ベンチマーク項目 | ICC版 | GCC版 |
---|---|---|
alter-table | 18.3秒 | 31.7秒 |
ATIS | 3.7秒 | 3.3秒 |
big-tables | 3.0秒 | 4.0秒 |
connect | 50.0秒 | 50.7秒 |
create | 248秒 | 249秒 |
insert | 648秒 | 663秒 |
select | 44.7秒 | 59.0秒 |
wisconsin | 4.0秒 | 3.7秒 |
また、GCC版の結果を1とした場合の相対的な実行結果を示したものが図1である。
ベンチマーク結果でまず目を引くのが、alter-tableテストおよびselectテスト実行の結果である。インテル コンパイラー版バイナリはGCC版バイナリと比べ、alter-tableテストでは約6割、selectテストでは約8割ほどの時間でテストを完走できている。ATISおよびwisconsinテストではGCC版のほうがインテル コンパイラー版よりも若干速かったが、これらについてはそれぞれ0.4秒、0.3秒という僅差である。
また、wisconsinベンチマークによって測定されたSQLコマンドごとのパフォーマンスをまとめたものが表5である。この表は、それぞれのSQLコマンドを一定回数実行するのにどれだけ時間がかかったか、というのを示しており、数値が小さいほどパフォーマンスが高い。この結果を見ると、インテル コンパイラー版バイナリはテーブルへの項目追加/削除といった操作が大幅に高速化されていることが分かるほか、データの並び替えやキャッシュされたテーブルのselect、キーの更新などもインテル コンパイラー版バイナリの方が高速、という結果となっている。
操作 | 所要時間(秒) | |
---|---|---|
ICC版 | GCC版 | |
alter_table_add | 7.3 | 13.7 |
alter_table_drop | 7.7 | 13.3 |
count | 3.0 | 8.7 |
insert_key | 137.3 | 140.3 |
order_by_big | 9.0 | 10.7 |
order_by_big_key | 8.7 | 10.0 |
order_by_big_key_desc | 9.0 | 10.7 |
order_by_big_key_diff | 9.0 | 10.7 |
order_by_big_key_prefix | 8.3 | 9.3 |
prepared_select | 16.3 | 18.0 |
select_big | 8.7 | 9.7 |
select_cache2 | 26 | 39.7 |
select_key | 30.3 | 27.0 |
select_key2 | 32.7 | 28.7 |
select_key2_return_key | 30.3 | 27.3 |
select_key2_return_prim | 31.7 | 28.0 |
select_key_prefix | 32.3 | 28.0 |
select_key_return_key | 29.0 | 26.3 |
update_of_key | 6.7 | 21.0 |
update_of_primary_key_many_keys | 42.0 | 37.0 |
このように、MySQLのWebサイトで配布されているインテル コンパイラー版バイナリはGCC版バイナリよりも高速ということが分かったが、さらにこれを高速化することはできないだろうか。MySQLのWebサイトによると、このインテル コンパイラー版バイナリは、下記のような設定でコンパイルされている。
CC=icc CXX=icpc CFLAGS="-O3 -unroll2 -ip -mp -no-gcc -restrict" CXXFLAGS="-O3 -unroll2 -ip -mp -no-gcc \ -restrict" ./configure --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data \ --libexecdir=/usr/local/mysql/bin --with-extra-charsets=complex --enable-thread-safe-client \ --enable-local-infile --enable-assembler --disable-shared --with-client-ldflags=-all-static \ --with-mysqld-ldflags=-all-static --with-embedded-server --with-innodb
この設定では、複数のファイル間での最適化を行うIPOが行われていない。また、インテル コンパイラーは特定のCPU向けに最適化したバイナリを生成する機能があるが、こちらについても利用されていない。そこで、続いてはこれらの機能を有効にしてMySQLをコンパイルし、MySQLのWebサイトで提供されているインテル コンパイラー版バイナリと比較してみよう。
コンパイルには、インテル コンパイラー 11.0の体験版を使用した。この体験版は国内でインテル コンパイラーの代理店となっているエクセルソフトのWebサイトからダウンロード可能だ。30日の使用制限があるものの、機能的には正式版とまったく同等である。
今回使用したコンパイル設定は下記のようにした。なお、IPOを利用する場合、アーカイバとしてLinux標準のarではなく、インテル コンパイラーに付属するxiarを利用することに注意して欲しい。
AR=xiar CC=icc CXX=icpc CFLAGS="-O3 -unroll4 -ipo -fp-model precise -no-gcc -restrict -xSSSE3" \ CXXFLAGS="-O3 -unroll4 -ipo -fp-model precise -no-gcc -restrict -xSSSE3" ./configure \ --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data --libexecdir=/usr/local/mysql/bin \ --with-extra-charsets=complex --enable-thread-safe-client --enable-local-infile --enable-assembler \ --disable-shared --with-client-ldflags=-all-static --with-mysqld-ldflags=-all-static \ --with-embedded-server --with-innodb
また、原稿執筆時に公開されているMySQL 5.1.31は、そのままではインテル コンパイラーでコンパイルできないという問題がある。この件はすでにMySQLのバグリポートで指摘されており、MySQLのソースコードを展開したディレクトリ以下の「mysys/stacktrace.c」を次のように修正することで対応できる。
ソースコード69行目の下記の部分 #if BACKTRACE_DEMANGLE char __attribute__ ((weak)) *my_demangle(const char *mangled_name, int *status) { return NULL; } を、次のように修正する。 #if BACKTRACE_DEMANGLE #if defined(__INTEL_COMPILER) #pragma weak my_demangle=my_demangle_null char *my_demangle_null(const char *mangled_name, int *status) #else /* __INTEL_COMPILER */ char __attribute__ ((weak)) *my_demangle(const char *mangled_name, int *status) #endf /* !__INTEL_COMPILER */ { return NULL; }
インテル コンパイラーでは、浮動小数点の精度を「-fp-model」コンパイルオプションで指定できる。今回は「precise」を指定したが、もし高い精度が不要な場合はこれを「fast=1」(高速)に変更することでより高速化できる可能性がある。もし興味のある方は試してみてほしい。
このようにしてコンパイルしたMySQLを先の公式版バイナリとまったく同様の設定でセットアップ・起動し、sql-benchを実行した結果が次の表6、図2である。alter-tableテストについては公式のインテル コンパイラー版よりもパフォーマンスが低下したものの、insertテストやconnectテストについてはパフォーマンスの向上が見られた。また、wisconsinテストによるSQLコマンドごとのパフォーマンス結果については、全体的にはパフォーマンスの向上が見られたものの、項目によっては公式版のほうがパフォーマンスが良い、という結果になったものもあった。
ベンチマーク項目 | インテル コンパイラー版 | 公式GCC版 | |
---|---|---|---|
自作版 | 公式版 | ||
alter-table | 29.3秒 | 18.3秒 | 31.7秒 |
ATIS | 3.3秒 | 3.7秒 | 3.3秒 |
big-tables | 3.3秒 | 3.0秒 | 4.0秒 |
connect | 48.3秒 | 50.0秒 | 50.7秒 |
create | 252.0秒 | 248.0秒 | 249.0秒 |
insert | 618.3秒 | 648.3秒 | 662.7秒 |
select | 44.0秒 | 44.7秒 | 59.0秒 |
wisconsin | 3.3秒 | 4.0秒 | 3.7秒 |
操作 | 所要時間(秒) | ||
---|---|---|---|
インテル コンパイラー版 | GCC版 | ||
自作版 | 公式版 | ||
alter_table_add | 13.0 | 7.3 | 13.7 |
alter_table_drop | 12.3 | 7.7 | 13.3 |
count_distinct_big | 2.3 | 3.7 | 3.7 |
count_on_key | 9.3 | 9.3 | 11.3 |
delete_all_many_keys | 65.7 | 78.0 | 77.7 |
delete_big_many_keys | 65.7 | 78.0 | 77.7 |
insert_key | 125.7 | 137.3 | 140.3 |
once_prepared_select | 11.0 | 12.7 | 12.7 |
prepared_select | 16.7 | 16.3 | 18.0 |
select_cache2 | 25.7 | 26.0 | 39.7 |
select_key | 26.0 | 30.3 | 27.0 |
select_key2 | 27.3 | 32.7 | 28.7 |
select_key2_return_key | 26.7 | 30.3 | 27.3 |
select_key2_return_prim | 27.0 | 31.7 | 28.0 |
select_key_prefix | 27.0 | 32.3 | 28.0 |
update_of_key | 28.7 | 6.7 | 21.0 |
update_of_primary_key_many_keys | 42.3 | 42.0 | 37.0 |
以上のように、インテル コンパイラーでコンパイルしたMySQLバイナリは、sql-benchにおいてGCCでコンパイルしたものと比べ高いパフォーマンスを発揮していることが分かった。特にinsertやselectといった操作はより高速に実行できる可能性がある。
ただし、実運用環境においては必ずしも大きな差が出るとは限らない点には気を付けてほしい。たとえば、MySQL向けの簡易ベンチマークとして、mysqlbenchというものがあるが、こちらのベンチマーク結果では、インテル コンパイラー版とGCC版とではほとんどパフォーマンスに差が見られなかった。このmysqlbenchはTPC-Bと呼ばれる、バッチ処理をイメージした単純なトランザクションのパフォーマンスを測定するもので、どちらかというとI/Oパフォーマンスが重視されるベンチマークだからだと思われる。
この点を考慮しても、インテル コンパイラー版のMySQLバイナリはGCC版バイナリ以上のパフォーマンスが期待できると考えて良いだろう。また、MySQLに限らず、ほかのデータベースシステムでもインテル コンパイラーを利用することで高速化が期待できる。もちろん、世の中のすべてのプログラムがインテル コンパイラーで高速化できるわけではないが、もし高いパフォーマンスが要求されるアプリケーションが必要な場合、一度インテル コンパイラーでのコンパイルを試してみてはいかがだろうか。
なお、インテル コンパイラーの最新情報や採用事例などはインテルのWebサイトでも公開されている。インテル コンパイラーに興味を持たれた方は、ぜひこちらも参照してほしい。
[PageInfo]
LastUpdate: 2009-11-16 19:35:52, ModifiedBy: hiromichi-m
[Permissions]
view:all, edit:login users, delete/config:members