August 01, 2013

Zekeriya ile FB'de biraz konuştuk, güzel ve faydalı oldu...

Sanırım, sınıfı geliştirmek için malloc() tarafında işaretçi değil de bir dilim gönderilmeli. Yoksa işler karışabilir ve zaten hali hazırda D'nin böyle bir yeteneği varken kullanmamak çok ama çok ayıp olur...:)

Aslında konuşmamız Buddy Memory Allocation (http://en.wikipedia.org/wiki/Buddy_memory_allocation) çerçevesinde yaptık ama bizim daha akıllı algoritmalar geliştirebileceğimizi düşünüyorum. Tabii bellek birimlerinin bu kadar ucuz ve hızlı olduğu bir devirde bütün bunlarla uğraşmak ne kadar faydalı olur onu bilemiyorum. Yine de güzel bir deneysel çalışma olacaktır. En azından devingen dizilerin genişleme tavırları, capacity kavramını ve/veya tüm verinin taşınmasını daha iyi anlamış olacağız...

Hatta bir SmartDynamicArray sınıfına doğru gittiğimizi görmekteyim! Bu konuda bir kaç not aldım:

1. davranış: 'freeLocated''dan sonra boş yer var mı? Varsa hemen ver, yoksa...
2. davranış: 'memory.capacity''de istenen alandan büyük mü? Büyükse genişlet ve ver, yoksa...
3. davranış: realloc() yapılmış tekrar kullanılabilir alan var mı? Varsa hemen ver, yoksa yapacak bir şey kalmamıştır, tüm dizideki verilerin taşınma ihtimaline rağmen diziyi genişlet.

(İŞTE OLAY BUNDAN SONRA KOPUYOR...)

4. davranış: Tahsis edilebilir kullanılmayan alanlardan işime yarayan en küçüğün bana ver? Veremiyorsan...
5. davranış: Tekrar kullanılabilir en büyük ve komşu (<-- bu çok önemli) ikisini topla ve istediğim boyuta ulaşıyorsa ikisi arasındaki kalan boşluktan itibaren diğerini taşı (align)...

İşte bu son aşama öyle akıllıca tasarlanmak zorunda ki en büyük boş alanlardan başlayacak, üstelik bunlar komşu olacak ve hatta arasında kalan veri de en küçük olacak. İşte bunu bulmak hiç kolay değil ve başarısız olduğunda bir sonraki adayları değerlendirmeli. Zaten bulamazsa 3. davranışın ikinci bölümüne geri dönmeli...

Hepsinden önemlisi, bu yapılan işlemlerin (3. davranışta gerçekleşmesi muhtemel) tüm dizinin belleğin başka bölümüne taşınma ihtimalinden daha yavaş olması durumunda boş bellek bölgelerini değerlendirmeyi kesmeli ve daha çok vakit kaybetmeden kaçınılmaz sona doğru diziyi genişletmeli...:)

Sevgiler, saygılar...

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

August 01, 2013

Ali hocam, bu son söylediğin çok akıllıca...

Yani 'free()' yapılırken, sadece bölüm(alan) listesindeki kullanıldı bayrağına "false" işareti koyarım diye düşünüyordum. Böylece asıl yoğunlaşılması gereken 'malloc()' görünüyordu ve belki 'realloc()' da benzeri olabilirdi. Ama şimdi, hazır bellek geri verilirken pekala bir kaç işlemi de yapabiliriz. Belki bu bir "ön hazırlık" olabilir.

Aslında ben olaya, biraz daha farklı (invert) bakıyorum, örnekten gidersek:

'A[64]:1 - B[1024]:0 - C[256]:1 - D[1024]:1'

Yukarıda, önceki örneğe bir bölüm daha eklenmiş 4'lü bir örnek görüyoruz. Kısaca 1011 bayraklarına sahip bölümlerden sonuncusu (D) bir süre sonra geri veriliyor ve 1010 olduğunu farz edelim. Bu durumda yaklaşık 2K'lık verinin (+256 byte) tam ortasında bir veri (C) yer almakta ve biz bunun ne zaman geri verileceğini bilmiyoruz. Peki biz bunu hemen şu hale getirebilseydik mantıklı bir hareket yapmış olur muyduk?

