Pascal İle Optimizasyon

CorsaiR

Emektar
27 Ara 2005
1,228
18
Çekirdekten
Pascal İle Optimizasyon Bu yazıda Pascal ile Intel'in x86 işlemcileri için klasik program geliştirme esas alınmış olsa da anlatılan prensipler farklı birçok geliştirme ortamı için de geçerlidir.
Giriş
1- İŞLEMCIDEN BAĞIMSIZ OPTIMIZASYONLAR
1.1- Hafıza aktarımlarını mümkün olduğunca büyük bloklar halinde yapmak doğru olur
1.2- String işlemleri için standart prosedürlerin yerine daha hızlı alternatifler bulunabilir
1.3- Genel değişkenler (global var.) ve işaretçi kullanımları (pointer) en aza indirilmelidir
1.4- Giriş-çıkış ve grafik ile ilgili işlemlerde standart fonksiyonların kullanımı azaltılmalıdır
1.5- Program doğru çalışıyorsa «Range Checking» kaldırılmalıdır
1.6- Karşılaştırma ve koşullar en aza indirilmelidir
1.7- Kullanılacak algoritmalar doğru seçilmelidir

2- İŞLEMCIYE ÖZEL OPTIMIZASYONLAR
2.1- 486 cephesinde durum
2.2- Pentium ve Pentium MMX
2.3- Pentium Pro ve Pentium II

PASCAL'DA ASSEMBLY
Inline direktifi
Harici Prosedürler
Assembler direktifi ve asm...end blokları

Pascal ile Optimizasyon:

Giriş:

Pascal'da kaynak kodu optimizasyonu, günümüzdeki bilgisayarlarların hızlı olmasından ötürü Pascal ile program geliştiren kişilerin genelde gözönüne almadıkları ama programlarının yavaş bilgisayarlarda bile yeterli hızda çalışmasını isteyenlerin (oyun ve veritabanı programcıları vb.) yapmaları zorunlu olan birşeydir.
Optimizasyon işlemi genellikle kaynak kodun okunurluğunu azaltan tekniklerle kod yazmayı, hatta assembly ile yazılmış harici nesnelerin (.obj dosyaları) programa dahil edilmelerini gerektirebilir. Bu bakımdan, programın geliştirme aşamasında hemen optimizasyon yapılması zordur. Turbo Profiler® gibi bir programla yavaşlamaya sebep olan bölümlerin belirlenip iyileştirilmesi, programın geliştirilmesinde modüler yapının iyi kurulması gerekir.

Optimizasyon temelde iki türlüdür:
1- İşlemciden bağımsız optimizasyonlar
2- İşlemciye özel optimizasyonlar

1- İşlemciden bağımsız optimizasyonlar :
Doğrudan Pascal kodu üzerinde yapılabilecek RAM hafıza disk erişimi ile ilgili okuma yazma işlemlerinin iyileştirilmesi, ayrıca, değişik çevre birimleriyle daha etkili iletişim yollarının bulunup uygulanmasıdır.

Avantajları:
? Programın okunurluğundan fazla taviz verilmeden iyileştirme yapılmış olur.
? Programın değişik ortam ve işlemcilerde kullanılması mümkündür.

Dezavantajları:
? Çok yüksek hız artışları sağlanamayabilir.
? Programın çalışma hızı kullanılan derleyiciye bağlıdır.

Pascal kodunun iyileştirilmesinde bazen standart kütüphanenin (turbo.tpl) sunduklarını reddetmek ve özel kütüphaneler (üniteler) kullanmak gerekir. Bu kütüphanelerde interruptlar (kesmeler) kullanmak gerektiğinde mutlaka interruptlar hakkında yeterince bilgi edinmek veya kütüphaneyi güvenilir bir yerden almak iyi olur. Ayrıca, Pascal'da assembly kullanımı ile ilgili bölümü, hem işlemci ile ilgili, hem de işlemciden bağımsız optimizasyonlar için gerektiğinden okumakta fayda vardır.
Bazı tavsiyeler:

1.1- Hafıza aktarımlarını mümkün olduğunca büyük bloklar halinde yapmak doğru olur.

