Thread overview
Değişken türleri performansa etkili mi?
Oct 06, 2012
Salih Dinçer
Oct 06, 2012
Salih Dinçer
Oct 06, 2012
mert
Oct 06, 2012
Salih Dinçer
Oct 07, 2012
mert
October 06, 2012

Merhaba,

Hemen cevaplayayım sanırım değil...:)

Aslında bu sonuç göreli de olabilir. Çünkü küçük de olsa bir fark var; bunu, biraz ara verip benim için sürpriz olan duruma (neredeyse eşit sonuçlara) sebep olan hatayı bulduğumda gördüm. Meğer ulong'larda bit işlem kullanıyorsanız (koddaki maskeleme bölümünde yer alan cast(T)'ye dikkat) tür dönüşümleri yapmak gerekiyormuş.

Aşağıdaki kod, boolean verilerinin her biri, gerçekten de 1 bit yer tutan bir yığıta (stack) sahip. Bu yığıtı her seferinde aynı 1/0'lar ile yarı rasgele bir biçimde (abur cuburla!) dolduruyorum. Dilersek de kurulum sırasında veri türünü değiştirebiliyorsunuz. Eğer Linux kullanıyorsanız, time ./universalTest şeklinde çalıştırdığınızda göreceksiniz ki; işlemci hızına göre değişen ama 30 sn.'yi geçmeyen önemsiz farklar var!

