Seite 10 von 10

Verfasst: 03.10.2005 14:51
von ZeHa
Naja laut der Optimizations.txt werden meistens überflüssige Kommandos entfernt bzw. lange Routinen durch kürzere ersetzt... das einzige, was den Code scheinbar länger macht, ist das Ersetzen von Poke-Calls durch den direkten Code. Aber das kam in meinem Programm nicht vor ;)

Verfasst: 03.10.2005 16:03
von remi_meier
Nö, die Liste ist etwas länger ;)

Z. B. Int(), das wird durch eine sehr lange Routine ersetzt, oder auch ASin,
ACos, ... auch RGB(), Red(), ...
Siehe Liste...
Der Optimizer optimiert nach Geschwindigkeit und nicht nach Grösse!


Übrigens: Optimizer strikes back! Makros (nicht 100%ige..) sind am Kommen.

Verfasst: 03.10.2005 17:02
von remi_meier
http://mypage.bluewin.ch/remimeier/zip/Optimierer.zip

Es ist vollbracht, denk ich zumindest (wird wohl noch Bugs haben...)

Pseudomakros sind nun in PB möglich! Warum Pseudo? Weil es einige
Einschränkungen gibt die es zu beachten gilt:
- diese Makros sind etwas langsamer als 'wirkliche' Makros!
- es muss mindestens ein Parameter angegeben werden, auch wenn der
nicht benötigt wird (sry, bin unfähig)
- KEINE LOKALEN VARIABLEN
- siehe Help.txt -> Macros!
- die mitgelieferte Userlib wird dazu benötigt.

Beispiel:

Code: Alles auswählen

Structure VECTOR
	x.f
	y.f
EndStructure

OptimizerStartMacro()
Procedure.f Length(*a.VECTOR)
	ProcedureReturn Sqr(*a\x * *a\x + *a\y * *a\y)
EndProcedure
OptimizerStopMacro()

Procedure.f Length2(*a.VECTOR)
	ProcedureReturn Sqr(*a\x * *a\x + *a\y * *a\y)
EndProcedure


a.VECTOR
a\x = 2
a\y = 4

Delay(500)
#n = 99999999

time1 = timeGetTime_()
For z = 0 To #n
  c.f = Length(@a)
Next
time1 = timeGetTime_() - time1

time2 = timeGetTime_()
For z = 0 To #n
  c.f = Length2(@a)
Next
time2 = timeGetTime_() - time2

MessageRequester("",Str(time1) + " " + Str(time2))
Makros: 1268
PB-Proc: 2229
Deeem optimized proc: 1470 (great work!)

Vorsicht mit dem deklarieren vieler Makros! Die Codegrösse steigt immens!

Danke fürs Testen!

greetz
Remi :)

Verfasst: 03.10.2005 18:14
von ZeHa
remi_meier hat geschrieben: Siehe Liste...
Der Optimizer optimiert nach Geschwindigkeit und nicht nach Grösse!
Okay welche Liste muß ich mir da anschauen? ;)

Verfasst: 04.10.2005 12:10
von remi_meier
PureArea.net Showcase ->
- PeekF(), PokeF(), PeekL(), PokeL(), PeekW(), PokeW(), PeekB(), PokeB()
- CallFunctionFast()
- Red(), Green(), Blue(), RGB()
- ACos(), ASin(), ATan(), Int(), Log(), Log10()

Verfasst: 26.03.2006 22:07
von Helle
Da ich im Forum schon wegen der (zum Teil sehr) unterschiedlichen Programm-Ausführungszeiten der verschiedenen PB4-Betas rumgemosert habe hier nun ein (weiterer) Versuch, ungünstiges "im-Speicher-zum-Liegen-kommen" zu korrigieren.
Jaja, es geht um mein heissgeliebtes Thema "Align" :mrgreen: !
Die oben genannten Laufzeit-Unterschiede dürften allesamt mit dem Thema "Alignment" zu tun haben und nicht mit irgendeiner schlechten Programmierung seitens des PB-Teams oder was sonst noch vermutet wurde.
Also hier ein neuer Versuch von AliSet:

Code: Alles auswählen

;--------------------- Setzen Alignment, K.Helbing ("Helle"), PureBasic 4.00 Beta 7, 26.04.2005 -------------------

