Jump to content

Recommended Posts

Obtiaznost: ****

 

Pawn je vykonávaný na abstraktnom stroji (Abstract Machine eXecutor). Tento číta výsledný skompilovaný kód a vykonáva dané inštrukcie. Ak narazí na switch(), porovnávanie hodnôt vykonáva automaticky (porovnávací kód sa nenachádza v skompilovanom súbore).

 

2. Kdy a jak použít switch

 

Okrem toho, že switch vyzerá krajšie, je aj rýchlejší.

Rýchlosť budem porovnávať s týmto kódom:

compif(x) {
    if (x == 1) {
        return;
    } else if (x == 2) {
        return;
    } else if (x == 3) {
        return;
    } else if (x == 4) {
        return;
    } else {
        return;
    }
}

compswitch1(x) {
    switch(x) {
        case 1..4: return;
        default: return;
    }
}

compswitch2(x) {
    switch(x) {
        case 3: return;
        case 2: return;
        case 4: return;
        case 1: return;
        default: return;
    }
}

Čím viac hodnôt (case-ov) porovnávate, tým viac sa oplatí používať switch.

Porovnanie (GetTickCount()) môže vyzerať nejak takto:

[02:55:21] iftime: 14435
[02:55:29] switchtime1: 8038
[02:55:37] switchtime2: 8053

Rovnako testovanie na dvoch hodnotách (case 1..2) (ale viac iterácií):

[03:09:03] iftime: 17946
[03:09:17] switchtime1: 14004
[03:09:33] switchtime2: 16093

A testovanie na 30 hodnotách:

[03:14:07] iftime: 72057
[03:14:26] switchtime1: 19457
[03:14:43] switchtime2: 19146

Ako je vidieť, switch už moc nenaberá na čase s viac hodnotami. A tiež switch1 má rovnakú rýchlosť ako switch2.

 

 

6. Ako funguje switch

 

Prečo je switch rýchlejší? Ostatné (Pawn viacmenej tiež) jazyky používajú tzv. Jump table.

 

Najprv ukážem ako vyzerá bežný if (kód vyššie) po skompilovaní: (kod som vytiahol cez oficialny pawndisasm.c)

* Niektore zbytocne instrukcie som kvoli prehladnosti odstranil. Kvoli tomu adresy nepojdu "za sebou".

* pri je (abstraktny register) miesto v pamati, ktore použiva Pawn AMX, kedze nedokaze porovnat priamo dve premenne. Vsetky operacie sa robia cez pri. Mozete si to predstavit ako premennu s rychlym pristupom.

* Okomentoval som to pre lahsie citanie, staci si pozriet komenty a adresy kam to skáče.

; compif(x)
; adresa | instrukcia
00000354  proc compif
; if (x == 1)
0000035c  load.s.pri 0000000c ; pri = x
00000364  eq.c.pri 00000001   ; pri != 1?
0000036c  jzer 00000380       ; ak plati, skoc na adresu 00000384 (dalsi else if)
0000037c  retn                ; (neplati) return
; else if (x == 2)
00000384  load.s.pri 0000000c ; pri = x
0000038c  eq.c.pri 00000002   ; pri != 2?
00000394  jzer 000003a8       ; ak plati, skoc na 000003a8
000003a4  retn                ; return
000003a8 ; ... dalsie else if

Porovnáva každý if s danou hodnotou, v prípade, že sa nerovnajú, "preskočí" na ďalší else-if. Ten skok trvá najdlhšie.

 

Jump table

 

V RAM vyzera dana tabulka takto: (vlavo adresy v RAM, vpravo inštrukcia na danej adrese)

RAM:
--------------------------
| jmptable:              |
| 0x01: JUMP 0x2349807   |
| 0x02: JUMP 0x0938490   |
| 0x03: JUMP 0x6454299   |
| ..                     |
| 0x2349807 kod z case 1 |
| ..                     |
--------------------------

Kód

