Altairの性能
第0.43版 2016年10月23日
第0.00版 1996年 2月11日
プロファイリング機能のサンプルによる測定結果
バージョン 0.25からプロファイリング機能を入れました。
関数単位に関数が呼ばれた回数、関数から戻るまでの時間の統計を取ることができます。
サンプルの prof/prof.apr の Test::main() は、以下にかかる時間を測定します。
+ 1000,000回の繰り返し (test_loop)
+ 整数の足し算の1000,000回の繰り返し (test_int_add)
+ 文字列の足し算の1000,000回の繰り返し (test_string_add)
+ オブジェクトのnewの1000,000回の繰り返し (test_new)
+ これらの総計 (test_all)
Javaプログラムの prof/Test.java はこれと同等の測定を行うものです。
これらの結果を以下に示します。
● Windows版
測定マシン: NEC ValueStar VG10J
Altair:バージョン 0.25
Java: JDK1.2.2
Altair Java
test_loop 3,616 0(注1)
test_int_add 5,107 0(注1)
test_string_add 240,286 461,454
test_new 4,266 390
test_all 253,275 461,844 単位 msec
(注1) Windowsマシンは、msec単位の時間を取得しようとしても
10 msec間隔ぐらいの値が取れる。
(注2) ここで測定された時間は、メソッドを呼び出してから
そのメソッドからリターンするまでの時間を測定しているため、
実際にOSが割り付けたCPUタイムより少し大きい。
● Linux版
測定マシン:DELL PowerEdge 1300
Altair:バージョン 0.25
Java: JDK1.1.7
Altair Java
test_loop 7,093 6
test_int_add 9,835 9
test_string_add 337,044 382,188
test_new 8,385 2,519
test_all 362,357 384,730 単位 msec
(注) ここで測定された時間は、メソッドを呼び出してから
そのメソッドからリターンするまでの時間を測定しているため、
実際にOSが割り付けたCPUタイムより
少し大きい。
Altairでは、単純なループや変数へのアクセスはJavaと比較して約1000倍遅いです。
この原因は、Altairでは、スタックフレームや変数領域をLISPのリストのような形式で
表現していて、毎回そのリストをたどったり、操作するためです。
しかし、文字列処理などのC++で組み込みの機能は、十分な速度が出ます。
Altairは、アセンブラで書くことに向いているような非常にプリミティブな処理、
たとえば整数やバイトデータを操作する処理を何回も繰り返すような処理を
記述することには向いていないです。
しかしながら、たいていの必要な機能はC++で組み込みのシステム関数になっており、
たいていのプログラムでは、この部分にかかる時間がほとんどと思われます。
C++で組み込みの機能に比較して、整数やバイトデータへのアクセスや繰り返しが
少ないようなアプリケーションならば、かなりの性能が出ると思われます。
サンプルの prof/prof.apr の Test::main2() は、以下にかかる時間を測定します。
+ test.xmlを百回パーズ
Javaプログラムの prof/Test2.java はこれと同等の測定を行うものです。
prof/Test2XmlGenは、1000個の繰り返し項目がある約2MバイトのXMLデータを
ファイル名 test.xmlで作成します。
このXMLデータをの100回パーズしたとき(バリデーションなし)にかかる時間と
おおよその消費メモリ量の結果を以下に示します。
● Windows版
測定マシン: NEC ValueStar VG10J
Altair:バージョン 0.25
Java: JDK1.2.2
Java XMLパーサー: Xerces 1.4.3
Altair Java
時間 44 23 単位 sec
消費メモリ 24.8 40.2〜44.2 単位 MByte
(注1) ここで測定された時間は、メソッドを呼び出してから
そのメソッドからリターンするまでの時間を測定しているため、
実際にOSが割り付けたCPUタイムより
少し大きい。
(注2) 消費メモリはWindows2000のタスクマネジャに表示されるメモリ使用量。
Altairでは、XMLパースツリーの表現にAltairのグラフ構造データを使っていますが、
ツリー構造を表現するだけなら、グラフ構造が表せるデータ表現は冗長で、
このデータの作成とその破壊のオーバーヘッドのため、Javaのパーサと比較して
性能が2倍程度遅いようです。
また、データの破壊はグラフ構造データのアークをたどるので
これも性能を悪くしている原因のようです。
Altairに組み込みのXMLパーサは、性能を重視するなら不向きかも知れませんが、
統一されたグラフ構造データアクセス方法でパースツリーへのアクセスや作成が
できるのでAltairのプログラミングに慣れていて、開発効率を重視する場合は
使うことに向いていると言えるかも知れません。
消費メモリに関してですが、Windows版Altairでは内部の文字列コードはSJISで
ほとんどが1文字バイトと思われ、これに対しJavaでは内部の文字コードがUnicodeで
1文字が2バイトなのでこの差が出たと思われます。
スタンドアロンプログラムのGUIに関しては、使用に耐えうる反応速度を有しているという
感触を得ています。これはスタンドアロンプログラムのGUIに必要な機能のほとんどが
C++で実装されていて、この部分にかかる時間がこれを呼び出すところに比べて
大きいからと思われます。
サンプルの guitest.apr で TP::all() のプロファイル結果を以下に示します。
● Windows版
測定マシン: NEC ValueStar VG10J
Altair:バージョン 0.25
Java: JDK1.2.2
count total average class func
(msec) (msec)
1 761 761 TP all
1 130 130 TP table_ed_test
1 100 100 TP heavy
1 90 90 TP label_test
1 70 70 TP control_test
1 70 70 TP drag
1 51 51 TP wm_size2
1 50 50 TP graph_ed_test
1 50 50 TableEditor Create
1 40 40 TP hier_ed_test
1 40 40 TP pict_ed_test
1 40 40 TP form_test
1 40 40 TP picture_test
1 40 40 TP wm_size
13 441 33 Window Create
1 20 20 TableEditor _DrawCells
1 20 20 TableEditor Draw
5 30 6 FrameScrollGlyph Draw
5 30 6 ScrollGlyph Draw
15 100 6 Window DrawProc
2 10 5 AlListBox Draw
20 100 5 PolyGlyph Draw
7 30 4 GlyphEditor Draw
9 40 4 Editor MoveControl
18 60 3 PolyGlyph MoveControl
15 50 3 Window MoveCtrlProc
12 30 2 RootGlyph Pick
12 30 2 Window EventProc
12 30 2 GUI Initialize
19 20 1 AlListBox AddItem
6 10 1 AlHScrollBar Draw
6 10 1 AlHScrollBar Create
8 10 1 EllipseGlyph Draw
12 20 1 TargetInfo Initialize
13 20 1 Window SetTitle
60 30 0 TableEditor DefaultCell
15 10 0 Editor Resize
62 20 0 MLabel Draw
83 20 0 LabelGlyph Create
211 10 0 RectangleGlyph Draw
19 10 0 VBoxGlyph _Insert
19 10 0 VBoxGlyph Insert
12 10 0 FormGlyph Resize
14 10 0 SpIdxGlyph Resize
300 150 0 PolyGlyph Append
18 10 0 PolyGlyph Resize
19 10 0 ScrollGlyph AllocationChanged
340 170 0 TMGlyph Body
666 40 0 TMGlyph child_tm
38 20 0 TMGlyph AllocationChanged
349 150 0 TMGlyph Draw
317 60 0 TMGlyph MoveControl
377 10 0 TMGlyph Move
21 10 0 TMGlyph Resize
353 80 0 MonoGlyph Body
38 20 0 MonoGlyph AllocationChanged
364 220 0 MonoGlyph Draw
332 80 0 MonoGlyph MoveControl
84 10 0 Glyph AllocationChanged
308 10 0 Glyph MoveControl
732 40 0 Glyph Width
12 10 0 Event Initialize
(注1) Windowsマシンは、msec単位の時間を取得しようとしても
10 msec間隔ぐらいの値が取れる。
かかった時間が 0とみなされたものは表示していない。
(注2) ここで測定された時間は、メソッドを呼び出してから
そのメソッドからリターンするまでの時間を測定しているため、
実際にOSが割り付けたCPUタイムより少し大きい。
● Linux版
測定マシン:DELL PowerEdge 1300
Altair:バージョン 0.25
count total average class func
(msec) (msec)
1 3896 3896 TP all
1 872 872 TP picture_test
1 847 847 TP table_ed_test
1 527 527 TP graph_ed_test
1 476 476 TP pict_ed_test
1 392 392 TP heavy
1 311 311 TableEditor Create
1 197 197 TP control_test
1 157 157 TP wm_size2
1 147 147 TP hier_ed_test
1 134 134 TP form_test
12 1426 118 GUI Initialize
13 1302 100 Window Create
1 92 92 TP label_test
3 235 78 TableEditor Draw
3 230 76 TableEditor _DrawCells
12 828 69 TargetInfo Initialize
35 1658 47 GlyphEditor Draw
1 35 35 HierEditor Create
1 33 33 HierEditor __CreateOneItem
78 2622 33 Window DrawProc
86 2664 30 PolyGlyph Draw
1 28 28 TP drag
1 27 27 TP wm_size
14 281 20 FrameScrollGlyph Draw
14 276 19 ScrollGlyph Draw
27 436 16 AlHScrollBar Draw
6 34 5 AlHScrollBar Create
4 20 5 VBoxGlyph Draw
4 21 5 FormGlyph FormWithScroll
3 12 4 HierEditor Draw
60 270 4 TableEditor DefaultCell
1 3 3 AlComboBox Create
2 6 3 AlListBox Create
3 9 3 HierEditor _DrawItems
83 267 3 LabelGlyph Create
12 41 3 RootGlyph Pick
12 43 3 Window EventProc
19 41 2 AlListBox AddItem
11 29 2 AlListBox Draw
196 457 2 AlButton DrawBase
11 31 2 AlButton Draw
15 35 2 Editor Resize
34 69 2 EllipseGlyph Draw
14 32 2 SpIdxGlyph Resize
1 1 1 AlComboBox Resize
1 1 1 AlListBox Resize
31 59 1 AlVScrollBar Draw
3 3 1 TableEditor _DrawLines
1 1 1 GraphEditor Create
1 1 1 PathGlyph _CalcBBox
1 1 1 PathGlyph Create
5 5 1 PieGlyph Draw
2 2 1 PictureGlyph Append
19 20 1 VBoxGlyph _Insert
19 21 1 VBoxGlyph Insert
12 19 1 FormGlyph Resize
18 34 1 PolyGlyph Resize
19 19 1 ScrollGlyph AllocationChanged
2466 3129 1 TMGlyph Draw
353 367 1 MonoGlyph Body
2544 4827 1 MonoGlyph Draw
50 2 0 AlMenu Append
11 7 0 AlComboBox Draw
7 1 0 AlHScrollBar Adjust
4 1 0 AlHScrollBar Resize
31 2 0 AlVScrollBar Adjust
8 1 0 AlVScrollBar Create
18 3 0 AlControl Create
6 1 0 HierEditorNodeItr ItrNext
6 2 0 HierEditorNodeItr ItrReset
3 1 0 HierEditor _DrawLines
3 2 0 HierEditor _DrawingArea
9 1 0 TableEditor HPosition
3 2 0 TableEditor _DrawingArea
6 3 0 GlyphEditor Create
14 2 0 ArrowPath Draw
138 123 0 MLabel Draw
66 13 0 LabelGlyph Draw
4 1 0 EllipseGlyph Create
2074 360 0 RectangleGlyph Draw
207 192 0 RectangleGlyph Create
14 1 0 ArrowLine Draw
76 13 0 FormGlyph Attach
300 139 0 PolyGlyph Append
37 4 0 ScrollGlyph Body
12 10 0 ScrollGlyph Resize
340 129 0 TMGlyph Body
2466 423 0 TMGlyph child_tm
38 26 0 TMGlyph AllocationChanged
377 30 0 TMGlyph Move
21 15 0 TMGlyph Resize
38 22 0 MonoGlyph AllocationChanged
4 1 0 Glyph child_tm
84 15 0 Glyph AllocationChanged
796 38 0 Glyph Height
732 45 0 Glyph Width
26 9 0 Glyph Move
452 10 0 Glyph Resize
332 15 0 Glyph Create
12 1 0 Message Initialize
12 3 0 Status Initialize
12 2 0 Event Initialize
(注1) かかった時間が 0とみなされたもの(時間が 1msec未満のもの)は表示していない。
(注2) ここで測定された時間は、メソッドを呼び出してから
そのメソッドからリターンするまでの時間を測定しているため、
実際にOSが割り付けたCPUタイムより
少し大きい。
WindowsではWindowsのMDIを使用しているのに対し、LinuxにはMDIがないので、
一概には言えませんが、プロファイル結果を見ると
スタンドアロンプログラムのGUIに関してはWindowsに分があると言えそうです。
サンプルの net/guitest.apr で Javaの言語仕様のHTMLドキュメントのページを
7ページブラウズしたときのプロファイル結果を以下に示します。
ここで性能が測定されるのは主にSocketへのWriteとSocketからのReadです。
● Windows版
測定マシン: NEC ValueStar VG10J
Altair:バージョン 0.25
Java: JDK1.2.2
count total average class func
(msec) (msec)
28 150 5 HttpConnection DoGet
223 70 0 HttpConnection Send
251 60 0 HttpConnection received
56 50 0 HttpConnection Send
251 40 0 HttpConnection Start
28 20 0 HttpConnection GetAbsolutePath
28 20 0 HttpConnectionMgr accepted
28 10 0 HttpConnection Close
1 10 10 HttpServer Start
1 10 10 HttpServer start
28 0 0 HttpConnection Create
1 0 0 HttpConnectionMgr Close
1 0 0 HttpConnectionMgr Create
28 0 0 HttpServer GetContentType
1 0 0 HttpServer Close
1 0 0 HttpServer Create
1 0 0 HttpServer stop
(注1) Windowsマシンは、msec単位の時間を取得しようとしても
10 msec間隔ぐらいの値が取れる。
かかった時間が 0とみなされたものは表示していない。
(注2) ここで測定された時間は、メソッドを呼び出してから
そのメソッドからリターンするまでの時間を測定しているため、
実際にOSが割り付けたCPUタイムより少し大きい。
● Linux版
測定マシン:DELL PowerEdge 1300
Altair:バージョン 0.25
count total average class func
(msec) (msec)
279 57 0 HttpConnection received
28 52 1 HttpConnection DoGet
223 17 0 HttpConnection Send
279 16 0 HttpConnection Start
28 12 0 HttpConnectionMgr accepted
56 4 0 HttpConnection Send
28 4 0 HttpConnection Close
28 3 0 HttpConnection GetAbsolutePath
28 2 0 HttpConnection Create
28 2 0 HttpServer GetContentType
1 0 0 HttpConnectionMgr Close
1 0 0 HttpConnectionMgr Create
1 0 0 HttpServer Close
1 0 0 HttpServer Start
1 0 0 HttpServer Create
1 0 0 HttpServer stop
1 0 0 HttpServer start
(注1) かかった時間が 0とみなされたもの(時間が 1msec未満のもの)は表示していない。
(注2) ここで測定された時間は、メソッドを呼び出してから
そのメソッドからリターンするまでの時間を測定しているため、
実際にOSが割り付けたCPUタイムより
少し大きい。
ファイルをバイナリモードで読み込む処理があることや
Windows版ではThreadを使っているがLinux版ではselectでpollingしているなどの違いが
あるので一概には言えませんが、この結果を見る限りでは、Socket通信に関しては
Linuxに分があるように見えます。
サンプルの prof/sqlprof.apr で以下のDBアクセスにかかる時間を測定します。
VARCHAR(255)のカラムが6つのPRIMARY KEYのカラムが1個あるDBテーブルについて
+ 20000件のレコードのINSERT(100件毎にcommit)
+ 20000件から100件SELECT(結果を取り出す時間を含む)
+ 20000件から100件DELETE
+ 19800件から全件DELETE
++ INDEXのついたカラムを1個追加した場合
++ INSERTを1000件毎にcommitした場合
● DBサーバマシン
マシン機種:DELL PowerEdge 1300 (CPU:550Hz メモリ: 896M)
OS:TurboLinux7.0
DB
Oracle: Oracle 8.1.7 for Linux
PostgresQL:PostgresQL 7.1.2
● ODBC
WindowsマシンからODBCでDBに接続
Windowsクライアントマシン: NEC ValueStar VG10J (CPU 1GHz メモリ 512M)
使用TP: Windows版Altair バージョン0.26
● Oracle-OCI、Postgres-libpq
DBサーバのLinuxマシンからOracleはOCIのクライアントライブラリで
PostgresQLはlibpqというクライアントライブラリで接続
使用TP: Linux版Altair バージョン0.26
本来は、何回か測定して平均をとらなければなりませんが、
以下は1回計った結果です。
(単位は msec)
|
total |
insert20000 |
select200 |
delete200 |
delete19800 |
commit(total) |
commit(average) |
Oracle ODBC |
73366 |
42380 |
91 |
370 |
28401 |
3825 |
18 |
Oracle ODBC INDEX |
117339 |
62069 |
71 |
220 |
52275 |
5659 |
27 |
Oracle ODBC commit1000 |
70732 |
37363 |
100 |
381 |
31145 |
530 |
22 |
Oracle OCI |
72440 |
38753 |
88 |
221 |
31391 |
4533 |
22 |
Oracle OCI INDEX |
123386 |
63608 |
77 |
197 |
56949 |
5394 |
26 |
Oracle OCI commit1000 |
73682 |
40083 |
99 |
218 |
31648 |
573 |
23 |
PostgresQL ODBC |
56111 |
55120 |
130 |
130 |
361 |
1942 |
9 |
PostgresQL ODBC INDEX |
59195 |
57463 |
60 |
60 |
1412 |
2113 |
10 |
PostresQL ODBC commit1000 |
55790 |
55009 |
130 |
100 |
381 |
520 |
21 |
PostgresQL libpq |
46811 |
45045 |
119 |
108 |
1329 |
1936 |
9 |
PostgresQL libpq INDEX |
47792 |
47086 |
56 |
67 |
377 |
1787 |
8 |
PostgresQL libpq commit1000 |
44289 |
43475 |
142 |
164 |
360 |
457 |
19 |
この結果から以下のようなことが推測されます。
レコードの件数が2万件程度の場合で単純なSQL文しか使わない場合:
+ OracleはODBCを使ってもOCIネイティブを使っても差はあまりない。
+ PostgresQLでは手に入りやすいODBCドライバはネイティブに比べ約20%遅い。
+ PostgresQLのINSERT(libpq)の速度はOracleのINSERTの速度に比べて同程度(誤差10%以内)。
+ INDEXをつけた場合、OracleのINSERTは約50%遅くなるがPostgresQLでは約5%しか遅くならない。
+ INDEXのある場合のINSERTは、PostgresQLの方がOracleに比べて約30%速い。
+ INDEXを使ったSELECT/部分DELETEは、INDEXを使わない場合に比べ
Oracleでは約20%しか速くならないのにPostgresQLでは約50%速くなる。
+ INDEXのついていないSELECTは、Oracleの方が約40%速い。
+ INDEXを使った場合のSELECTは、PostgresQLの方が約20%速い。
+ 全件DELETEでは、PostgresQLの方がOracleに比べ約28倍速い。
+ INDEXがついている場合の全件DELETEでは、PostgresQLの方がOracleに比べ約141倍速い。
(INDEXがつくとOracleの場合全件DELETEが遅くなるのに対し
PostgresQLではINDEXがない場合に比べて速くなっている)
+ 部分DELETEでは、Postgresの方が約2.5倍速い。
+ INDEXを使った部分DELETEでは、Postgresの方が約3.5倍速い。
+ commitにかかる時間はOracleに比べPostgresQLでは約半分。
+ INSERT時に100件毎にcommitを1000件毎にcommitに変えた場合(commit回数約10倍にした場合)、
commitにかかる総時間は、Oracleでは約1/8になるのに対し、PostgresQLでは1/3にしかならない。
この場合commitにかかる総時間はOracleとPostgresQLで同程度。
(Oracleでは、更新データ量が多くても少なくてもcommitにかかる時間は一定であるのに対し、
PostgresQLでは、更新データ量が多くなるとcommitにかかる時間も多くなる。)
推測:
Oracleはデータ量がが大規模でもSQL文が複雑でもRollback領域をたくさん使ってもコンスタントな性能が
でるようになっているがその反面、簡単なことにかかるオーバーヘッドが大きいのではないか?
これに対し、PostgresQLでは大規模データや複雑なSQL文の場合に性能が出ないかも知れないが、
データ量が少ない場合やSQL文が簡単な場合は、シンプルなだけその場合の性能がよいのではないか?
と思われます。