;- Alignment: Das Legen von CPU-Instruktionen (und auch Daten!) auf Speicheradressen, die ohne Rest durch 4 teilbar
;- sind (oder anderer Wert, der eine Zweier-Potenz sein muss; bei einem 32-Bit Betriebssystem aber sinnvollerweise
;- 4). Auf diese Speicheradressen kann effektiver zugegriffen werden als auf "ungerade", das Programm sollte also
;- schneller werden. Dies zeigt sich messbar natürlich nur bei etwas größeren Anwendungen (EXE!); ein Zehnzeiler in
;- einer (fast) Endlos-Schleife als Test ist Nonsens. Ein Schachprogramm lief ca.7-8% schneller.
;- Da es Unfug ist, jede CPU-Instruktion zu "alignmentieren", wurden in Programmen häufig vorkommende Instruktionen 
;- ausgewählt, die 4-oder 8-Byte langen OP-Code haben.   
;- Es besteht natürlich immer die "Gefahr", dass eigentlich gut liegende Befehle durch an anderer Stelle eingeschobene
;- NOP´s auf schlechtere "Plätze" verschoben werden. Dann ist eben der Gewinn geringer bzw. garnicht da. Probieren!   
;- Gesetzt wird Alignment immer nach - JMP
;-                                   - RET
;-    wenn nur 1x NOP nötig dann vor - CMP WORD[MEM],WERT  bei WERT <80h  ist 8-Byte-Opcode 
;-                                   - CMP [16-Bit-REG],WERT  ist 4-Byte-Opcode für Wert<80h
;-                                   - MOV      "         "           "
;-                                   - ADD      "         "           "
;-                                   - SUB      "         "           "         für Wert<80h wenn nicht AX-Register
;-                                   - ADC      "         "           "
;-                                   - SBB      "         "           " 
;-                                   - AND      "         "           "
;-                                   - SHL      "         "           "         für Wert >1 
;-                                   - SHR      "         "           "               "
;-                                   - LEA in Verbindung mit [ESP+...]"   Alle ausser ESP+0 
;-                                   - PUSH         "     "      "
;-                                   - INC          "     "      "
;-                                   - DEC          "     "      "
;-                                   - FADD         "     "      "
;-                                   - FLD          "     "      "
;- Würden 2 oder gar 3 NOP´s nötig sein, wird auf Alignment verzichtet (dies ist die grosse Änderung im Vergleich
;- zur Vorgänger-Version).
;- Erweiterungen sind jederzeit möglich.
;- Die EXE-Datei wird (natürlich) um die Anzahl der eingefügten NOP´s grösser.
;- Je nach Datei-Grösse kann der Durchlauf durchaus einige Minuten dauern.
;- Empfehlung: Das Ganze in einer RAM-Disk ablaufen lassen (auch wegen der vielen HD-Zugriffe, aber keine Angst!).
;- Als "Wiederfinder" in der EXE-Datei wird der Befehl UD2 verwendet, den ja wohl keiner in seinem Programm
;- verwendet ;).
;- WICHTIG! AliSet und die eigene Quelldatei ins Compilers-Verzeichnis von PB kopieren! 
;- Quell- oder PB-Dateien werden nicht verändert; überschrieben wird nur die evtl. vorhandene EXE-Datei.

Global FILELAENGEA.l = $0                                  ;Filelänge ASM-Datei
Global FILELAENGEE.l = $0                                  ;Filelänge EXE-Datei
Global S1.l = $47494c41                                    ;ALIG
Global S2.l = $0a34204e                                    ;N 4 mit LF
Global S3.l = $0a324455                                    ;UD2 mit LF
Global M1.l = $564f4d                                      ;MOV    Leerzeichen werden unten auf Null gesetzt!
Global M2.l = $44524f57                                    ;WORD
Global M3.l = $504d43                                      ;CMP
Global M4.l = $434e49                                      ;INC
Global M5.l = $434544                                      ;DEC
Global M6.l = $434441                                      ;ADC
Global M7.l = $424253                                      ;SBB
Global M8.l = $504d4a                                      ;JMP
Global M9.l = $0a544552                                    ;RET
Global M10.l = $444441                                     ;ADD
Global M11.l = $4c4853                                     ;SHL
Global M12.l = $524853                                     ;SHR
Global M13.l = $425553                                     ;SUB
Global M14.l = $0b505345                                   ;ESP+
Global M15.l = $41454c                                     ;LEA 
Global M16.l = $48535550                                   ;PUSH
Global M17.l = $444e41                                     ;AND 
Global M18.l = $44444146                                   ;FADD
Global M19.l = $444c46                                     ;FLD