Buna rağmen bu sonuç hala benim için bir sürpriz... 8-(

/*
universalTest.d (06.10.2012)
*/
class Stack(T) {
   private int konum;
   private T[] stack;

   public:
       immutable type_length = (T.sizeof * 8);

   this (size_t size) {
       size_t taşmaVar_mı = size % type_length ? 1 : 0;
       stack = new T[(size / type_length) + taşmaVar_mı];
   }

   void push(bool veri) @property {
       immutable index = konum / type_length;
       immutable xMask = konum % type_length;

       if(veri) stack[index] |= cast(T)1 << xMask;
       konum++;
   }

   bool bitTest(size_t bit) {
       T xCell = stack[bit / type_length];
       T xMask = cast(T)1 << bit % type_length;/*
                      ^----bu çok önemli çünkü
                      ulong'da sıkıntı yapıyor! */
       return (xCell & xMask) != 0;
   }

   string toString() {
       string sonuç = "[";
       size_t n;
       foreach(i; 0..(type_length * stack.length)) {
           sonuç ~= bitTest(i) ? "1" : "0";
       }
       return sonuç ~ "]";
   }
}

bool abur_cuburlaDoldur(size_t n) {
 union u { uint i; float f; }

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

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

import std.stdio;

void main() {
 immutable xAdet = uint.max;
 auto test = new Stack!ubyte(xAdet); // ushort||uint||ulong
      //test.writeln;
 with(test) {
   writefln("%d x (%d bits integer)\n%d [1/0] booleans:\n",
                         stack.length, type_length, xAdet);
   foreach(i; 0..xAdet) {
     push(abur_cuburlaDoldur(i));/*
     push(cast(bool)uniform(0, 2));//*/
   }
   //toString.writeln;
 }
}

Dip Not: Eğer sözde rasgele değerler ile yığıtı doldurmak isterseniz 1.push() satırını kapatarak altındakini açın. Ancak bu sefer algoritmanın karışıklığından dolayı test süreleri en az 2-3 kat artıyor. Zaten bize rasgelelik gerekmiyor. Hatta her iki testte aynı değerleri üreten bir işlevin olması daha iyi ölçülebilen test sonuçları elde etmemizi sağlıyor.

Başarılar...

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

October 06, 2012

Bir dizi hata yapmışım. Örneğin toString() işlevi, şart olmasa da override ile tanımlamak gerekiyordu. Ayrıca unutkanlık olsa gerek n diye bir değişken kullanılmıyordu, kaldırdım. İlginçtir DMD override konusunda beni uyarırken kullanılmayan değişkenlere sesini çıkarmıyor.

En önemli hata ise baştaki konum değişkeni int olmamalıydı!

class Stack(T) {
   private size_t konum;
   :    :    :

Çünkü test adedi uint.max olduğuna göre burada bir taşma meydana geliyor. Tabi her iki test sonucunun (ubyte ile ulong veri türleri) aynı çıkmasının nedeni olabilir gibi görünüyor. Ancak değil; eğer başka hata yapmadıysam...:D

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

October 06, 2012

Alıntı:

>

İşlemler byte türü üzerinde bile olsa int türünde gerçekleştirilir. Şurada "int terfileri" ve "Aritmetik dönüşümler" başlıkları bana her zaman için şaşırtıcı gelir:

Alıntı:

>
> void birİşlem(int sayı)
> {
>     // ...
> }
>
> void main()
> {
>     byte küçükDeğer = 7;
>     birİşlem(küçükDeğer);    // otomatik tür dönüşümü
> }
> ```

>
> Orada da önce küçükDeğer'e eşit geçici bir int oluşturulur, ve birİşlem o geçici int değeri ile çağrılır.
>
>
Yine ilgili bölümden;

Alıntı:
>
> Bu terfilerin nedeni mikro işlemcinin doğal türünün int olmasıdır.
>
Bir kez daha gözden geçirmek iyi geldi bana. Şöyle ki; Yazdığım programda ubyte ve byte türlerini seçmeye çalışıyordum. Hesaplamalar int türünde yapılacağından çok farketmeyecek gibime geliyor ubyte veya int olması.
Doğru muyum?

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

Alıntı (acehreli):

>

Herhalde temel türlerden bahsediyorsun ve hatta yalnızca tamsayı türlerinden... Çünkü kesirli sayı türleri en azından bazı işlemlerde daha yavaş olabilir. Ayrıca kendi yazdığımız türler çok büyük olabilirler ve örneğin kopyalama işlemleri istediğimiz kadar yavaş olabilir.

Buradaki amaç bütün türler için eşit bir ortam yaratmak. Elbette tamsayı (integer) olmayanları test dışında bıraktım. Kurduğum Union'dan da anlaşılacağı üzere, bunların arkaplandaki bitsel karşılıkları farklıdır.

Alıntı (acehreli):

>

Bu deneyin amacını biraz daha açıklayabilir misin. Burada amaç byte bile kullanılabilen durumda long kullanılmasının etkilerini görmek mi? Ve anlaşılan o verilerin bir diziye yerleşecekleri bir uygulama ile ilgileniyoruz. Çünkü eğer işlem hızı ile ilgileniyorsak o türü bir çok işlemde kullanabilir ve ölçebilirdik de.
Belki deneyin artık yoğunlaşılması gereken tek kısmı kalıyor ki "işlemci içindeki işlemleri". Buradaki amaç ise "işlemcinin belleğe erişimi" test edildi. O yüzden 1 ve 0'lar kullanıldı çünkü en temel öğe ve ortak nokta...

Alıntı (acehreli):

>

Ben özellikle bit Stack'inin konuyla ilgisini kuramıyorum. Eğer çok ilgili değilse, benim gibi insanların kafasını karıştırabiliyor. Yazdıklarını bir kaç kere okudum ve o konuya takıldım kaldım. Acaba ne ilgisi olabilir? Geçende türlerin büyüklüklerinin işlemcinin ara belleğine sığma konusunda etkili olduklarını konuşmuştuk. O etkiyi mi ortadan kaldırıyorsun?
Tam olarak ilgisi "universal" olması için. Ayrıca aynı yavaşlık sorununu, asal sayıları bulurken (Eratosten Kalburu Algoritması (http://ddili.org/forum/thread/)), bool düzeyinde ve de sadece tek olanları (böylece 1 byte ile 16 sayı ifade ediliyor!) aynı şekilde (bit işlemler) kaydederken görmüştüm. Gerçi o zamanlar C kullanıyordum ama bir benzerini dinamik diziye yerleştirilen ve her seferinde büyüklük karşılaştırılması yapılarak sıralanan dizi&bağlı liste testimizde (http://ddili.org/forum/thread/724)

Bu durumda türler arasındaki yavaşlığın tek sebebi kalıyor; o da sıralanırken bellekte tüm verinin ötelenmesi. Bu da doğal bir şey çünkü ötelenen verinin (hücrenin) yapısı büyükdükçe performans düşer. İşte biz dizi&bağlı liste testimizde yaşadığımız ek yavaşlığın sebebi sadece ve sadece bundan kaynaklanıyor olmalı. Her ne kadar türle ilgili olsa da universal test türün doğrudan ilgili olmadığını bize gösterdi...:)

Alıntı (mert):

>

Bir kez daha gözden geçirmek iyi geldi bana. Şöyle ki; Yazdığım programda ubyte ve byte türlerini seçmeye çalışıyordum. Hesaplamalar int türünde yapılacağından çok farketmeyecek gibime geliyor ubyte veya int olması.
Doğru muyum?
Mümkün olduğunca ubyte seçerseniz daha iyi olacak gibime geliyor. Tabi negatif sayılarla da ilgileniyorsanız başka. Ayrıca alternatifi char da seçilebilir ama bu sefer writefln() ile ekrana bunun değerini yazmaya kalkarsanız ve tür dönüşümü yapmazsanız sayısal değerini değil ASCII'deki karşılığını görürsünüz.

Aslında sizin verdiğiniz örnekte, işlev parametresinde int kullanmazsanız bir kopyası dışında tür dönüşümü yapılmaz. Asıl dikkat edilmesi gereken sabitler! Çünkü sabit sayılarda (örn. yukarıda yazdığım yazılımda bu 1 idi o yüzden cast(T)1 yaptım!) varsayılan tür int olur; tabi yanında U ve L harfilerini kullanmaz veya varsayılan türü taşırmazsanız...

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

October 06, 2012

Herhalde temel türlerden bahsediyorsun ve hatta yalnızca tamsayı türlerinden... Çünkü kesirli sayı türleri en azından bazı işlemlerde daha yavaş olabilir. Ayrıca kendi yazdığımız türler çok büyük olabilirler ve örneğin kopyalama işlemleri istediğimiz kadar yavaş olabilir.

Bu deneyin amacını biraz daha açıklayabilir misin. Burada amaç byte bile kullanılabilen durumda long kullanılmasının etkilerini görmek mi? Ve anlaşılan o verilerin bir diziye yerleşecekleri bir uygulama ile ilgileniyoruz. Çünkü eğer işlem hızı ile ilgileniyorsak o türü bir çok işlemde kullanabilir ve ölçebilirdik de.

İşlemler byte türü üzerinde bile olsa int türünde gerçekleştirilir. Şurada "int terfileri" ve "Aritmetik dönüşümler" başlıkları bana her zaman için şaşırtıcı gelir:

http://ddili.org/ders/d/tur_donusumleri.html

Ben özellikle bit Stack'inin konuyla ilgisini kuramıyorum. Eğer çok ilgili değilse, benim gibi insanların kafasını karıştırabiliyor. Yazdıklarını bir kaç kere okudum ve o konuya takıldım kaldım. Acaba ne ilgisi olabilir? Geçende türlerin büyüklüklerinin işlemcinin ara belleğine sığma konusunda etkili olduklarını konuşmuştuk. O etkiyi mi ortadan kaldırıyorsun?

Ali

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

October 07, 2012

Mert, verinin boyutu da programın hızını etkiliyor. Ne kadar küçükse işlemcinin ara belleğine sığma şansı o kadar büyük. O yüzden byte veya ubyte yetiyorsa ve büyük diziler kullanacaksan onları seçmen önerilir.

char türünü ise yalnızca UTF-8 kodu amacıyla kullanmalıyız. Salih'in de hatırlattığı gibi, onun değerlerinin Unicode ile ilgileri var. Kütüphaneler bunu varsayabiliyorlar.

C ve C++'ta byte ve ubyte bulunmadığı için char ve unsigned char kullanılırdı. D'de byte ve ubyte daha uygun.

Ali

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

October 07, 2012

Anladım.
Teşekkürlerimle:-)

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