Örnek:
EGA/VGA renkli metin ekranı $B800 segmentinde adreslenir. Bu segmentte her word ekrandaki bir karakterin kodunu ve niteliğini içerir.
Aşağıda, bu adrese doğrudan veri yazarak ekranı o anda geçerli yazı niteliğindeki belli bir karakterle (Zkar parametresi) dolduran aynı işi yapan iki procedure vardır. İkinci procedure, veri atamalarını word paketleri halinde yaparak birinciye göre iki kat daha hızlı çalışan kod üretilmesini sağlar.


info3.gif
Satir ve Sutun ekrandaki satır ve sütun sayılarını içeren global değişkenlerdir.

Bu örnekler test amaçlı olarak yazdığım bir örnek programdan alınmıştır.

1. Procedure:

Uses Crt;
...
Procedure Zemin(Zkar:Char);
(* Atamalar 8 bit (byte) yapılıyor.
Program parçası anlaşılır şekilde yazılmış.
Optimizasyon yok. *)
Var
Q:Word;
Begin
For Q:=Satir*Sutun downto 0 do
begin
Mem[$B800:Q*2 ]:=Byte(Zkar);
Mem[$B800:Q*2+1]:=TextAttr;
end;
end;
...


2. Procedure:

Uses Crt;
...
Procedure Zemin(Zkar:Char);
(* Atamalar 16 bit (word) yapılıyor.
Program parçasının anlaşılırlığı azalmış.
Kaynak kodu optimizasyonu var. *)
Var
Q,Cift:Word;
Begin
Cift:=Byte(Zkar)+(TextAttr Shl 8);
For Q:=Satir*Sutun downto 0 do
MemW[$B800:Q Shl 1]:=Cift;
end;


İkinci prosedürün kaynak kodu optimizasyonu için ardışık iki atama yerine her seferde bir atama yapılmış, sabit tamsayıyla çarpma işlemleri «shl» operatörüyle gerçekleştirilmiştir. Bu prosedür, 32-bit yazmaçlar ve atamalar kullanılarak daha da iyileştirilebilir.
Konuyla ilgili diğer önemli bir uyarı da Blockread ve Blockwrite ile ilgili. Bu prosedürler geniş arabellekle kullanılmalıdırlar. Arabellek boyutu 512 baytın katları olmalıdır. Örneğin 10.000 bayt arabellek yerine tam 10 kilobaytlık 10.240 bayt arabellek kullanılması performans açısından biraz daha iyidir. Ama en büyük performansı büyük arabellek verecektir.

1.2- String işlemleri için standart prosedürlerin yerine daha hızlı alternatifler bulunabilir
String tipi değişkenler, ilk Pascal derleyicilerinde karakter dizileri olarak tanımlanıyorlardı. Bir prosedürde parametre olarak kullanılmaları «stack» bölümüne içerikleriyle kopyalanmalarına, dolayısıyla zaman ve yer kaybına yolaçıyordu. Bu sorun çok önceleri String tipi değişkenleri işaretçi (pointer) gibi kullanmakla halledildi. Derleyiciler artık parametre olan String değişkenlerin sadece adresini stack bölümüne atıyorlar, gerektiğinde bu adresten kullanıyorlar.
Yine de String ile ilgili atama ve kopyalama işlemleri çok hızlı değildir. Programda String tipindeki değişkenlerin sıklıkla kullanıldıkları bölümler varsa (isim sıralama, kelime işlem vb.) bu bölümleri optimize etmek mümkündür.

Örneğin, S ve D string, N bayt tipinde değişkenler olmak üzere, S'in ilk N karakterini D'ye aktarmak için
D:=Copy(S,1,N);

yazmak yerine

Move(S[1],D[1],N);
D[0]:=Chr(N);

ikilisini yazmak çok daha iyi sonuç verir.

info1.gif
Move komutu string tipi işlemlerde kullanmak için çok idealdir.

