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++で組み込みの機能に比較して、整数やバイトデータへのアクセスや繰り返しが
少ないようなアプリケーションならば、かなりの性能が出ると思われます。

XMLパーサの性能

サンプルの 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に関しては、使用に耐えうる反応速度を有しているという
感触を得ています。これはスタンドアロンプログラムの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に分があると言えそうです。

簡易HTTPサーバの性能

サンプルの 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に分があるように見えます。

DBアクセスの性能

サンプルの 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文が簡単な場合は、シンプルなだけその場合の性能がよいのではないか?
  と思われます。