Thread overview
Xor ile değiş tokuş daha yavaş
May 18, 2013
Salih Dinçer
May 18, 2013
Salih Dinçer
May 19, 2013
Salih Dinçer
Jul 30, 2013
Salih Dinçer
Jul 31, 2013
Salih Dinçer
May 17, 2013

DConf 2013'ün sunumları belirli aralıklarla (Pazartesi, Çarşamba, ve Cuma) Reddit'te duyuruluyor:

http://www.reddit.com/r/programming/

O sayfada mikroişlemci mimarileriyle ilgili bir yazıyla karşılaştım:

http://www.gamedev.net/page/resources/_/technical/general-programming/a-journey-through-the-cpu-pipeline-r3115

O yazının yan bilgilerinden birisi olarak da daha hızlı olduğu sanılan xor işleci yönteminin modern işlemcilerde aslında daha yavaş kaldığını öğrendim:

import std.stdio;
import std.datetime;

enum döngüTekrarı = 10_000;
enum işlevTekrarı = 10_000;

void swapTemp(T)(ref T lhs, ref T rhs)
{
   foreach (i; 0 .. döngüTekrarı) {
       T temp = lhs;
       lhs = rhs;
       rhs = temp;
   }
}

void swapXor(T)(ref T lhs, ref T rhs)
{
   foreach (i; 0 .. döngüTekrarı) {
       lhs ^= rhs;
       rhs ^= lhs;
       lhs ^= rhs;
   }
}

void main()
{
   int i, j;
   auto ölçümler = benchmark!(() { swapTemp(i, j); },
                              () { swapXor(i, j); })(işlevTekrarı);

   writefln("swapTemp: %8s ms", ölçümler[0].to!("msecs", int));
   writefln("swapXor : %8s ms", ölçümler[1].to!("msecs", int));
}

Bendeki bir çıktısı:
'
swapTemp: 203 ms
swapXor : 716 ms
'
Ali

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

May 18, 2013

Yukarıda bir büyü var...:)

Bu büyü, assembly büyüsü! Altyordam ve döngü kodlarını saymazsak, her iki algoritmanın birbirine eşit olduğunu söyleyemeyiz. Hatta XOR algoritması, 3 satırdan oluşmayabilir. Assembly kodlarına bakmadım ama kodları birbirine eşitlemeliyiz. Çünkü XOR yöntemi, her ne şartta olursa olsun ve/veya işlemci kullanılırsa kullanılsın sistem kaynakllarından tasarruf etmeli...

Biz 3 defa XOR yaptığımızı zannediyoruz ama (zannedersem) yazmaçlar arası veri aktarıldığı için bu 2 katına da çıkabilir. O yüzden derleyicinin işini şu şekilde kolaylaştırmalıyız:

       T temp = lhs ^ rhs;
       rhs ^= temp;
       lhs ^= temp;

İşte bu şekilde test ettiğimizde, sürelerin birbirine daha yakın olduğunu görebiliriz. Çok daha iyi bir sonuç (optimization) için 'asm { }' kümesi kullanmak işe yarayabilir.

Alıntı:

>

$ dmd testxor.d -release -m32 && ./testxor
swapTemp: 283 ms
swapXor : 363 ms

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

May 18, 2013

Alıntı (acehreli):

>

...Oyun programcılığında performans çok önemli olduğundan değişkenlerin değerlerini bilerek erkenden atama (prefetch) gibi numaralar yapmaları gerekiyormuş.
Vaouvvv... 8-(

Bu konuyu biraz araştırmalıyım...

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

May 18, 2013

Alıntı (Salih Dinçer):

>

assembly büyüsü

Değilmiş; mikro işlemci büyüsüymüş. :)

Yukarıdaki yazıda da anlatıldığı gibi, modern mikroişlemciler her işlemi en az beş parça halinde işliyorlarmış (yazıda "5-stage pipeline" denen yer): işlemi oku (fetch), ana dönüşüm (decode), ikincil dönüşüm, işletme, sonuçları yazma.

Birden fazla işlemin beş alt parçası birbirlerini etkilemedikleri sürece aynı anda işletiliyorlar.

Bu mimariye daha yatkın olduğundan geçici değişken kullanan yöntem daha hızlı sonuç veriyor.

Belki de derleyiciden şunu bekleyebiliriz: "Şu üç satırdan anlaşıldığına göre bu programcı aslında değiş tokuş yapıyor. O zaman ben bu mimaride daha hızlı sonuç ürettiğini bildiğim geçici değişken yöntemini uygulayayım."

Olabilir... Ama o anda boşta yazmaç yoksa belleğe yazmak daha yavaş sonuç verebilir. vs...

Alıntı:

>

Çok daha iyi bir sonuç (optimization) için 'asm { }' kümesi kullanmak işe yarayabilir.

Doğrudur ama programcının D yanında bir de assembly bilmesi beklenmemeli. Örneğin ben bilmiyorum. Bu da çalışma hayatım sırasında sıfır adet asm bloğu yazdığımı gösterir. Düşünüyorum: Çalıştığım hiçbir projede başkaları tarafından da asm bloğu yazılmadı. O yüzden onu bir kenara bırakalım. Hem o bambaşka bir düşünce tarzı gerektiriyor hem de bu örnekte de gördüğümüz gibi, programcının akıllılıklarının etkisi ters olabiliyor.

O yazının sonuç bölümünde "programlarınız hep basit olsun" ("Always keep your code simple") deniyor. Kabul... Buna rağmen, Manu Evans'ın DConf 2013'teki ikinci konuşmasını da görmenizi öneririm (o konuşma henüz hazır değil). Oyun programcılığında performans çok önemli olduğundan değişkenlerin değerlerini bilerek erkenden atama (prefetch) gibi numaralar yapmaları gerekiyormuş.