1.3- Genel değişkenler (global var.) ve işaretçi kullanımları (pointer) en aza indirilmelidir
Yerel (local var.) değişkenlere erişim genel değişkenlere olduğundan daha hızlıdır. Sayaç vb. değişkenlerin genel değişken olarak tanımlanmaları şart değildir. Bunları prosedür ve fonksiyonlar içinde geçici yerel değişkenler olarak tanımlamak daha iyi sonuç verir.

1.4- Giriş-çıkış ve grafik ile ilgili işlemlerde standart fonksiyonların kullanımı azaltılmalıdır
Grafik kütüphanesi ve giriş-çıkış komutları, standartlara ve tüm kullanıcıların donanımına uyumlu olmaları amacı güdülerek yazıldıklarından oldukça yavaştırlar.
Daha zahmetli de olsa, ilgili kesmelerden yararlanılarak grafik için Vesa uyumlu modlara erişerek bankları veya LFB'ı kullanacak şekilde programlamak, giriş-çıkış içinse ilgili portları ve işletim sisteminin olanaklarını kullanmak yerinde olur.

1.5- Program doğru çalışıyorsa «Range Checking» kaldırılmalıdır
Range Checking seçeneği, değişkenlere geçerli oldukları aralığın dışında bir değer atanıp atanmadığını kontrol eden kodları programa ekler. Bu kodlar karşılaştırma kodları oldukları için performansı olumsuz etkilerler. Programın hata ayıklama dönemi bitip doğru çalıştığından emin olununca seçenek devreden çıkarılmalıdır.

Kaynak kodu optimizasyonunda bir diğer önemli konu derleyici için iyileştirmeye uygun kod yazmaktır. Yakın zamanda geliştirilen derleyicilerin çoğu optimizasyon yeteneklerine sahipler.

Unutulmaması gereken diğer bir konu da yapılan optimizasyonu test etmektir. Performansa fazla katkı sağlamayan optimizasyon kodun okunurluğunu ve taşınırlığını boşuna azaltmış olur.

1.6- Karşılaştırma ve koşullar en aza indirilmelidir
Karşılaştırma komutları, geniş kapsamlı bir programda sıkça rastlanan komutlardır. Ama işlemci için bu tür komutlar, düz bir yoldaki yol ayrımlarıdır; işlemcinin hangi yola sapacağına karar vermesi yavaşlamaya sebep olacaktır.
Günümüz işlemcilerinin karşılaştırma komutlarının sonucunu kestirmek ve böylece bu tür komutların hız kesmesini önlemek için kullandıkları dallanma tahmini yöntemleri, eğer yapılan tahmin yanlışsa boşa harcanan saat çevrimlerine yolaçar. Aşağıdaki iki yapı aynı işi yapmalarına karşın uygulamada, eğer mümkünse, ikincisi tercih edilmelidir. Birinci yapı bahsedilen mahsurlu duruma yolaçabilir.

1. IF (Koşul) THEN A_iSLEMi
ELSE B_iSLEMi;

2. B_iSLEMi;
IF (Koşul) THEN
begin
Geri_Al_B_iSLEMi;
A_iSLEMi;
end;

1.7- Kullanılacak algoritmalar doğru seçilmelidir
Bazı bilinen algoritmalarda aynı işi yapanlardan hangisinin daha hızlı çalıştığı malumdur. Örneğin Quicksort sıralama yöntemi, Bubble sort yönteminden çok daha hızlı çalışır. Programcı, kendi geliştirdiği algoritmanın daha etkin hale getirilmesinin mümkün olup olmadığını araştırmalı, mümkünse algoritmasını iyileştirmelidir.

2- İşlemciye özel optimizasyonlar :
İşlemcinin özelliklerinin ve varsa ilave komut setlerinin etkili bir şekilde kullanılmasıdır. Örnek olarak Pentium ve üstü işlemcilerin aynı anda iki bağımsız komutu işleme özelliğinin kullanılması için «pairing» yapma veya bir çoklu ortam (multimedia) uygulamasında MMX™ komut setininin avantajlarından faydalanmak verilebilir.

Avantajları:
? Mümkün olan en hızlı program kodu geliştirilebilir.
? Yeni teknolojilerden yararlanılabilir.

