Thread overview
January 12, 2013
int son = 2;
switch(son) {
	case 1: son = 1; break;
	case 2: son = 2; break;
	default:
}

kodunun bir kısmının disasm çıktısı aşağıdaki gibi oluyor
00402019 89 45 FC mov dword ptr [son],eax
0040201C 83 F8 01 cmp eax,1
0040201F 74 07 je D main+18h (0402028h)
00402021 83 F8 02 cmp eax,2
00402024 74 0B je D main+21h (0402031h)
00402026 EB 0C jmp D main+24h (0402034h)

ama case 0: eklersek buraya
0040201C 85 C0 test eax,eax
0040201E 74 0C je D main+1Ch (040202Ch)

oluyor. Neden cmp yerine test kullanılmış ikisi arasında ne gibi farklılıklar var?

Zekeriya

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 12, 2013

Alıntı:

>

Not: Böyle konular çok yararlı oluyor ama konu başlıklarını hep "Inline ASM ile ilgili bir soru" gibi seçersek birbirlerinden ayırt edemeyeceğiz.

Haklısınız :) düzelttim

Zekeriya

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 12, 2013

Biraz yabancı forumlarda araştırdım anladığım kadarıyla

test komutu xor işlemi yapıyormuş
cmp ise subtraction işlemi yapıyormuş

Bu yüzden hızdan tasarruf etmek amacıyla test kullanılmış olabilir

Zekeriya

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 12, 2013

Hiç araştırmadan görebildiğim, test komutu daha az yer tuttuğu için daha etkin. (3 yerine 2 bayt.)

Ali

Not: Böyle konular çok yararlı oluyor ama konu başlıklarını hep "Inline ASM ile ilgili bir soru" gibi seçersek birbirlerinden ayırt edemeyeceğiz. :)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 12, 2013

Alıntı:

>

Mikroişlemci onları aynı hızda işletmiyor muymuş yani? Şaşırırım. Bence ikisi de aynı hızdadır.

Benchmark testine tabi tuttum hemen

import std.datetime;
import std.stdio;
void benchmark_test(){
	asm{
		mov EAX, 10000;
		test EAX,EAX;
	}
}
void benchmark_cmp(){
	asm{
		mov EAX, 10000;
		cmp EAX, 0;
	}
}

void main() {
	auto r = benchmark!(benchmark_test, benchmark_cmp)(10_000);
	writeln(r);
	while(1){}
}

Çıktı:
[TickDuration(55), TickDuration(61)]

Nedenini bilemiyorum ama sonuçlara göre test komutu cmp den daha hızlı gözüküyor.

Zekeriya

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 13, 2013

Evet, sanki test komutu daha hızlı gibi ama benim yaptığım testlerde de birbirlerine çok yakın değerler aldım. Hatta her zaman aynı sonucu almadığım için birbirlerinin değerlerini gördüğüm oldu...

Arka planda hepsi statik sayfalardan oluşan Firefox açıktı ve zaman bilgisini 'time ./asmtest' komutu ile aldım.

Kod ise şöyle:

 bool benchmark_test(int value){
   asm {
     mov EAX, value;
     test EAX, EAX;
     jnz EAXisTrue;
   }
   return false;
   EAXisTrue:
   return true;
 }

 bool benchmark_cmp(int value){
   asm {
     mov EAX, value;
     cmp EAX, 0;
     jnz EAXisTrue;
   }
   return false;
   EAXisTrue:
   return true;
 }

 /*        cmp                test
  * real 0m11.594s          0m11.550s
  * user 0m11.332s          0m11.284s
  * sys  0m0.000s           0m0.000s
  */

void main() {
 immutable xAdet = uint.max >> 3;

 foreach(i; 0..xAdet) {
   //randBool(i).benchmark_cmp();/*
   randBool(i).benchmark_test();//*/
 }
}

bool randBool(size_t n) @property {
 union u { uint i; float f; }

 auto sayı = u(0);
 sayı.f = 1/cast(float)n;

 return sayı.i % 2 ? 1 : 0;
}

Şuradaki komut açıklamalarına baktığımızda da:

Her ikisinin de aynı çevrim (cycle) zamanlarında çalıştığı ama farklı bayrakları kurduğu (set) görülüyor. Yanlış hatırlamıyorsam cmp daha etkin görünüyor.

Sevgiler, saygılar...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 12, 2013

Alıntı (zekeriyadurmus):

>

test komutu xor işlemi yapıyormuş
cmp ise subtraction işlemi yapıyormuş

Mikroişlemci onları aynı hızda işletmiyor muymuş yani? Şaşırırım. Bence ikisi de aynı hızdadır.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 13, 2013

Her işlev çağrısının belirli bir masrafı var. İşlev içindeki işlemler çok az olduğunda o masraf ön plana çıkar ve deneyi etkilemiş olur. O masrafı azaltmanın yolu, deney adedi olan 10_000 değerini işlevin içine foreach döngüsü ekleyip orada bir döngü kurmaktır.

Deneyi her deneyişimizde sonuçlar çok farklı çıkabiliyor.

benchmark'a verilen işlevlerin sırasını değiştirince cmp daha hızlı çıkabiliyor.

Öyle yapılmasa bile cmp daha hızlı çıkabiliyor.

Çıkmasa bile, bellekte diğerinden başka yerde derlenmiş olduğu için biri diğerinden daha hızlı çıkabilir. Bunun nedeni, ilk test yapılırken diğer işlevin kodlarının da mikroişlemcinin ara belleğine girmiş olması olabilir.

Eğer mikroişlemcinin belgesi her iki işlemin de tek çevrimde gerçekleştiğini söylüyorsa öyledir. Bunlar en basit işlemlerden olduklarından başka türlüsünü beklemem. (TEST için reg,reg satırına bakıyoruz çünkü iki yazmaç karşılaştırıyoruz ve CMP için reg,imm satırına bakıyoruz çünkü bir yazmaç ve bir sabit değer (immediate value) karşılaştırıyoruz.)

Ama daha az bayt kullanan kod daha hızlı olacaktır çünkü bellekte daha az yer tuttuğu için mikroişlemcinin ara belleğinden taşma şansı daha azdır. Tabii bu basit deneyde böyle bir etkiyi göremeyiz çünkü bu kadar küçük işlevler sığacaklardır.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]