Ali

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

May 19, 2013

Tekrar Merhaba,

Kodu biraz değiştirmek zorunda kaldım. Çünkü derleyici, değerlerin durumunu koruduğunu bildiğinden kestirme yollar seçiyor. Gerçekten de XOR biraz daha yavaş ama 2 kat değil. Duruma göre 1 veya 2 fazla komut işlettiği için de olabilir, bilemiyorum. Bütün bunları LibreOffice Calc ile yaptığım karşılaştırmada görebilirsiniz. Bilgisayarımdaki test sonucu ise şu şekilde:

Alıntı:

>

'$ ./d.sh testxor.d
swapTemp: 252 ms
swapXor : 414 ms'

http://img28.imageshack.us/img28/598/testxor.png

import std.stdio;
import std.datetime;

enum döngüTekrarı = 10_000;
enum işlevTekrarı = 10_000;

struct Deneme
{
   int a = 100;
   int b = 101;
   int c;
}

void TMP(ref Deneme test)
{
   foreach (i; 0 .. döngüTekrarı)
   {
        with (test)
        {
            c = a;
            a = b;
            b = a;
        }
   }
}

void XOR(ref Deneme test)
{
   foreach (i; 0 .. döngüTekrarı)
   {
        with (test)
        {
            c = a ^ b;
            a ^= c;
            b ^= c;
        }
   }

}

void main() {
   Deneme bir, iki;

   with (bir) {
       c = a ^ b;
       a ^= c;
       b ^= c;
   }

   asm { nop; nop; nop; }

   with (iki) {
       c = a;
       a = b;
       b = a;
   }

   asm { nop; nop; nop; }

   auto ölçümler = benchmark!(() { bir.TMP(); },
                              () { iki.XOR(); })(işlevTekrarı);

   writefln("swapTemp: %8s ms", ölçümler[0].to!("msecs", int));
   writefln("swapXor : %8s ms", ölçümler[1].to!("msecs", int));
}

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

July 30, 2013

Dün Facebook'da bir tartışma (-bknz. Rhodeus Grubu (https://www.facebook.com/groups/rhodeus/)) başlamıştı ve ben de buraya referans verdim...

Alıntı ("Çağatay Karahan"):

>

Gençler c# a başladım.

int a = 1;
int b = 2;

Başka bir değişken kullnmadan a'nın değerini b'ye b'nin değerini a'ya nasıl atayabilirim?

Benim önerim, yavaş olduğunu belirtmekle birlikte şöyleydi:

 asm {
   mov EAX, lhs;
   mov EBX, rhs;
   xor EAX, EBX;
   xor EBX, EAX;
   xor EAX, EBX;
   mov lhs, EAX;
   mov rhs, EBX;
 }

En son başka bir arkadaşımız da matematiği kullandı:

Alıntı ("Ahmet Akif Uğurtan"):

>

a=3 b=5 ise
a=a+b; a=8 oldu
b=a-b; b=3 oldu
a=a-b; a=5 oldu
yer değiştirdiler :)

Bugün sahurdan hemen sonra biraz düşündüm ve bu tartışmanın çok gereksiz olduğu sonucuna vardım. Çünkü gerek toplama/çıkarma, gerekse XOR yapmak için değerleri yazmaçlara kaydetmek gerekiyor. Üstelik matematik işlemlerinde işaretli değerler olabileceğinden en az iki kat daha fazla kodlama (karşılaştırma ve dallanma komutları: CMP, JNZ vb.) gerekecek. Oysa yazmaçlara alınan değerler pekala çaprazlama eşleştirilebilirdik:

 asm {
   mov EAX, lhs;
   mov EBX, rhs;
   mov lhs, EBX;
   mov rhs, EAX;
 }

Bu 4 satırlık assembly kodunu hızını ölçmek için başka hiç bir şeyle karşılaştırma yapma gereği duymuyorum! Sanırım bundan hızlı bir yer değiştirme yapılamazdı herhalde...:)

Saygılarımla...

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

July 30, 2013

Alıntı (Salih Dinçer):

>
>   asm {
>     mov EAX, lhs;
>     mov EBX, rhs;
>     mov lhs, EBX;
>     mov rhs, EAX;
>   }
> ```

> Bu 4 satırlık assembly kodunu hızını ölçmek için başka hiç bir şeyle karşılaştırma yapma gereği duymuyorum!

En baştaki swapTemp() de öyle derlenmiyor mu zaten?

Ali

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

Sanırım D biraz fazlasını yapıyor. Örneği LEA'yı kullanıyor ve 4 satır ile bitireceğine başka şeyler yapıyor. Sanırım asm {} kümesini pervasızca ve pek sıklıkla kullanmalıyız. Çünkü biliyoruz ki o satırlar aynen koda dahil olacak...

Ama hala bazı sıkıntılarımız var. Örneğin referans olarak, işleve gelen parametreyi asm {} kümesi içinde kullanamıyorum. Şu kodun bilgimiz dahilinde çalışması gerekirdi ama çalışmıyor. Muhtemelen bir püf noktası var ama ne?

import std.stdio;

void main() {

 int bir = 1; int iki = 2;

 void swap(ref int lhs, ref int rhs) {
   asm {
     mov EAX,lhs[EBP];
     mov EBX,rhs[EBP];
     mov lhs[EBP],EBX;
     mov rhs[EBP],EAX;
   }
 }
 swap(bir, iki);
 writefln("%d, %d", bir, iki);
}

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

July 31, 2013

Parametreler ref değilse derleniyor ama bunun bir hata olup olmadığını bilmiyorum.

Ali

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