Dezavantajları:
? Bu tür optimizasyonları her Pascal derleyicisi yapmadığı için assembly ile programa dahil etmek gerekecektir.
? Fazladan çaba, zaman ve yeterli bilgi gerektirir. Programcı, işlemcinin özelliklerini ve çalışma prensiplerini bilmelidir.
? Program, yapılan işlemciye özel optimizasyonlar yüzünden her işlemcide çalışmayabilir. Bu durumda çalışma kütüphanelerinin bazı bölümlerinin normal ve optimize olarak iki biçiminin bulundurulması ve gerekenin çalıştırılması zorunludur. Örneğin, MMX için optimizasyonlar yapılmışsa programı Pentium™ ve Pentium Pro™ 'da çalıştırmak için optimize edilmemiş normal kütüphaneye ihtiyaç duyulacaktır. Ayrıca Intel, AMD, Cyrix ve diğer üreticilerin işlemci tasarımları değişik olduğundan ötürü her işlemcide aynı oranda iyileştirme yapılamayabilir.

Çoğunluğun kullandığı x86 temelli bilgisayarları gözönüne alacak olursak, tümü için geçerli bir optimizasyon tekniği yoktur. İşlemcilerin çalışma prensiplerine göre teknikler değişir. Ama bugünkü uygulamada, Pentium için optimize edilmiş bir program daha üst seviye işlemciler için de az veya çok optimize edilmiş sayılabilir.
İşlemcilerin işleyişini gözönüne alarak programları optimize etmek oldukça zahmetli bir iştir. Esasen bu derleyici yazanların ve low-level programcıların işidir. Burada temel bazı işlemci işleyiş ve Pascal'da assembly kullanım bilgileri verilecektir.

2.1- 486 cephesinde durum:
Intel'in x86 komut setinde ilk köklü değişikliği yapıp 32-bit yazmaçlar (register) ve komutlar eklediği işlemcisi 80386'dan sonra piyasaya sürdüğü, uzun süre piyasada kalan ve çeşitli çekirdek (CPU) hızlarında birçok değişik modelleri (SX, DX, DX2, DLC vs.) çıkan, zamanının başarılı bir işlemcisidir. Çoğu durumda bir saat çevriminde bir komut işleyecek şekilde tasarlanmıştır.

486 işlemciler 5 aşamada komut işlemektedirler.
1- Prefech : Komutların işlemci iki 16 baytlık arabelleğinden birine alınır.
2- Decode : Komut yolundan gelen komutların çözümlemesi yapılır.
3- Address Generation : Adres çözümlemesi yapılır.
4- Execution : Komutun çalıştırılması bu aşamada olur.
5- Writeback : Yazmaç içeriklerinin güncellendiği bölümdür.

2.2- Pentium ve Pentium MMX:
Pentium işlemciler, kendilerinden önceki nesillere göre komut işleme kapasitelerindeki büyük gelişme ile dikkat çektiler. Bu gelişme sayesinde birçok uygulamada aynı saat hızında Pentium işlemci 486 işlemciden en az iki kat daha hızlı komut işliyordu. Bu gelişmenin en önemli sebepleri:
- Dallanma tahmini (Branch prediction) : Dallanma (jump) komutlarında işlemcinin birtakım tahminler yapmak yoluyla dallanmanın yolaçtığı gecikmeleri azaltmasıdır.
- Çift pipeline : Komutların U ve V ile sembolize edilen iki pipeline (komut yolu) içinde eşzamanlı olarak işlenmesi sayesinde teorik olarak aynı anda iki komut işlenmesidir. Pratikte bunun gerçekleşebilmesi bazı şartların sağlanması gerekir.
- Yeni kayan nokta işlem ünitesi : Pentium, gerçel sayı işlemlerinin hızını belirgin bir şekilde arttıran yeni matematik işlemci tasarımıyla kendi dönemindeki x86'ların önemli bir yavaşlığı telafi etti.

Pentium MMX işlemci, klasik Pentium'a göre biraz daha iyi komut işler. Daha geniş L1 arabellek, daha iyi dallanma tahmini algoritması ve yeni komut seti eklentileri ona avantaj sağlar.

