Peder82 Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Meget interessant, er det en lærer (professor) her?? Lenke til kommentar
LonelyMan Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 (endret) La oss se litt på hvordan vi kan skrive til minnet. Her er den samme koden fra forrige innlegg, bare at jeg har laget en funksjon som skriver over den første bokstaven i Tekst stringen. .386 .model flat, stdcall option casemap:none INCLUDE \MASM32\INCLUDE\windows.inc INCLUDE \MASM32\INCLUDE\kernel32.inc INCLUDE \MASM32\INCLUDE\User32.inc INCLUDELIB \MASM32\LIB\kernel32.lib INCLUDELIB \MASM32\LIB\User32.lib INCLUDELIB \MASM32\LIB\Masm32.lib MinProsedyre PROTO .DATA Tekst db "Assembler er enkelt.",0 Overskrift db "Hei",0 .DATA? .CODE Start: ; Kall prosedyren vår INVOKE MinProsedyre ; Sprett opp en messageboks INVOKE MessageBox, 0, OFFSET Tekst, OFFSET Overskrift, MB_OK or MB_ICONINFORMATION ; Terminerer denne prosessen og detacher alle .DLL invoke ExitProcess, eax MinProsedyre PROC mov eax, OFFSET Tekst mov cl, 'X' mov [eax], cl ret MinProsedyre ENDP end Start Hvis vi ser litt på MinProsedyre funksjonen. La oss gå gjennom hver instruksjon: mov eax, OFFSET Tekst Denne instruksjonen kopierer adressen til 'Tekst' (som ligger i data seksjonen), og lagrer den i eax. mov instruksjonen er motsatt enn hva som er naturlig, den første parameteren er target (eax) og den andre er kilde (OFFSET Tekst) Så når man skriver mov eax, OFFSET Tekst så flyttes kilden (OFFSET til Tekst) i eax registeret. Og nå inneholder eax registeret adressen til strengen vår. mov cl, 'X' cl er ett 8 bits register og kan inneholde 1 byte om gangen. Her flytter vi bokstaven 'X' til registeret cl. Assembleren gjenkjenner '' tegnene og erstatter det som er inni med integer tall. Bokstaven X har integer tall 88, så assembleren (ml.exe) erstatter 'X' med 88 før den assemblerer programmet ditt, så dette er noe som skjer før programmet blir laget. Denne funksjonen gjør det enklere å skrive ascii tall, uten å måtte slå det opp i ascii tabellen, så dette er en funksjon i assembleren for å gjøre det enklere å kode. Så, vi flytter bokstaven X (Ascii 88) inn i cl registeret. mov [eax], cl Her skriver vi innholdet av cl registeret (Som nå inneholder bokstaven X), den skriver det til adressen som er i eax registeret. Du ser jeg har hakeparantes rundt eax, dvs da skriver vi til minneadressen som er i eax registeret, og ikke til registeret selv. Hvis vi nå kjører programmet, så SKAL Tekst strengen (som er i .DATA seksjonen) nå ha første bokstav erstattet med en X. Kjører det og sjekker Endret 17. desember 2011 av LonelyMan 1 Lenke til kommentar
LonelyMan Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 (endret) La oss lage en buffer på 1 megabyte og skrive en million 'A' bokstaver i hele bufferen. .386 .model flat, stdcall option casemap:none INCLUDE \MASM32\INCLUDE\windows.inc INCLUDE \MASM32\INCLUDE\kernel32.inc INCLUDE \MASM32\INCLUDE\User32.inc INCLUDELIB \MASM32\LIB\kernel32.lib INCLUDELIB \MASM32\LIB\User32.lib INCLUDELIB \MASM32\LIB\Masm32.lib MinProsedyre PROTO .DATA .DATA? Buffer DWORD ? .CODE Start: ; Kall prosedyren vår INVOKE MinProsedyre ; Terminerer denne prosessen og detacher alle .DLL invoke ExitProcess, eax MinProsedyre PROC INVOKE GlobalAlloc, GPTR, 1000000 mov Buffer, eax mov edi, eax mov ecx, 1000000 mov al, 'A' rep stosb INVOKE GlobalFree, Buffer ret MinProsedyre ENDP end Start Her gjør vi noe litt mer avansert. I den uinitialiserte dataseksjonen ser du at jeg har laget en handle som vi skal bruke når vi allokerer 1 MB med minne. I min prosedyre bruker vi GlobalAlloc til å kreve en megabyte minne. GPTR betyr at windows skal automatisk fylle hele bufferen med 0. Viktig å skjønne at alle funksjoner returnerer verdien i eax registeret. Selv i c++, så er dette gjemt unna for deg, alle funksjonene returnerer verdier i eax, men høynivåspråket skjuler denne detaljen for deg ved å gjemme det under andre variabelnavn. Men husk at alle funksjoner som returnerer en verdi, de returnerer verdien alltid i eax registeret. Så du ser etter jeg har kjørt GlobalAlloc, så returnerer den en handle til minnet vårt i eax, denne flytter vi til Buffer variabelen som ligger i uninitialiserte data seksjonen. rep er en instruksjon som står for "repeat". stosb står for "Store single byte", men hvis du putter en rep instruksjon foran stosb så vil den repetere så og så mange ganger. Du angir antall repetisjoner i ecx registeret, du ser jeg har puttet en million i ecx registeret. Så skriver vi 1 million 'A' bokstaver i hele bufferen, og deretter frigjør vi minnet og avslutter. Endret 17. desember 2011 av LonelyMan 1 Lenke til kommentar
LonelyMan Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 (endret) Fra nå av vil jeg ikke kvotere hele programmet, "skjelettet" på programmet kan sees i mine tidligere innlegg over her, det blir for langt å ha skjelettet på programmet med hver gang, så nå inkluderer jeg bare prosedyren. Nå skal vi teste å lage en loop. denne loopen vil ikke være mest optimal, men den er likevel rask. Det er bare for at folk skal forstå hvordan en lager loops i assembler. MinProsedyre PROC mov ecx, 20 mov eax, 10 L1: add eax, 5 loop L1 ret MinProsedyre ENDP la oss kjapt gå gjennom instruksjonene her: mov ecx, 20 loop instruksjonen som du ser på linje 4, denne instruksjonen fungerer i samsvar med ecx registeret. Denne instruksjonen fungerer kun ved at du setter antall ganger i ecx registeret, loop count MÅ være i ecx registeret eller så fungerer ikke loop instruksjonen. Så her setter vi ecx til antall ganger vi ønsker å loope. mov eax, 10 Før vi entrer loopen, så setter vi eax registeret til en fast verdi av 10 først. Bare for moro skyld, slik at vi ikke starter på 0. L1: add eax, 5 L1 er en label, alle labels må ettersluttes med kolon. I prosedyrer skal labels kun ha 1 kolon, men hvis du setter 2 kolon etter hverandre så blir dette en global label, dvs du kan kalle den fra alle plasser i programmet, uansett hvor det er. Men siden dette er en prosedyre så lager vi en lokal label ved å bruke 1 kolon. Nå er vi inni selve loopen, for instruksjonen "add eax, 5" ligger rett på labelen, loopen vil gjentatte ganger hoppe tilbake til denne labelen. add eax, 5 vil legge til 5 i eax registere hver gang loopen hopper hit. og vi satt ecx registeret til 20, så hvis den looper 20 ganger hit, og eax var satt til 10 før vi entret loopen så eax registeret inneholde tallet 110 når loopen er ferdig kjørt. 10 + (20*5) = 110 Endret 17. desember 2011 av LonelyMan 1 Lenke til kommentar
LonelyMan Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 (endret) La oss teste conditional asm. I høynivå språk bruker man IF-THEN, DO-WHILE og REPEAT-UNTIL, men i asm instruksjonsverdenen fungerer dette annerledes. Der fins IF-THEN DO-WHILE i asm også, og de kan faktisk brukes på samme måten som i C++ eller andre høynivåspråk. Men la oss teste dette på instruksjonsnivå istedet. mov eax, 10 cmp eax, 10 je L2 INVOKE MessageBox, 0, OFFSET LOL, OFFSET Caption, MB_OK L2: INVOKE MessageBox, 0, OFFSET ROFL, OFFSET Caption, MB_OK ret instruksjonen som er relevant i dette tilfellet er på linje 2, "cmp eax, 10". cmp står for "compare". cmp eax, 10 sjekker om eax er likt 10. På neste linje ser du instruksjonen "je L2". Som står for "Jump if even". den forrige instruksjonen "cmp eax, 10" setter noen interne flags i cpu'en som baseres på resultatet fra denne compare instruksjonen. Og neste instruksjon "je L2" leser disse flaggene i cpu'en og bruker de basert på testen. "cmp eax, 10" så er det jo åpenbart at eax er 10, så "je L2" vil hoppe til labelen L2 og da vil messagebox med offset "ROFL" kjøre, ellers så vil den første message boksen kjøre. Disse to instruksjonene (der fins haugevis av andre) kan sies å være det samme som "IF-THEN" i høynivåspråk. HVIS det viser seg at den første messageboksen skulle kjøre (hypotetisk) så ville den kjørt den andre messageboksen like etterpå, fordi den ligger like etter. Men det ville ikke skjedd om den hoppet til L2 labelen, der er ingen messagebox etter den. Så det kunne lønnet seg å bruke JNE L2 istedet, som står for "Jump if NOT even" Endret 17. desember 2011 av LonelyMan 1 Lenke til kommentar
David Brown Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Kjører du på 64 bits med mitt program så blir det ikke det samme, og kompilerer du ett 64 bits c++ program så vil den fungere på en annen måte. Årsaken til at det muligens kan være raskere er fordi kompilatoren din benytter SSE til å kalkulere modulus og muligens kjører over flere tråder. "Feil" resultat skyldes at resultatet tolkes som signed dword, du kan ikke kalkulere 100 millioner tall og forvente at det skal akkumuleres opp til ett reelt tall, det fungerer kun for å måle hastigheten, ikke for å få ett rett resultat. Jeg kommer tilbake senere med en tilsvarende SSE variant, men har dårlig tid nå. Koden laget av kompilatoren brukte ikke SSE, og selv om det var på 64-bit er det ingenting i den genererte assembly koden som bruker hverken 64-bit arithmetic eller de ekstra registerene som er tilgjengelige. Jeg regner med at koden fra 32-bit gcc ville være praktisk sett identiske. Lenke til kommentar
David Brown Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Seien Sie so gut... 31 ms, 100 mill. :!: OPTION PROLOGUE:NONE OPTION EPILOGUE:NONE ALIGN 4 Multipler PROC push ebx mov ebx, 3 xor eax, eax mov ecx, 100000000 mov edx, ebx ALIGN 16 n1: add eax, ebx add ebx, edx cmp ebx, ecx jbe n1 mov ebx, 5 mov edx, ebx ALIGN 16 n2: add eax, ebx add ebx, edx cmp ebx, ecx ja n3 add eax, ebx add ebx, edx add ebx, edx cmp ebx, ecx jbe n2 n3: pop ebx ret Multipler ENDP OPTION PROLOGUE:PROLOGUEDEF OPTION EPILOGUE:EPILOGUEDEF Et problem med den originale oppgaven er at det er åpent til bedre implementasjoner og algoritmer. For å være ihvertfall litt meningsfullt, er det derfor viktig å holde seg til samme struktur. Man skal kjøre gjennom alle tall opp til 1000 (eventuelt en annen tall), se om det kan deles ved 3 eller 5, og legge sammen tallene. Det gjør du ikke her. Det er klart at din algoritme her er raskere enn originalen, og gir samme resultantene, men det kan ikke sammenlignes med C koden. Dersom man får lov til å endre algoritmen, er min C++ template kode like gyldig - og der bruker man kompilatoren til å kalkulere resultantene på forhånd, slik at koden er bare en instruksjon. Det hadde også godt an å bruke en bedre generelle algoritme som fungere i O(0) tid istedenfor O(1) tid - men igjen så ville det ikke være sammenlignbar. Enten må vi holde oss til akkurat samme algoritme, med optimisering av implementasjon men ikke metoden, ellers må vi finne et annet problem som ikke har samme forbedringsmuligheter. Så for min del er ikke denne koden aksepterte som assembly implementasjon av oppgaven - du har optimisert algoritmen, ikke laget en assembly implementasjon som slå C implementasjon. Forresten da jeg skrevet samme implementasjon som deg i C, laget kompilatoren omtrent identiske kode som kjørte på omtrent samme tid (34 ms på min PC). Men jeg kunne også gi kompilatoren en ekstra "-funroll-all-loops" flag som reduserte tiden til 26 ms - en 20% økning i hastighet for 10 sekunds arbeid. 1 Lenke til kommentar
David Brown Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Jeg lar deg lekke litt mer med assembly'en før jeg fortelle om trikset kompilatoren brukte for å lage raskere kode. Nå kan du fortelle om trikset som gjorde koden din raskere enn min. Deling er en ganske treg operasjon på x86 cpu'er (og de alle fleste andre cpu'er), og passer veldig dårlig inn i pipelines. Dermed bruker gode C kompilatorer (som gcc) ganging istedenfor deling ved en konstant. Det er ikke lett å finne ut de beste konstanter å bruke, og være sikkert på at det er riktig, spesielt dersom man bruker signed arithmetic - derfor er det best å la kompilatoren gjør jobben. Koden under er fra listing filen fra kompilatoren (jeg tok feil tidligere, da jeg sa at den ikke brukte ekstra amd64 register - men koden til 32-bit x86 hadde vært veldig likt): 123 test1000: 124 .LFB15: 125 .cfi_startproc 126 00c0 31FF xorl %edi, %edi 127 00c2 31C9 xorl %ecx, %ecx 128 00c4 41B85655 movl $1431655766, %r8d 128 5555 129 00ca 41B96766 movl $1717986919, %r9d 129 6666 130 .p2align 4,,10 131 .p2align 3 132 .L20: 133 00d0 89C8 movl %ecx, %eax 134 00d2 89CE movl %ecx, %esi 135 00d4 41F7E8 imull %r8d 136 00d7 C1FE1F sarl $31, %esi 137 00da 29F2 subl %esi, %edx 138 00dc 8D1452 leal (%rdx,%rdx,2), %edx 139 00df 39D1 cmpl %edx, %ecx 140 00e1 7410 je .L18 141 00e3 89C8 movl %ecx, %eax 142 00e5 41F7E9 imull %r9d 143 00e8 D1FA sarl %edx 144 00ea 29F2 subl %esi, %edx 145 00ec 8D1492 leal (%rdx,%rdx,4), %edx 146 00ef 39D1 cmpl %edx, %ecx 147 00f1 7502 jne .L19 148 .L18: 149 00f3 01CF addl %ecx, %edi 150 .L19: 151 00f5 83C101 addl $1, %ecx 152 00f8 81F9E803 cmpl $1000, %ecx 152 0000 153 00fe 75D0 jne .L20 154 0100 89F8 movl %edi, %eax 155 0102 C3 ret Lenke til kommentar
LonelyMan Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Første poeng er at det er viktig at du poster kode når du legger ut tall når du sammenligner. Neste poeng er at fordi jeg tenker ut bedre algoritmer enn deg, så blir ikke det automatisk juks, din algoritme var elendig og nå har du kopiert min, legger ut tall som ikke samsvarer med noen kode. Det tredje poenget er at du ikke kan sammenligne 64 bits kode med 32 bits kode på noen måter. Det fjerde poenget er at koden allerede ER rollet ut, det du sier høres veldig merkelig ut, det fins ikke flere registre å rolle ut i dette tilfellet. Så jeg er svært spent på å se koden. De konstantene du snakker om kalles magic numbers. Jeg er godt kjent med de, men har ikke brukt de. Lenke til kommentar
Matsemann Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Poenget var ikke å lage en algoritme som løste problemet mest mulig effektivt, men å implementere gitt kode i forskjellige språk. (altså, bloggen til Torbjørn). At problemet har en bedre matematisk løsning er ikke poenget. Her skriver vi innholdet av cl registeret (Som nå inneholder bokstaven X), den skriver det til adressen som er i eax registeret. Du ser jeg har hakeparantes rundt eax, dvs da skriver vi til minneadressen som er i eax registeret, og ikke til registeret selv. Er det type register indirekte adressering og slikt? Vært borti lite assembly, bare litt i et fag nå i høst, og da var vi egentlig en del nivået under assembly. Det hadde også godt an å bruke en bedre generelle algoritme som fungere i O(0) tid istedenfor O(1) tid - men igjen så ville det ikke være sammenlignbar. Jeg kan big-O notasjon, men aldri vært borti noe annet enn konstant tid O(1), hva skal O(0) bety? Lenke til kommentar
Abigor Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Etter at jeg lærte assembly fikk jeg større kunnskaper om flytskjemaer og oppbygning av kode sekvensielt. Dette er noe jeg har hatt nytte av senere i objektbasert programmering. Den viktigste grunnen til at jeg lærte assembly var likevel at det var pensum. Lenke til kommentar
LonelyMan Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 (endret) David Brown, som sagt du kjører et 64 bits der med 16 registre. Mitt program er ett 32 bits program med 8 registre, altså halvparten av hva du bruker der. Du kan jo på ingen måte sammenligne det der, men det mest tragiske var at jeg likevel hadde samme hastighet enn dog du har dobbelt så mange registre tilgjengelig, det er helt latterlig. Hva jeg kunne gjort med disse ekstra registrene Min konklusjon er: 1: Din forrige kode sa du var 32 bits kode (men i det nye eksemplet ditt her så er det 64 bits "kode") jeg føler at du ikke snakker sant selv om du kaller det bakoverkompatibelt så er det dobbelt opp med registre og det kan nesten kvalifiseres som 64 bits, derfor sier jeg det for å unngå forvirring. 2: Du tar min algoritme og implementerer den. 3: Du implementerer den på ett hardware sett som har dobbelt så mange registre og er ikke engang et 32 bits program. Det er helt klart og utvilsomt ett slag som er tapt fra din side, utvilsomt. Endret 17. desember 2011 av LonelyMan Lenke til kommentar
LonelyMan Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Er det type register indirekte adressering og slikt? Vært borti lite assembly, bare litt i et fag nå i høst, og da var vi egentlig en del nivået under assembly. Ja, stemmer Lenke til kommentar
torbjørn marø Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Det hadde også godt an å bruke en bedre generelle algoritme som fungere i O(0) tid istedenfor O(1) tid - men igjen så ville det ikke være sammenlignbar. Jeg kan big-O notasjon, men aldri vært borti noe annet enn konstant tid O(1), hva skal O(0) bety? jeg antar han mente O(1) og O(n), ikke O(0) og O(1)... :| O(0) ville i såfall bety en algoritme uten instruksjoner i det hele tatt Lenke til kommentar
Matsemann Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Ja, derfor jeg stusset litt Lenke til kommentar
Abigor Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Hva vil O(1) si? Kort og effektiv algoritme? Lenke til kommentar
Matsemann Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 (endret) En algoritme som bruker konstant tid på å gjøre noe. Slik som å utføre noen beregninger som tar like lang tid uansett input. Er noe O (n) sier man det tar lineær tid. Da er antall operasjoner som må gjøres proporsjonal med input. F. eks det å finne minste tall i en liste. Da må du gå igjennom hele listen, og blir listen større tar det tilsvarende lang tid. Altså O (n) Skal du finne første element i en liste spiller det jo ingen rolle hvor mange elementer som kommer etterpå, så det er O (1) Sorteringsproblemer er typisk O (n*n) Endret 17. desember 2011 av Matsemann 1 Lenke til kommentar
David Brown Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Det hadde også godt an å bruke en bedre generelle algoritme som fungere i O(0) tid istedenfor O(1) tid - men igjen så ville det ikke være sammenlignbar. Jeg kan big-O notasjon, men aldri vært borti noe annet enn konstant tid O(1), hva skal O(0) bety? jeg antar han mente O(1) og O(n), ikke O(0) og O(1)... :| O(0) ville i såfall bety en algoritme uten instruksjoner i det hele tatt Korrekt - beklager feilskrivingen min. Du kan tenke at jeg mente å skrive O(n^1) og O(n^0) - det var ihvertfall det som var tanken. Lenke til kommentar
David Brown Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 En algoritme som bruker konstant tid på å gjøre noe. Slik som å utføre noen beregninger som tar like lang tid uansett input. Er noe O (n) sier man det tar lineær tid. Da er antall operasjoner som må gjøres proporsjonal med input. F. eks det å finne minste tall i en liste. Da må du gå igjennom hele listen, og blir listen større tar det tilsvarende lang tid. Altså O (n) Skal du finne første element i en liste spiller det jo ingen rolle hvor mange elementer som kommer etterpå, så det er O (1) Sorteringsproblemer er typisk O (n*n) Sortering er vanligvis O(n.log(n)) tid, ihvertfall med vanlige effektive algoritmer (heap sort, quick sort, insertion sort). Det fins O(n^2) sorting algoritmer, som bubblesort, som er greit når du trenger noe liten og enkelt, og ikke skal sortere store lister. Det fins også algoritmer som nærmer seg O(n), som bucket sort, men de er kun bedre enn O(n.log(n)) i bestemte omstendigheter. Lenke til kommentar
David Brown Skrevet 17. desember 2011 Del Skrevet 17. desember 2011 Første poeng er at det er viktig at du poster kode når du legger ut tall når du sammenligner. Jeg trodde jeg hadde postet en god del av koden. Jeg har slurvet litt med å poste C koden - men det er bare når det er soleklart hvordan C koden skal være, eller andre har også postet koden. Men mangler du noe bestemt, så kan jeg godt poste den. Jeg er selvfølgelig enige med det at man må ha koden for å kunne kjøre det på samme maskin, for å kunne sammenligne tider. Neste poeng er at fordi jeg tenker ut bedre algoritmer enn deg, så blir ikke det automatisk juks, din algoritme var elendig og nå har du kopiert min, legger ut tall som ikke samsvarer med noen kode. Joda, det er "juks" i denne sammenhengen. Jeg har en betydelige bedre algoritme enn deg - og jeg så den med en gang jeg leste utfordringen på bloggen. Men som andre har sagt, var ikke det poenget her, fordi en raskere algoritme viser ingenting i sammenligning mellom C og assembly. Utfordringen var for å gi deg sjanse til å overbevise andre at du kan skrive koden raskere i assembly enn andre kan i C - ikke for å se hvem som kan finne en bedre algoritme. Koden i C er: static int sumn(unsigned int n) { // Return sum of 1 + 2 + .. + (n-1) return (n * (n - 1)) / 2; } static unsigned int sum3or5(unsigned int n) { unsigned int n3 = (n + 2) / 3; unsigned int n5 = (n + 4) / 5; unsigned int n15 = (n + 14) / 15; return 3 * sumn(n3) + 5 * sumn(n5) - 15 * sumn(n15); } int main(void) { printf("%i\n", sum3or5(1000000000)); return 0; } Men optimisering på, er den genererte assembly koden en instruksjon "movl $2138801452, %esi". Det vil si, kompilatoren er smart nok til å gjøre alle kalkulasjonene på forhånd siden talene er konstant. Det går ikke an å lage noe bedre koden enn det. Dersom jeg bruker ekstra "volatile" variabler og begrenset optimisering for å tvinge kompilatoren å generere koden til kalkulasjon, tok den hele 8 nanosekunder å kjøre "sum3or5" funksjonen. Er det lov for deg å endre algoritme, så er det lov for meg å gjøre det. Og jeg gjør det på en måte som er lite avhengig av de faktiske tall som vi bruker her - det er kompilatoren som gjør grovarbeidet. Det tredje poenget er at du ikke kan sammenligne 64 bits kode med 32 bits kode på noen måter. Joda, vi kan sammenligne dem. For det første er de fleste instruksjonene nokså likt. Det ville ha vært noen forskjell dersom jeg hadde brukt en 32-bit kompilatoren, men strukturen i genererte koden hadde vært likt. Statistisk sett er det få programmer som kjører mer enn 10-20% fortere etter omkompilering til 64-bit sammenlignet på 32-bit på samme systemet. For det andre har 64-bit vært den kurante arkitekturen i PC verden i mange år - jeg kan ikke gjøre noe for at du er begrenset til gammeldags teknologi. For det tredje, handler dette tråden mye om hvor egnet eller uegnet assembly er til generelle programmering, og faktum at du er ikke i stand til å benytte kraften i prosessoren din p.g.a. begrensninger til assembly er et veldig viktig poeng. Du kan ikke påstå at du kan skrive det raskeste mulig programmer til PC'en din, når du faktisk ikke bruke prosessoren. Det fjerde poenget er at koden allerede ER rollet ut, det du sier høres veldig merkelig ut, det fins ikke flere registre å rolle ut i dette tilfellet. Så jeg er svært spent på å se koden. De konstantene du snakker om kalles magic numbers. Jeg er godt kjent med de, men har ikke brukt de. Nei, koden er ikke rollet ut. Du har rullet ut litt i koden din, men man kan gjøre det mye mer. For å ta den første loopen din: n1: add eax, ebx add ebx, edx cmp ebx, ecx jbe n1 Da har du en backover hopp for hver rundt, noe som koster i pipelining ytelse. En mer effektivt koding hadde vært: n1: add eax, ebx add ebx, edx cmp ebx, ecx ja n2 add eax, ebx add ebx, edx cmp ebx, ecx ja n2 add eax, ebx add ebx, edx cmp ebx, ecx ja n2 add eax, ebx add ebx, edx cmp ebx, ecx jbe n1 n2: Det kalles for loop unrolling, og det er noe som er tungvindt å gjøre manuelt i assembly, men enkelt å gjøre i en kompilator. Det er ikke alltid at det øker hastighet - det er en balanse mellom pipelining, branch kostnader, branch prediction buffers, cache linjer, prefetch buffers, osv. Kompilatoren har en nokså god ide om dette for alle de forskjellige prosessorene, men det blir litt "trial and error". Fort gjort med en kompilator der man bare endre noen command line switcher, men ikke så morsomt i assembly verden. Og dersom du noen gang prøve å jobbe med en annen cpu som ikke er like register-fattig som x86, finner du fort ut hvor flott det er å ha en kompilator som holde redde på alle register - dette type unrolling kan nemlig la kompilatoren kjøre interleaving på itterasjonene ved å bruke forskjellige registerer og dermed unngå stalls p.g.a. dependencies. (Jeg beklager at det blir en del engelske uttrykk her - dette er ikke noe jeg pleier å snakke om på norsk.) 1 Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå