Linux kullandığım süreçlerde sıkı bir kde kullanıcısı olmama rağmen diskden okuma, geç yükleme gibi yavaşlıklarına dikkat etmeden geçemiyordum. “KDE’nin standart kum saati animasyonunu değiştireyim, daha güzel bir animasyon yapayım” diyerek yola çıktığımda karşılaştığım kod, kde’nin açılıştaki yavaşlığını göstermek için yeterli oldu.KDE’nin svn den gerekli kod bloğunu buldum.// setup animation framesfor (int i = 1; i < 11; i++){frames.append(new QPixmap(locate("data", "kicker/pics/disk" + QString::number(i) + ".png")));}
Şimdi bunda ne hata var ve niye takıntı ettim? Biraz “Search in files” yapınca kdebase’de (sadece kdebase’de) 240 tane locate ile 130 byte’lık 300 byte boyutunda resim dosyalarının yüklü olduğunu gördüm. tüm KDE açılışı sırasında bu rakam daha da artacaktı. (en az 1000’lerde)Şimdi de neden bunu bu kadar sıkıntı yaptığımı anlatayım; iki c dosyası yazın. teki 30bytelik 100 tane dosya açıp kapasın, teki de bir dosya açıp 3000byte yüklesin. aradaki hız farkı inanılmaz olacaktır. Linux ortamında dosya açıp kapamak çok pahalıdır. Cidden çok pahalıdır ve bunu KDE gibi 10 senelik bir yapıda nasıl düzeltilmediği sorusu sorulabilir. KDE yavaş açılıyor diyoruz hatta çoğu kde developer’ı bunu GCC nin C++’ı yanlış derlediğine bağlar..(Microsoft’un patent konularından dolayı eklenemeyen optimizasyonları yüzünden). Aslında okadar uzaklara gitmeye gerek yok. Sorun gözümüzün önünde.
Sıra bunun yerine ne olması gerektiğinde. tek bir dosyada birleştirilip üzerine zip çekilmesi ve hafızada zipin açılması bile inanılmaz ölçüde performansı artıracaktır.3 Satır koddan çıkan hata oldukça ilginç. Bu KDE’yi kötü yapmıyor, KDE cidden güzel ama daha çok uzun yolları olduğu da bir gerçek. Ama C++ olmasının getirisi olarak yapılan herşeyin başka yerde de kullanılabiliyor olması ve bir takım programların ciddi emek verilerek yazılmış olması bizi, KDE iyi demeye itiyor. ama harddiskime yazık ediyor o da ayrı bir konu.Tabii animation in frame sayısının static olarak koda eklenmiş olmasının ne derece doğru olduğunu tartışmıyorum bile. C++’a yatkınlığı olan insanlar hatayı anlayacaktır.

Bu konu sadece C++ ya da C ye özgü değildir. PHP, Java, Python ya da bash’a kadar çoğu programlama dilinde eğer performans istiyorsanız algoritmanızı geliştirmeniz gerekmektedir. Filesystem’e küçük dosyalar ile yük bindirmek doğru bir yöntem değildir.

Gelelim küçük bir çok dosya ile büyük tek dosyanın kullanım hızlarını karşılaştırmaya.. test programı gcc -O0 ile derlenmiştir ve ia32 için yazılmıştır. ia64 için değişime ihtiyacı vardır…Kerneldeki IO yoğunluğu etki etse de genel olarak sonuç değişmeyecektir.Test, küçük ve çok dosyalarda bildiğim kadarıyla en iyi çalışan reiserfs file system’de test edilmiştir.Yazma: 9000 bytelik tek dosya time2: 342715169163392 time1: 342715167851856 diff: 1311536Yazma: 300 * 30 bytelik dosya time2: 342715391811664 time1: 342715169883904 diff: 221927760Okuma: 9000 bytelik tek dosya time2: 342715392682352 time1: 342715391901096 diff: 781256Okuma: 300 * 30 bytelik dosya time2: 342715415133008 time1: 342715392717272 diff: 22415736
Sayıların ne anlama geldiğini biraz daha net açıklarsam;221927760 / 1311536 = 169.212099401 Yani yazmada, birleştirerek yazma 169 kat şu andaki yapıya göre daha hızlıdır. (yazma yapılmadığını düşünelim hadi.)22415736 / 781256 = 28.691921726 Yani Okumada, birlestirerek okuma 28 kat şu andaki yapıya göre daha hızlı.Sanırım bu yavaşlığın sebebini anlatmaktadır.Test programını kendisi çalıştırıp denemek isteyen arkadaşlar için programı derlerken;

