dmd 2.058 のリリース


投稿ツリー



前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 .2 | 投稿日時 2012/2/15 21:51 | 最終変更
SHOO  管理人   投稿数: 658
[1@digitalmars.com" rel="external">http://forum.dlang.org/thread/jhfdcu$iht$1@digitalmars.com 公式アナウンス]

* 新機能
- 新しくラムダ式 ( => )を追加
- 1.userproperty のユーザー定義プロパティを追加
- -sharedスイッチを-dylibの代わりに追加。
- OSX向けのXMMレジスタ対応の強化
- AVXインストラクションの追加(64bit向け)
- ベースクラスの保護は非推奨(public/private/protected継承)
- traitsに isVirtualMethod と getVirtualMethods の追加
- 構造体やクラスのinvariant()は暗黙的にconstになった


* バグフィックス
多いので特に私が注目したのは…
- [[Bugzilla:314]]: static importなどが必ずpublicになってしまう問題
- [[Bugzilla:620]]: テンプレートメンバ関数だとプロパティに出来なかった問題
の2つです。やっと解決したか、という感じ。

* 破壊的変更
今回もいくつかあります。
- (int, real){ /* 処理 */ } このように、デリゲートリテラルの仮引数を省略できなくなりました。(ラムダ式の影響)
- auto dg = (int a){ return a; } この、dgは今まではデリゲートでしたが、今回のバージョンからは関数ポインタに推論されます(リテラル内から外の変数に一切アクセスしていないため)
投票数:30 平均点:7.00
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 .2 | 投稿日時 2012/2/18 4:57
TM 
生成バイナリの浮動小数点計算のパフォーマンスが2.057のものと比較して大きく変わっているようです。
2coreのx86マシンでは3倍近く上昇しましたが、一方8coreのAMD64機では半減致しました。
共にwindowsマシンですがレジスタ周りで何かしら改修があったのでしょうか?
投票数:22 平均点:5.45
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2012/2/23 0:51
SHOO  管理人   投稿数: 658
パフォーマンスに関する点としては、関数のインライン化に関する更新があったようです。浮動小数点演算では…ベクトル演算関連くらいしか思い当たるものはありませんね…。私はdmdの中身まで詳しくは無いので、もしかしたら何かしらの変更があったのかもしれません。
投票数:32 平均点:3.13
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2012/2/23 11:19
tama  一人前   投稿数: 111
コードを貼ると,誰かコンパイラのバックエンドのコードジェネレータに詳しい人が反応してくれるかもしれません!

Macだとどうなのだろうか…
投票数:23 平均点:4.78
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 | 投稿日時 2012/2/24 6:12
ゲスト 
次のようなコードです。(大変汚くて申し訳ございません^q^;)
2.057と2.058で特に最適化をかけたときに顕著に差が見られます。

#code(d){{{
import std.stdio, std.datetime, std.math, std.random, std.parallelism, core.thread;

immutable int benchTime = 10;

void main(){
uint floatScore = 0;
FloatBench[] f_thread = new FloatBench[totalCPUs];
foreach(ref elem; f_thread){
elem = new FloatBench;
}

foreach(ref elem; f_thread){
elem.start();
}

foreach(ref elem; f_thread){
elem.join();
floatScore += elem.localCount;
}

writeln("score : ", floatScore);
}



class FloatBench : Thread{

this(){
super(&run);
}

uint localCount = 0;

private:
void run(){

immutable uint arr = 0x100;
auto rnd = Xorshift(unpredictableSeed);
StopWatch sw;
double[arr] a , b, c = 0;

for(uint i = 0; i < arr; i++){
a[i] = uniform(sqrt(double.max)*(-1) + 1.0, sqrt(double.max), rnd);
b[i] = uniform(sqrt(double.max)*(-1), sqrt(double.max) - 1.0, rnd);
}

sw.start();
while(sw.peek().seconds < benchTime){
for(int i = 0x3FFF; i >= 0; i--){
c[] += a[] * b[];
a[] += uniform(-0.5, 0.5, rnd);
c[] -= a[] * b[];
b[] -= uniform(-0.5, 0.5, rnd);
}
localCount++;
}
}
}
}}}
投票数:37 平均点:2.97
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 | 投稿日時 2012/3/3 3:27
SHOO  管理人   投稿数: 658
御返事遅くなりました。

ちょっとだけ調べてみました。