switch (x) {..}

sa teda kompilerom prepíše na

jump (jmptable + x);

Ideálne teda nedochádza k žiadnemu porovnaniu hodnôt, iba k jednému skoku.

 

Switch v Pawn

Pawn je teda v tomto trochu iný. Tabulka (v Pawn nazýzvaná "casetbl") sa rovnako vygeneruje, ale nepoužíva sa priamo skok, ale len porovnávanie hodnôt. AMX V reálnom čase porovnáva hodnotu x so všetkými "cases" a až keď nájde rovnakú hodnotu, skočí na danú adresu.

compswitch1 z kódu uvedeného vyššie:
 

00000404  proc compswitch1
0000040c  load.s.pri 0000000c ; pri = x
00000414  switch 00000444     ; switch (pri), jump table je na adrese 00000444  
; case 1..4:
00000424  retn                ; return - vnutro case
00000428  jump 00000470       ; skoc za casetbl, v pripade ze nenasiel ziadnu hodnotu v tabulke
; case: default
00000438  retn                ; return, resp. iny kod
0000043c  jump 00000470       ; skoc za "casetbl", teda na dalsi kod
00000444  casetbl 00000004 00000438 ; celkovo 4 moznosti, pri default skoč na 00000438
                  00000001 00000424 ; case 1: jmp 00000424 
                  00000002 00000424 ; case 2: jmp 00000424 
                  00000003 00000424  
                  00000004 00000424  
00000470 ; ..

Je teda zrejmé, že "1..4" vygeneruje zápisy pre všetky možnosti medzi tým s rovnakou skokovou adresou.

 

Kód cmpswitch2 vyzerá podobne. Pre stručnosť sem dám len casetbl.

00000478  proc compswitch2
; ..
000004f4  casetbl 00000004 000004e0 ; 4 zapisy
                  00000001 000004cc ; x == 1 -> skoc na prvy case
                  00000002 000004a4 ; x == 2 -> druhy case
                  00000003 00000490
                  00000004 000004b8
000004e0 ; ..

Rozdiely medzi cmpswitch1 a 2 sú, že každý case má odlišnú adresu kam skočiť.

 

Záver

Možno ste si všimli, že hodnoty sú v compswitch2 po skompilovaní zoradené. Kompiler ich zoradil automaticky.

The records in the case table are sorted on their value. An abstract machine may take advantage of this lay-out to search through the table with a binary search.
(z Pawn Implementer Guide). Podľa zdrojového kódu amx sa však nepoužíva binary search, ale lineárne porovnávanie všetkých hodnôt zaradom.
  • Líbí se mi to! (+1) 3

Share this post


Link to post
Share on other sites

 

(porovnávací kód sa nenachádza v skompilovanom súbore).

S tímto bych nesouhlasil. V kompilovanem kodu je vsechno. Ale pri spusteni se cely nahraje do pameti (Tj muzes po spusteni mod smazat ze slozky gamemodes a furt svr pojede (do resetu)). Taky jeden z duvodu proc nema moc smysl resit jestli vytvorit pole o 50 nebo 100 znacich kdyz ma cely kompilovany kod 10MB :d

Share this post


Link to post
Share on other sites

Sry venďo, že ti spamujem do navodu :p

 

S tímto bych nesouhlasil. V kompilovanem kodu je vsechno. Ale pri spusteni se cely nahraje do pameti (Tj muzes po spusteni mod smazat ze slozky gamemodes a furt svr pojede (do resetu)). Taky jeden z duvodu proc nema moc smysl resit jestli vytvorit pole o 50 nebo 100 znacich kdyz ma cely kompilovany kod 10MB icon_e_biggrin.gif

Myslel som to tak, že ak použiješ switch, vo vyslednom subore je len "switch (adresa tabulky)" a samotna casetbl. Porovnavanie hodnot a nasledny skok na tu spravnu hodnotu tam nie je, robí to amx na pozadí.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

×