gcc -O0 createfiles.c -o createfiles && mkdir data

vermeniz yeterli olacaktır.# include # include # include char *c;FILE *filepointer;int buyukdosyaolustur(){int i, rc;char buf[50];/* Esit bir karsilastirma olmasi icin snprintf */for (i = 1; i < 301; i++)snprintf(buf, sizeof(buf), "data/test_small%d.dat", i);filepointer = fopen("data/test_big.dat", "w+");rc = fwrite(c, 9000, 1, filepointer);fclose(filepointer);return 0;}int kucukdosyalariolustur(){int i, rc;char buf[50];for (i=1; i< 301; i++){snprintf(buf, sizeof(buf), "data/test_small%d.dat", i);filepointer = fopen(buf, "w+");rc = fwrite(c, 30, 1, filepointer);fclose(filepointer);}return 0;}int buyukdosyadanoku(){int i, rc;char buf[50];/* Esit bir karsilastirma olmasi icin snprintf */for (i = 1; i < 301; i++)snprintf(buf, sizeof(buf), "data/test_small%d.dat", i);filepointer = fopen("data/test_big.dat", "r+");fread(c, sizeof(char), 9000, filepointer);fclose(filepointer);return 0;}int kucukdosyalardanoku(){int i, rc;char buf[50];for (i=1; i<301; i++){snprintf(buf, sizeof(buf), "data/test_small%d.dat", i);filepointer = fopen(buf, "r+");fread(c, sizeof(char), 30, filepointer);fclose(filepointer);}return 0;}unsigned long long int nanotime_ia32(void){unsigned long long int val;__asm__ __volatile__("rdtsc" : "=A" (val) : );return(val);}int main(int argc, char *argv[]){unsigned long long int time1, time2;/* data/test_big.dat 9000bytelik dosya olusturulmasi */c = malloc(9001);if (!c) return 1;memset(c, 64, 9000);c[9000] = " 0";time1 = nanotime_ia32();buyukdosyaolustur();time2 = nanotime_ia32();free(c);printf("Yazma: 9000 bytelik tek dosya time2: %lld time1: %lld diff: %lld rn" , time2 , time1, time2 - time1);/* 300 * 30 byte lik dosya olusturulmasi */c = malloc(31);if (!c) return 1;memset(c, 64, 30);c[30] = ' 0';time1 = nanotime_ia32();kucukdosyalariolustur();time2 = nanotime_ia32();free(c);printf("Yazma: 300 * 30 bytelik dosya time2: %lld time1: %lld diff: %lld rn", time2, time1, time2- time1);/* 9000 bytelik tek dosyadan okuma */c = malloc(9001);if (!c) return 1;memset(c, 0, 9000);c[9000] = ' 0';time1 = nanotime_ia32();buyukdosyadanoku();time2 = nanotime_ia32();free(c);printf("Okuma: 9000 bytelik tek dosya time2: %lld time1: %lld diff: %lld rn", time2, time1, time2 - time1);/* 300 * 30 bytelik dosyalardan okuma */c = malloc(31);if (!c) return 1;memset(c, 0, 30);c[30] = ' 0';time1 = nanotime_ia32();kucukdosyalardanoku();time2 = nanotime_ia32();free(c);printf("Okuma: 300 * 30 bytelik dosya time2: %lld time1: %lld diff: %lld rn", time2, time1, time2 - time1);return 0;}