'A[64]:1 - B[256]:1 - C[2048]:0'

Yani önceki halindeki C, B'nin başına kopyalandı ve geride kalan C ve D birleştirildi. Gerçi teorik olarak birleşmedi tamamı boş alan varsayıldı; orada C'nin bir kopyası hala dursa bile...:)

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

August 01, 2013

Alıntı (Salih Dinçer):

>

D'nin böyle bir yeteneği varken kullanmamak çok ama çok ayıp olur...:)

Daha iyisi yapılamıyorsa enayilik de olur. ;)

Alıntı:

>

5. davranış: Tekrar kullanılabilir en büyük ve komşu (<-- bu çok önemli) ikisini topla

Toplama işi alanlar daha önce geri verilirken yapılabilir mi acaba? Dolu, boş, dolu diye yan yana üç alana bakalım:

'[A:dolu:64][B:boş:1024][C:dolu:256]'

C geri verildiğinde kendisinden önceki alana bakılır ve boşsa ona eklenir:

'[A:dolu:64][B:boş:1280]'

Kendisinden önceki alan kavramını destekleyebilmek için alan hesabının çift bağlı bir listeyle tutulması gerekebilir.

Ali

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

August 01, 2013

Evet, klasik malloc() işlevi bize istediğimiz alan genişliğindeki bir bellek bölgesinin başını gösteren bir adet işaretçi vermektedir. Eğer biz veriyi başka yere kopyalarsak hala eski yerine ulaşılmak istenecektir...:)

Ancak biz D kullanacağımız için dilim döndüreceğiz. Bu durumda dilimin adresi null olana (GC'ye teslim edilene) kadar değişmeyeceğine göre o bellek bölgesini gösteren dilim, pekala daha sonra başka bir bellek bölgesini gösterebilir. Bunun mümkün olduğunu gösteren örnekler hazırlamaya başladım. Şimdilik lütfen aşağıdaki ile yetinin:

import std.stdio;

void main() {
 char[] memory = "BuBirVeriGrubu".dup;
                //0123456789

 alias char[][char*] AA;

 AA cells = [ &memory[0]: memory[0..2],
              &memory[2]: memory[2..5],
              &memory[5]: memory[5..9],
              &memory[9]: memory[9..$]
            ];

 char* unused;
 foreach(cell; cells.keys) {
   cells[cell].writeln(" @:", cell);
   unused = cast(char*)cell;
 }

 cells[unused] = null;

 foreach(cell; cells.values) cell.writeln("<-");

} /***** ÇIKTISI *****

Bu @:F7693FF0
Bir @:F7693FF2
Veri @:F7693FF5
Grubu @:F7693FF9
Bu<-
Bir<-
Veri<-
<-

*/

Burada bir AA (associative array) kullanarak dilimin kendisini nesne (2 işaretçi) olarak tuttuğum gibi, baştaki işaretçiyi de sanki gereksimiş gibi "key" olarak tanımladım. İşaretçi key'in tek amacı komşunu bulmak ama henüz bunu örnekte göstermedim. Sadece bool yerine null atayarak bellek bölgesini gösteren dilimi GC'ye emanet edeceğimi gösterdim. Ayrıca null bizim için false demek olacak.

Sevgiler, saygılar...

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

August 01, 2013

Alıntı (Salih Dinçer):

>

Yani önceki halindeki C, B'nin başına kopyalandı

Onu yapamayız çünkü C'nin adresini daha önce sunmuştuk. Sunduğumuz kodun elindeki göstergeler o alanı göstermekteler.

Ali

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

August 01, 2013

Anladım.

Ama sanırım bir dmd hatası var. O program yalnızca 32 bit derlendiğinde çalışıyor. dmd'nin eşleme tablolarıyla ilgili hatalarından birisi olmalı. Döngü içinde 'cells[cell]' yapıldığı an "Range violation" hatası veriyor.

Ali

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

August 02, 2013

Hocam bence AA kullanmak oldukça performans kaybına neden olacaktır başka bir çözüm üretmek gerek.

Zekeriya

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

August 03, 2013

Katılıyorum, yoksa bağlı liste kullanacağız...

Ben sadece özü de bağlı liste olan hazır bir yapıyı "şıgırdanak" diye yazayım dedim. Yoksa şu sıralar fazla kod yazmaya vakit bulamıyorum. Bu vesileyle de sanırım 64 bit derlemede bir hata tespit ettik ama incelemedim. Belki benim bilgisayarda bu sorun olmuyordur bilemiyorum...

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

August 04, 2013

Sonunda, özlediğim kod yazmaya vakit bulabildim!

Bir çocuğun oyuncağını alması gibi sevinç doluyum...:)