#code(d){{{
foreach (i; 0..0x3FFF)
{
c[] += a[] * b[];
a[] += rnds[i&0xf];
c[] = a[] * b[];
b[] -= rnds[i&0xf];
}
}}}
このコードは、
#code(console){{{
dmd -O -release -inline -c main
obj2asm main>output.txt
}}}
として吐いたアセンブリでは
#code(asm){{{
L168: push dword ptr -018B4h[EBP]
push dword ptr -018B8h[EBP]
push dword ptr -018ACh[EBP]
push dword ptr -018B0h[EBP]
push dword ptr -018A4h[EBP]
push dword ptr -018A8h[EBP]
call near ptr __arraySliceSliceMulSliceAddass_d
mov ESI,EBX
and ESI,0Fh
push dword ptr -08Ch[ESI*8][EBP]
push dword ptr -090h[ESI*8][EBP]
push dword ptr -018B4h[EBP]
push dword ptr -018B8h[EBP]
call near ptr __arrayExpSliceAddass_d
push dword ptr -018B4h[EBP]
push dword ptr -018B8h[EBP]
push dword ptr -018ACh[EBP]
push dword ptr -018B0h[EBP]
push dword ptr -018A4h[EBP]
push dword ptr -018A8h[EBP]
call near ptr __arraySliceSliceMulSliceAssign_d
push dword ptr -08Ch[ESI*8][EBP]
push dword ptr -090h[ESI*8][EBP]
push dword ptr -018ACh[EBP]
push dword ptr -018B0h[EBP]
call near ptr __arrayExpSliceMinass_d
inc EBX
add ESP,050h
cmp EBX,03FFFh
jb L168
}}}
このようになります。
これはつまり、 c[] += a[] * b[]; というようなコードが、 _arraySliceSliceMulSliceAddass_d という関数の呼び出しに変換されているということです。この関数はdmdが自動生成しているようです。(この関数にはXMM命令を使用していません。また、_arraySliceSliceMulSliceAssign_d という関数はdruntimeが定義していて、XMM対応している)
したがって、この関数の中身を見れば、バージョンアップ前後の違いがわかるかと思います。
#code(asm){{{
__arraySliceSliceMulSliceAddass_d comdat
assume CS:__arraySliceSliceMulSliceAddass_d
push EBX
xor EDX,EDX
cmp 8[ESP],EDX
je L28
L9: mov EAX,01Ch[ESP]
mov ECX,014h[ESP]
mov EBX,0Ch[ESP]
fld qword ptr [EDX*8][EAX]
fmul qword ptr [EDX*8][ECX]
fadd qword ptr [EDX*8][EBX]
fstp qword ptr [EDX*8][EBX]
inc EDX
cmp EDX,8[ESP]
jb L9
L28: mov EDX,0Ch[ESP]
mov EAX,8[ESP]
pop EBX
ret
__arraySliceSliceMulSliceAddass_d ends
}}}
多分これ?が中身です。
すべての処理系でこれと同一のものが吐かれるとは限りませんし、どのCPUがこれらの命令を実行するのにどれだけコストを使うか等しりませんが…。
参考になれば幸いです。

また、ベンチマーク用のコードで少し気になった点が。
+ スレッドを使用していますが、場合によっては浮動小数点演算の精度や速度に影響する可能性があります。詳しくは知りませんが、昔浮動小数点演算の精度がやたら落ちて結局スレッドのせいだった覚えがあります。
+ 乱数の生成がベンチマークのコード内のループ処理内に入っています。浮動小数点演算のベンチマークがしたいのであれば、これらはループ処理内に入れるべきではありません。
+ あと、ベンチマークには関係ないですし、結論としては問題ないのですが、
double[arr] a , b, c = 0;
このコードはあまりオススメできません。a, bはdouble.nanで初期化され、cだけ0で初期化されます。
a,bはあとのfor文で初期化しますので問題ありませんが、こういった、あとで初期化することを明示したい場合は
double[arr] a = void, b = void, c = 0;
とするのがいいでしょう。もっと言えば、宣言を分けるのがいいでしょう。
double[arr] a = void;
double[arr] b = void;
double[arr] c = 0;
+ 定数の宣言はenumでしたほうが良いでしょう(enumなら確実にコンパイル時に実行されます。staticではないimmutableではコンパイル時か実行時か曖昧です。)
immutable uint arr = uniform(0, 10, rnd); // 実行時に初期化されて値が決定
enum arr = 0x100; // コンパイル時に確実に値が決定
投票数:34 平均点:5.59
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2012/3/4 23:15
ゲスト 
いくらか検証を行ったところ、SHOOさんの推測の通りトラブルの元はスレッドで、スレッドを利用しない実装ではパフォーマンスに有意な差は認められませんでした。
また、スレッド実装のものでもlinux版DMDではこの現象は発生しないようです。

おもしろいことに、ベンチマークをfloatやrealで実装するとwindows環境でも生成バイナリに差はほとんど出ず、doubleの場合に限り2.057版バイナリが異様に肥大し性能が低下するようでした。

つまり、
・windows版DMD
・Threadを利用
・倍精度浮動小数点演算
の場合にのみ、この現象が発生するようです。
これについては引き続き逆アセンブラと格闘してみます。


>SHOOさん
私信ではございますがコードのアドバイスありがとうございました。
まだプログラミング歴3ヶ月程の若輩者ですが今後ともご指導ご鞭撻願います。
投票数:29 平均点:5.17
返信する

このトピックに投稿する

題名
ゲスト名
投稿本文

  条件検索へ


メインメニュー

ログイン

ユーザー名:


パスワード:





パスワード紛失  |新規登録

Menu