Pentium için optimizasyonda Pascal kodu içinden yapılabilecek en önemli etki, inline veya asm bloklarını çift pipeline mimarisinin kurallarına uyarak optimize etmektir. İşlemciye aynı anda iki komut işletebilmenin yolu mümkün olduğunca uygun komut çiftleri oluşturmaktır. Pentium'un pipeline'ını oluşturan yollar U ve V yolları olarak adlandırılır. U yolu tüm komutları işleyebilirken V yolu bazı sıkça kullanılan basit yapılı komutları işleyebilir. Bu yolların etkin kullanımı, komutların uygun sırayla işlemciye ulaştırılmasıyla olur.

Bazı eski karmaşık yapılı komutlar, komut çiftlemeyi mümkün kılacak şekilde eşder komutlara bölünebilirler.

Örneğin,
MOVZX EAX,BYTE PTR [...] = XOR EAX,EAX + MOV AL,BYTE PTR [...]

Temel kurallar şunlardır:

1- Her iki komut basit yapıda olmalıdır. Komutları, Pentium'un işleyişi bakımından 4'e ayırmak mümkündür:
UV (Hem U'da hem V'de çiftlenebilen),
PU (U'da çiftlenebilen),
PV (V'de çiftlenebilen,
NP (çiftlenemeyen)

UV : MOV, PUSH, POP yazmaç, LEA, NOP, INC, DEC, ADD, SUB, CMP, AND, OR, XOR,
A.L.U. yazmaç,... , A.L.U. adres,yazmaç/değer, NOP, TEST(kısmen)
PU : ADC, SBB, SHR, SAR, SHL, SAL yazmaç,değer , ROR, ROL, RCR, RCL yazmaç,1
PV : yakın CALL, JUMP, koşullu dallanma komutları.

Bunların dışındaki komutlar U yolunda işlenir ve çiftlenemezler.

2- İki komut arasında yazmaç bağlılığı bulunmamalıdır. Yani bir komut kendinden öncekinin sonucunu beklemek zorunda olmamalıdır. Örnekler:

MOV BX,CX ; ADD AX,BX ' ikinci komut birincide BX'in alacağı değere bağlı, çiftlenemez!
MOV BX,CX ; MOV CX,AX ' ikinci komut birinciyi beklemeden işlenebilir.
CMP AX,5 ; JA _etiket ' karşılaştırma ve dallanma komutları bu şekilde çiftlenebilir.

3- Genellikle, önekli komutlar U'da işlenir ve çiftlenemezler.

Pentium için optimize edilen programlar, işlemci çalışma prensiplerinden ötürü daha eski işlemcilerde normalden de yavaş çalışabilirler. Bunun sebebi, eski karmaşık yapılı komutların aynı anlama gelen komutlara ayrılmasıyla komut çiftleme imkânı oluşturmak, Pentium işlemcilerde hız kazandırırken eski tip işlemcilerde kaybettirebilir. Günümüzde pek önemi kalmayan bu durum bir uyarı niteliğindedir.

2.3- Pentium Pro ve Pentium II :
Mimarileri ve komut işleme teknikleri çok benzer olan olan bu iki işlemci, üç komutu aynı anda işleme yeteneğine sahiptir. Bunun dışında, gelişkin dallanma tahmini, yazmaç isimlerini otomatik değiştirme, sırasız komut işleme gibi çok etkili yöntemlerle çalışırlar. Pentium II, MMX desteği, 16-bit programları daha iyi işlemesi ve yeni veriyolu mimarisi ile Pentium Pro'dan ayrılır.
Pentium Pro ve PII'nin komut yollarını D0, D1, D2 diye adlandırırsak, D0 Pentiumlardaki U'ya, diğerleri V'ye karşılık gelir. Komutların uygunlaştırılması üçlü halde yapılır. Bununla birlikte Pentium için optimize edilen program bu işlemcilerde de normalden hızlı çalışacaktır.

Bu anlatılanların işlemci özelliklerinin bazı eksikleri ve belirtilmemiş istisnalar vardır. Genel durum, belirtildiği şekilde olup ayrıntılara girilmemiştir.

Pascal'da Assembly:
Derleyiciler herzaman en uygun kodu üretmezler, hatta birçoğu eski işlemcilerle olan uyumluluğu bozmamak için yeni işlemcilerde oldukça «müsrif» davranan komutları üretebilirler. Ayrıca hafıza erişimi bolca olan ya da matematiksel işlem yapan kodların optimize edilmesi genellikle mümkündür. Derleyicinin yapamadığı yerde bunu programcı, kodunu assembly komutlarıyla destekleyerek yapar.
Assembly komutları Pascal programlarına üç yoldan eklenebilir:
1- Inline komutuyla doğrudan, derlenmiş byte kod olarak,
2- Assembler'da Pascal modeliyle derlenmiş .obj dosyaları yoluyla,
3- TP6'dan itibaren Assembler direktifi ile tüm prosedürde veya asm ... end bloğu arasında 16-bit 80286 komutları olarak.

Inline direktifi:
İşlemciye gönderilecek komutları hazır olarak programa katmak için kullanılır. Bir prosedür için uygun olan herhangi bir yerde yazılabilir. Kullanımı dikkat ve biraz bilgi ister. Normalde derleyicinin destekle-mediği komutları bu sayede programa eklemek mümkün olur. Bugünkü uygulamada bundan başka avantajı kalmamıştır. Bu direktif hakkında ayrıntılı bilgi bu yazıda verilmeyecektir.
Assembly komutlarının karşılığı olan byte kodları Debug veya herhangi bir disassembler program yardımıyla elde ettikten sonra ardışık / ile ayrılmış baytlar şeklinde parantezin arasına yazmak gerekir.
Inline($A1/$FF/$F0); veya aynı anlamda Inline($A1/$F0FF); komutu MOV AX,$FFF0 komutunun karşılığı olarak programa dahil edilebilir. Görüldüğü gibi, word değerlerin bayt halinde yazılması sırasında yüksek ve düşük baytların ters sırada yazılması gerekir.

Harici Prosedürler:
Pascal modeline göre derlenmiş assembly program parçaları .obj dosyaları halinde programa dahil edilebilir, programın içindeki veriyi kullanabilir.

Assembler direktifi ve asm...end blokları:
Kullanılan derleyiciye bağlı olarak kaynak kodu içinde assembly komutları ve prosedürleri kullanılabilir. Çok yaygın derleyicilerden Borland Pascal 6 ve 7'de 286/287 komutları, TMT Pascal'da 386/387 komutları desteklenmektedir.
Genel kullanımı şu şekildedir:

Procedure ProcName( {parametreler} );Assembler;
asm
... {Assembly komutları}
end; {Prosedür sonu}

Sözkonusu olan fonksiyonlar olduğunda da aynı yapı geçerlidir.
Prosedür ve fonksiyonların değer parametreleriyle yazmaçlar arasındaki alışverişi parametreleri doğrudan boyutuna uygun yazmaca atanarak yapılabilir. Adres içeren parametrelerde ve fonksiyonlardan dönecek değerlerde dikkat edilecek noktalar vardır.

Küçük bir hatırlatma: Prosedürlerin veya fonksiyonların parametreleri değer parametresi veya değişken parametresi olabilir.
Procedure EkrandanSatirOku( X,Y,U : Byte; Var Str:String);
Bu prosedürün görevi, metin ekranındaki X,Y koordinatından U uzunluğundaki bilgiyi okuyup Str string değişkenine aktarmak olsun. Buradaki X,Y ve U değer parametreleridir, değişmezler, Str ise değişken parametresidir, prosedür içinde değeri değişerek çıkabilir.

Bu prosedür çağırılırken
EkrandanSatirOku(4,5,N,S);
şeklinde çağırılabilir,
EkrandanSatirOku(4,5,N,'ABC');
şeklinde çağırılamaz!
Çünkü, değer parametrelerine değişken konabilir ama değişken parametrelerine (var ile tanımlı parametrelere) değer konamaz.
Adres içeren parametreler, pointer, string, dizi (array) tipinde olan değer parametreleri ve tüm değişken parametreleridir. Bunların 4 baytlık (segment ve ofsetli) adresleri alınıp asm...end bloğunda işlenirler.
Fonksiyonlarda ise, fonksiyonun geri dönecek değeri, tanımlanan tipine göre Byte, Shortint veya Char ise AL'de, Word veya Integer ise AX 'de, Longint veya Pointer ise AX:DX 'de saklanır.
Ayrıca çok kullanılan bazı assembly komutlarını hatırlatmakta fayda var:

( y:yazmaç, a:adres, d:değer, @:sıçrama komutları için ofset )
- MOV y/a, y/a/d
- AND, OR, XOR y, y/a
- NOT, NEG y/a
- SHL, SHR, ROL, ROR y/a, y/d
- LEA y, [y+d]
- JMP @
- JA, JZ, JE, JB, JNA, ... @
- TEST, CMP y/a, y/a/d

Yukarıdaki komutlarda «a, a» kombinasyonu geçerli değildir. Ayrıca adres ve yazmaç kullanımı ile ilgili de kısıtlamalar vardır. Örneğin SHL DX,CL geçerli ama SHL DX,CX geçersizdir!

Tüm bu bilgilerin ışığında, bir string değişkenin N. karakterinin Ascii kodunu veren bir fonksiyon yazılabilir:

Function Ascii(Var S:String; N:Byte):Byte;Assembler;
asm
LES DI, S[0] { 1: S'in başlangıç adresi ES:DI'a depolanır }
XOR BX,BX { 2: BX yazmacı sıfırlanır }
XOR AX,AX { 3: AX yazmacı sıfırlanır }
MOV BL, N { 4: Kaçıncı karakter hesaplanacağı BL'ye }
MOV AL,ES:[DI] { 5: S'in uzunluğunu içeren ilk bayt AL'ye aktarılır }
CMP AL,BL { 6: AL, BL ile karşılaştırılır }
JB @1 { 7: AL'de bulunan S'in uzunluğu N'den küçükse işlem yapılamaz}
MOV AL,ES:[DI+BX] { 8: N. karakter AL'ye aktarılır }
JMP @2 { 9: Fonksiyonun sonucu AL'de }
@1:XOR AL,AL {10: İşlem mümkün değilse fonksiyondan sıfır değeri döner}
@2: {11: Bitti!.. }
end;

Bu fonksiyon, esasen Ord(S[N]) ifadesiyle aynı görevi görmesine rağmen konuya iyi bir örnek oluşturduğu için yazılmıştır. S'in ES:DI'a aktarılan adresi, sıfırıncı baytını yani uzunluğunu içerir. Uzunluğu N'den küçükse, fonksiyonun istenen karakterin değerini vermesi mümkün değildir. Bu durumda AL değerinin sıfırlanarak fonksiyonun terkedildiği @1 etiketine dallanma yapılır ve fonksiyondan sıfır değeri döner. S'in uzunluğu N'den büyük veya eşitse işlem mümkündür, AL'ye N. karakterin aktarılması ile işlem tamamlanır. Bu da şöyle gerçekleşir: N'in değerinin 4. Satırdan beri BX'de olduğunu biliyoruz. S[0]'ın adresi ES:[DI] idi. Bu adresten BL yani şimdi BX kadar uzakta olan bayt, N. bayttır. Bu bayt AL'ye 8. Satırda aktarılır ve fonksiyon görevini yerine getirmiş olur.

Sözün kısası...
Optimizasyon konusu, donanımın yazılıma göre daha hızlı gelişim göstermesi yüzünden pek üzerinde durulmayan ama tecrübeli programcıların gözardı etmedikleri bir konudur. Aynı işi yapan iki rakip programdan daha hızlı olanının, daha düşük konfigürasyonda iyi çalışanın tercih edilmesi olasılığı yüksektir. Ayrıca disk gibi depolama birimlerinin hızı konusunda pek az gelişme oluyor. Dosya işlemlerinin optimizasyonu halen önem taşıyan bir konudur.
Pascal’ı ve Intel işlemcilerini baz alarak yazılan bu yazıdaki bilgilerin daha kaliteli programların gelişmesine katkıda bulunmasını dilerim.


Sezgin Usanmaz

 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.