Gerçi saç baş yoldurması muhtemel gözüküyor ama siz arkadaşlarımın desteği ile üstesinden geliriz diye düşünüyorum. Amacımız standart 'malloc()' işlevine alternatif olmak değil. Belki D dilimlerinin gücünü görmek.

Bu konuda bütün gün düşündüm ve aklıma şöyle bir yapı kurmak geldi:

struct Düğüm {
 char[] dilim;
 Düğüm * önceki;
 bool boşta_Mı;
}

Çok fazla karmaşıklığa girmek istemiyorum! Kanaatimce her şey yukarıdaki gibi basit olabilir. Bir kaç deneme yaptıktan sonra ayrıntılarına ve çalışan kodlara değineceğim. Kısaca olay tıpkı bir Matruşka gibi olacak; küçükten büyüğe gidersek:

  • Hücre (dizinin tek birimlik bölümü)
  • Dilim (dizin bir bölümü)
  • Düğüm (birbiriyle komşu bellek bölümleri)
  • Dizin (nesneleri hayatta tutan, ulaşılmasını kolaylaştıran)
  • Sınıf (önceki sayfadaki MEM sınıfımız)

Değerli önerilerinizi dört gözle bekleyeceğim. Şimdilik kafamda bir çok şeyi kurdum. Bir tek bağlı listede gezinme ve doğru hücreyi bulma kafamı karıştırıyor. BinarySearch kullanmayı düşünüyorum. Çünkü dilimlerin gösterdiği bellek bölgeleri sıralı. O yüzden hızlı bir erişim mümkün görünüyor. Yine de bu haliyle bile epey dolambaçlı...:)

Sevgiler, saygılar...

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

August 05, 2013

Sanırım tamam...:)

Aslında bizim burada yaptığımız, tek bir işaretçi gönderen geleneksel 'malloc()' yerine bir dilim taşıyıcılığında iki işaretçi birden göndermek. Böylece ayrılan bellek bölgesi daha güvenli bir şekilde kullanılabiliyor. Ancak şu an yolun başındayız. Çünkü 'free()' yapmak sadece boolean değeri true yapmak manasına geliyor:

import std.conv, std.string, std.stdio;

struct Düğüm {
 char[] dilim;
 Düğüm * önceki;
 bool boşta_Mı; // false (boşta değil)
}

void birebirAktar(T)(T[] hedef, T[] aktar) {
 size_t SINIR = hedef.length <= aktar.length ?
                hedef.length - 1 : // hedef büyükse =>
                aktar.length - 1;
 do hedef[SINIR] = aktar[SINIR]; while(SINIR--);
}

void main() {
 char[] test = "BuBirVeriGrubu".dup;
              //0123456789
 with(new MEM(16)) {
   foreach(boyut; 2..6) {
     malloc(boyut); //<-- aslında bir dilim de dönüyor!
   }
   /* sırasıyla 2, 3, 4, 5 karakterlik bellek bölümleri
    * bir dilim olarak oluşturuluyor ama başka bir dilim
    * vasıtasıyla ve açık bir şekilde veri yüklenyior...
    */
   (*dizin[1]).dilim.birebirAktar(test[0..2]); // length = 2 "Bu"
   (*dizin[2]).dilim.birebirAktar(test[2..5]); // length = 3 "Bir"
   (*dizin[3]).dilim.birebirAktar(test[5..9]); // length = 4 "Veri"
   (*dizin[4]).dilim.birebirAktar(test[9..$]); // length = 5 "Grubu"

   /* dilimlerin test dizgesini değil de ayrılan
    * bellek bölgesini işaret ettiğinin bir kanıtı:
    */
   memory[0] = 'b'; memory[2] = 'b';

   toString.writeln;
   dizin.writeln;

   // bu bir free() için arama denemesidir:
   auto dilimHangiDüğümde = binarySearch((*dizin[4]).dilim);
      (*dilimHangiDüğümde).writeln("<--şu an boşta değil!");
      (*dilimHangiDüğümde).boşta_Mı = true;
      (*dilimHangiDüğümde).writeln("<--ve şimdi sildik...");
 }
}

'MEM()' sınıfımızda ise fazla bir değişiklik yapmadım; eklenen satırların yanına açıklama yerleştirdim. Sadece dizin isminde bir dizi TDPL kitabındaki binarySearch algoritmasını eklemiş olduk diyebiliriz.. Tabiyetiyle 'malloc()' işlevimiz biraz yenilendi:

Alıntı:

>
> class MEM {
>   private:
>     char[] memory;
>     size_t freeLocated, memSize;
>
>   public:
>     Düğüm*[] dizin;                  // her yeni düğüm burada...
>     immutable byteSize = 8;
>
>   this(size_t minSize) {
>     size_t isOverload = minSize % byteSize;
>     memory = new char[](minSize - isOverload);
>     memSize = memory.length;
>     dizin ~= null;                   // kök için olmak zorunda !
>   }
>
>   char[] malloc(size_t size) @property {
>     scope(exit) freeLocated += size;
>     auto konum = freeLocated + size;
>
>     if(memSize  < konum) {
>       memory.length += memSize * 2;
>       memSize = memory.length;
>     }
>     auto dilim = memory[freeLocated..konum];
>     dizin ~= new Düğüm(dilim, dizin[$ - 1]);
>     /* döndürülen her dilim, bir düğüm taşıyıcılığında
>      * dizin'e ekleniyor ve hali hazırda önceki düğüm
>      * yine bu dizin sayesinde bağlanıyor...
>      */
>     return dilim;
>   }
>
>   Düğüm * binarySearch(char[] slice) {
>     auto input = dizin;
>     while(true) {
>       size_t i = input.length / 2;
>       char[] mid = (*input[i]).dilim;
>       if(&mid[0] > &slice[0]) {
>         input = input[0..i];
>       }
>       else if (&mid[0] < &slice[0]) {
>          input = input[i + 1..$];
>       }
>       else return input[i];
>     }
>     return null;
>   }
>
>   override string toString() const {
>     import std.range : repeat;
>     string memImage  = "       DECIMAL MEMORY DUMP        ASCII  \n";
>            memImage ~= format("%s\n", repeat('-', memImage.length)) ;
>
>     for(int i; i < memory.length; i += byteSize) {
>       auto row = memory[i..i + byteSize];
>       foreach(ubyte address; row) {
>         if(address < 10) memImage ~= "   ";
>         else if(address < 100) memImage ~= "  ";
>         else if(address < 256) memImage ~= " ";
>         memImage ~= to!string(address);
>       }
>       memImage ~= " " ~ row ~ "\n";
>     }
>     return memImage ~ format("%s>Total %s bytes<\n", repeat(' ', 10), memory.length);
>   }
> }
> ```

>
Şimdi sırada, boşa düşen bellek bölgesi yanında (üst veya alt komşusunda), benzer bir boş alan olduğunda, birinin silmesi ve dilimi silinen kadar uzatması gerekiyor. Sorun şu ki ana caddeye (dizin) çıkamıyorum ve sokaklar (Düğüm) içinde sadece 1 yönde gezilebiliyor. Beki bağların sayısını arttırmalıyım; önceki ve sonraki diye...

Kodun çıktısı ise şöyle:

'       DECIMAL MEMORY DUMP        ASCII
------------------------------------------
 98 117  98 105 114  86 101 114 bubirVer
105  71 114 117  98 117 255 255 iGrubu��
         >Total 16 bytes<

[null, 7FC95FF12FC0, 7FC95FF12F80, 7FC95FF12F60, 7FC95FF12F40]
Düğüm("Grubu", 7FC95FF12F60, false)<--şu an boşta değil!
Düğüm("Grubu", 7FC95FF12F60, true)<--ve şimdi sildik...
'
Başarılar...

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