Global INSTR.l = $0
Global WT.b = $0
Global WT1.b = $0

Global *MemoryID.l = $0
Global PROGID.l = $0 

Global PROG$
  
;-------- Abfrage Name der Quell-Datei

       PROG$ = InputRequester("PB-Quelldatei","Bitte Quelldatei ohne Erweiterung (.PB) eingeben!","")

;-------- Test, ob Dateiname gültig ist

       If ReadFile(1,PROG$ + ".PB")
           ElseIf MessageRequester("Status", "Datei nicht gefunden!")
           End 
       EndIf 
       CloseFile(1) 
 
;-------- erstmal die ASM-Datei zur Bearbeitung erstellen ("commented"), "exe" damit Programm nicht
;-------- startet sondern nur EXE-Datei erstellt wird. Datei kann gelöscht werden. 

       MessageRequester("Status", "Nach der OK-Bestätigung bitte warten bis Fertigmeldung erscheint!")
     
       PROGID = RunProgram("PBCompiler.exe", PROG$ + ".pb /inlineasm /quiet /commented /exe " + PROG$ + "O.exe", "",#PB_Program_Hide | #PB_Program_Open) 
      
       WaitProgram(PROGID)
       CloseProgram(PROGID)
     
       CopyFile("PureBasic.asm","OldPureBasic.asm")        ;für Testzwecke, kann entfallen

       OpenFile(1,"PureBasic.asm")
           FILELAENGEA=Lof(1)
       CloseFile(1) 
     
              ;----------------------- RAM-Speicher für direkten Zugriff reservieren ----------------------
       *MemoryID = AllocateMemory($2000000)    ;jeweils 16 MB für die ASM- und EXE-Datei
                                               ; eventuell anpassen an Source-Datei
       If *MemoryID = $0 
         MessageRequester("Fehler!", "Konnte den angeforderten Speicher nicht reservieren!")
         End  
       EndIf 

       ReadFile(1,"PureBasic.asm")
           ReadData(1,*MemoryID,FILELAENGEA)
       CloseFile(1)

              MOV esi,*MemoryID        ;ESI ist damit tabu!
              XOr bp,bp                ;Merker ob ALIGN "gut" ist
              MOV ebx,1h               ;evtl. Test auf "Main" o.ä. für grösseren Wert, ist aber nicht relevant
              MOV edx,0dfdfdfdfh       
SEARCH:       MOV al,[esi+ebx-1h]
              CMP al,3bh          ;";"         
              JE l_nofound4    
              CMP al,41h               ;wegen z.B. PAND, FIADD und ähnlichen möglichen Fehlinterpretationen 
              JAE l_nofound1 
              MOV eax,[esi+ebx]
              And eax,edx              ;Kleinbuchstaben-Bit löschen, Leerzeichen wird Null!  
              MOV edi,ebx              ;ist die eventuelle Einfüge-Stelle
            
              MOV INSTR,eax            ;für z.B. Test ob WORD              
              CMP eax,M18              ;FADD
              JE l_voradd3             ;Test auf esp+
              CMP eax,M19              ;FLD
              JE l_voradd3

              CMP eax,M8               ;JMP  
              JE l_nachjmp
              CMP eax,M9               ;RET
              JE l_nachjmp


              CMP eax,M3               ;CMP
              JE l_vorcmp
              CMP eax,M10              ;ADD
           JE l_vorcmp   
              ;JE l_voradd             ;mögliche Variationen, um Ergebnis evtl. zu verbessern (auch komplettes
                                       ; Weglassen von Abfragen möglich)
              CMP eax,M1               ;MOV
              JE l_voradd
              CMP eax,M11              ;SHL
              JE l_vorshift
              CMP eax,M12              ;SHR
              JE l_vorshift
              CMP eax,M13              ;SUB
           JE l_vorcmp  
              ;JE l_voradd
              CMP eax,M6               ;ADC
           ;JE l_vorcmp  
              JE l_voradd              
              CMP eax,M7               ;SBB
           ;JE l_vorcmp  
              JE l_voradd              
              CMP eax,M15              ;LEA
              JE l_voradd3
              CMP eax,M16              ;PUSH
              JE l_voradd3
              CMP eax,M4               ;INC
              JE l_voradd3
              CMP eax,M5               ;DEC
              JE l_voradd3
              CMP eax,M17              ;AND
           JE l_vorcmp 
              ;JE l_voradd
            
              JMP l_nofound1

        ;----------------------- Align NACH einem JMP oder RET einfügen ---------------------------
NACHJMP:      INC ebx
              CMP byte[esi+ebx],0ah    ;Ende der Zeile?
              JNE l_nachjmp            ;nein
              INC ebx
              MOV edi,ebx              ;Einfügestelle      
              INC bp                   ;Merker für "gutes" ALIGN
              JMP l_found
             
       ;---------------- Align VOR div.Instruktionen bei bestimmten Konstellationen ---------------
VORCMP:       CALL l_wordtest
              XOr ecx,ecx              ;für Werttest
              CMP WT,cl                ;Null?
              JE l_voradd2             ;kein Word, nächster Test
           ;------------------ ist WORD ----------------------------       
NOKLAMMER:    INC ebx
              MOV al,[esi+ebx]              
              CMP al,5bh               ;[
              JNE l_noklammer
NOKLAMMER1:   INC ebx
              MOV al,[esi+ebx]               
              CMP al,20h
              JE l_noklammer1          ;Leerzeichen
              CMP al,5fh               ;_  als Kennung für Variable
              JE l_werttest      
              CMP al,5dh               ;]
              JE l_nofound1      
              JMP l_noklammer1

WERTTEST:     INC ebx
              MOV al,[esi+ebx]
              CMP al,2ch               ;Komma
              JNE l_werttest  
WERTTEST1:    INC ebx
              MOV al,[esi+ebx]
WERTTEST3:    CMP al,30h               ;Leerzeichen oder führende Nullen
              JBE l_werttest1
WERTTEST2:    CMP al,0ah
              JE l_auswertungd
              CMP al,68h               ;h
              JE l_auswertungh
              CMP al,48h               ;H
              JE l_auswertungh
              CMP al,20h
              JE l_werttest4           ;für dez bis Zeilenende     
              SHL ecx,8h
              MOV cl,al

WERTTEST4:    INC ebx
              MOV al,[esi+ebx]
              JMP l_werttest2       

AUSWERTUNGH:  TEST ecx,0ffff0000h
              JNZ l_nofound1
              CMP ch,38h
              JAE l_nofound1
              JB l_found 
  
AUSWERTUNGD:  TEST ecx,0ff000000h
              JNZ l_nofound1
              CMP ch,39h
              JA l_nofound1            ;Register             
              MOV eax,ecx
              SHR eax,8h
              CMP ah,31h
              JA l_nofound1
              JB l_found 
              CMP ch,32h
              JA l_nofound1
              JB l_found 
              CMP cl,38h
              JAE l_nofound1
              JMP l_found 
;------------------------ Ende Werttest ----------------------------------------------

VORADD:       ADD ebx,3h
VORADD1:      INC ebx
VORADD2:      MOV al,[esi+ebx]              
              CMP al,5bh               ; [   
              JE l_nofound3   
             
              And al,dl
              JZ l_voradd1
              MOV WT,al      
              INC ebx
              MOV al,[esi+ebx]         ;Test auf 2.Buchstaben
              CMP al,5fh               ;_  Variablen aussieben   
              JE l_nofound1        
              And al,dl
              MOV WT1,al     
              CMP al,58h               ;X? für AX.BX,CX,DX
              JE l_isregister
              CMP al,49h               ;I? für DI,SI
              JE l_isregister
              CMP al,50h               ;P? für BP
              JE l_isregister

;-------------------------------------- Suche nach ESP+Wert, Wert>0 ------------       
VORADD3:      INC ebx
              MOV eax,[esi+ebx]              
              CMP al,0ah
              JE l_nofound1
              And eax,edx
              CMP eax,M14              ;ESP+?
              JNE l_voradd3            
              ADD ebx,3h
VORADD4:      INC ebx
              MOV al,[esi+ebx]
              CMP al,5dh               ;]
              JE l_nofound1             
              CMP al,31h               
              JAE l_found              ;grösser Null   
              JMP l_voradd4     

ISREGISTER:   INC ebx
              MOV al,[esi+ebx]
              CMP al,30h               ;Leerzeichen, Komma, Null
              JB l_isregister
              JE l_isregister1   
              CMP al,39h
              JA l_nofound1
ISREGISTER1:  MOV ecx,INSTR
              CMP ecx,M1               ;MOV?
              JE l_found               ;kein Werttest
              CMP WT,41h
              JE l_found               ;ist AX-Register  DX???
              ;CMP WT,44h               ;nochmal in Ruhe anschauen, ob lohnend
              ;JNE l_isregister3     
              ;CMP WT1,58h
              ;JE l_found      
             
ISREGISTER3:  XOr ecx,ecx
              JMP l_werttest3        
            
VORSHIFT:     CALL l_wordtest
              CMP WT,1h
              JNE l_vorshift2 
              ADD ebx,3h
              JMP l_found

VORSHIFT1:    INC ebx
VORSHIFT2:    MOV al,[esi+ebx]              
              CMP al,5fh               ;_  Variablen aussieben    Klammer? Sollte hier egal sein
              JE l_nofound1             
              And al,dl
              JZ l_vorshift1
              INC ebx
              MOV al,[esi+ebx]         ;Test auf 2.Buchstaben
              And al,dl
              CMP al,58h               ;X? für AX.BX,CX,DX
              JE l_isregister2
              CMP al,49h               ;I? für DI,SI
              JE l_isregister2
              CMP al,50h               ;P? für BP
              JNE l_nofound1

ISREGISTER2:  INC ebx
              MOV al,[esi+ebx]
              CMP al,2ch               ;Leerzeichen, Komma
              JBE l_isregister2
              INC ebx
              CMP al,31h  
              JE l_nofound1            ;1-er Shifts haben eigenen Opcode!
              CMP al,39h               ;Test nicht für Wert, sondern auf Register!
              JA l_nofound1
                          
       ;-------------------------- was lohnenswertes (hoffentlich!) gefunden -----------------------------                      
FOUND:        ADD FILELAENGEA,8h       ;für 1x ALIGN wird die Datei 8 Byte länger
              INC ebx
     ; ADD ebx,6h 
       ;---------------------------- Restdatei nach "hinten" verschieben ---------------------------------      
              MOV ecx,FILELAENGEA
              SUB ecx,4h
SCHIEBEN1:    MOV eax,dword[esi-8h+ecx]
              MOV dword[esi+ecx],eax
              SUB ecx,4h
              CMP ecx,edi
              JAE l_schieben1 
      
       ;----------------------------- "ALIGN 4" einfügen mit LF ------------------------------------------
              MOV eax,S1
              MOV [esi+edi],eax
              MOV eax,S2
              MOV dword[esi+4h+edi],eax
              Or bp,bp    
              JNE l_genehm
 
              PUSH edi                 ;Einfügestelle von ALIGN 4
        ;------------------------------ "UD2" einfügen mit LF -------------------------------------
NACHALI:      INC ebx
              CMP byte[esi+ebx],0ah    ;Ende der Zeile?
              JNE l_nachali            ;nein
              INC ebx
              MOV edi,ebx              ;Einfügestelle      
    
       ;----------------------------- "UD2" einfügen mit LF -------------------------------------          
              ADD FILELAENGEA,4h       ;für 1x UD2 wird die Datei 4 Byte länger
              INC ebx
              ADD ebx,6h               ;bei Gelegenheit mal optimieren
       ;---------------------------- Restdatei nach "hinten" verschieben --------------------------
              MOV ecx,FILELAENGEA
              SUB ecx,4h
SCHIEBEN2:    MOV eax,dword[esi-4h+ecx]
              MOV dword[esi+ecx],eax
              SUB ecx,4h
              CMP ecx,edi
              JAE l_schieben2 
      
       ;----------------------------- "UD2" einfügen mit LF ---------------------------------------
              MOV eax,S3
              MOV [esi+edi],eax
   
              PUSHAD
       OpenFile(1,"PureBasic.asm")
           WriteData(1,*MemoryID,FILELAENGEA)
       CloseFile(1)
     
       PROGID = RunProgram("PBCompiler.exe", PROG$ + ".pb /inlineasm /quiet /reasm /exe " + PROG$ + ".exe", "",#PB_Program_Hide | #PB_Program_Open) 
     
       WaitProgram(PROGID)
       CloseProgram(PROGID)

       OpenFile(2,PROG$ + ".exe")
           FILELAENGEE=Lof(2)
     
       ReadFile(2,PROG$ + ".exe")
           ReadData(2,*MemoryID+$1000000,FILELAENGEE)
       CloseFile(2)
              POPAD
 
              MOV ecx,1000000h 
              ADD ecx,FILELAENGEE
              MOV ax,0b0fh             ;in der EXE-Datei Suche nach Opcode für UD2 (0F0B)
SEARCH04:     DEC ecx
              CMP [esi+ecx],ax
              JNE l_search04
             
              MOV ax,0fh               ;max. soviel Bytes zurück verfolgen auf der Suche nach NOP´s
                                       ; evtl. verfeinern wegen möglicher Kommentare! 
FOUND05:      DEC ecx
              CMP Word[esi+ecx],9090h  ;2xNOP und damit auch 3xNOP
              JE l_found06
              DEC ax
              JNZ l_found05              
              INC bp                   ;"Gut" also nur, wenn 1xNOP
FOUND06:
     
        ;-------- Restdatei erstmal wieder nach "vorn" verschieben um 4 Bytes UD2 --------- 
              MOV ecx,FILELAENGEA
              SUB ecx,4h
      
SCHIEBEN3:    MOV eax,dword[esi+4h+edi]
              MOV dword[esi+edi],eax
              ADD edi,4h
              CMP edi,ecx
              JB l_schieben3
          
              SUB FILELAENGEA,4h        
  
              POP edi
               
              Or bp,bp 
              JNE l_genehm

        ;-------- Restdatei  wieder nach "vorn" verschieben um 8 Bytes ALIGN 4 --------- 
              MOV ecx,FILELAENGEA
              SUB ecx,4h
      
SCHIEBEN4:    MOV eax,dword[esi+8h+edi]
              MOV dword[esi+edi],eax
              ADD edi,4h
              CMP edi,ecx
              JB l_schieben4
          
              SUB FILELAENGEA,8h        



GENEHM:       XOr bp,bp
      ;ADD ebx,2h          
       ;----------------------------------- Rest der Datei ----------------------------------------
NOFOUND1:     INC ebx
              CMP ebx,FILELAENGEA
              JB l_search
              JMP l_fertig
  
NOFOUND3:     INC ebx
              CMP ebx,FILELAENGEA
              JAE l_fertig
              CMP byte[esi+ebx],0ah    ;LF?
              JE l_search
              JMP l_nofound3

NOFOUND4:     INC ebx
              CMP ebx,FILELAENGEA
              JAE l_fertig
              CMP byte[esi+ebx],0ah    ;LF?
              JNE l_nofound4
              INC ebx  
              JMP l_search
                        
;-------------------------------------- Unterprogramme ---------------------------------------------------
WORDTEST:     MOV WT,0h
              ADD ebx,3h
LEERW:        INC ebx
              MOV eax,[esi+ebx]              
              And eax,edx
              Or al,al
              JE l_leerw
                      
              CMP eax,M2               ;WORD
              JNE l_nofound2
              MOV WT,1h
NOFOUND2:     RET 

FERTIG:      
       OpenFile(1,"PureBasic.asm")
           WriteData(1,*MemoryID,FILELAENGEA)
       CloseFile(1)
     
       RunProgram("PBCompiler.exe", PROG$ + ".pb /inlineasm /quiet /reasm /exe " + PROG$ + ".exe", "",2) 


       MessageRequester("Status", "Geschafft!")

End
Der gravierende Unterschied zum Vorgänger ist, das für zu durchlaufenden Code nur noch 1 NOP zugelassen wird.
AliSet und die eigene Quelldatei ins Compilers-Verzeichnis von PB kopieren!
Ich hoffe, es testet mal jemand!

Gruss
Helle

Verfasst: 26.03.2006 23:05
von MVXA
Möchte dich keines falls kränken, ich finde es genial was du da machst,
aber warum nutzt du PB, wenn du so gut wie alles in Assembler
programmierst o_O?

Verfasst: 28.03.2006 13:37
von Helle
@MVXA: Ich versuche die gebotenen Möglichkeiten so gut wie möglich zu nutzen :) ! Assembler dort, wo es wirklich auf Speed ankommt und PB dort, wo ich mich sonst mit Win-API rumschlagen müsste (z.B. Bildschirmausgaben).
Übrigens: Auf [url]http://www.mdcc-fun.de/k.helbing gibts eine erweiterte Version mit gaaaanz vieeeeel PB-Anteil!

Gruss
Helle