PB im Vergleich mit anderen Sprachen in Bezug auf Speed
- Mok
- BotHunter
- Beiträge: 1484
- Registriert: 26.12.2005 14:14
- Computerausstattung: MSI GX780R
Intel Core i5-2410M
Nvidia GT 555M
Windows 7 Home Premium 64 bit - Wohnort:
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
Den Code bis ins allerkleinste Eck optimieren kann man sowieso nur mit Inline Assembler.
Hab gerade keinen Bock, ein Beispiel zu kompilieren und assemblieren, falls jemand unbedingt ein Beispiel will, kann ich aber gerne eines posten!
Hab gerade keinen Bock, ein Beispiel zu kompilieren und assemblieren, falls jemand unbedingt ein Beispiel will, kann ich aber gerne eines posten!
Win 7 Home Premium 64 bit | PureBasic 5.20 - x86 und x86-64 | Firefox [aktuelle stable-Version hier einfügen]
"Jeder macht irgendwann mal Fehler, darum gibt's auch Bleistifte mit Radiergummi." --Carl
"Jeder macht irgendwann mal Fehler, darum gibt's auch Bleistifte mit Radiergummi." --Carl
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
Hier ein umfangreiches Beispiel was man so alles optimieren kann. Code funktioniert zwar nicht mit PB 4.51 und ich weiß auf die schnelle nicht wordan es liegt, aber ich denke er ist trotzdem sehr veranschaulichend:
Code: Alles auswählen
;
; Small ASM tutorial
; Petit TUT ASM
;
; F.Weil 20040617
;
; This listing is a workshop about ASM insertion in PureBasic code. Nothing exhaustive but a possible first basis.
;
; The workshop is based on 'les taches de Martin', meaning each point of an image is set according to the average of it's neighbors.
; A limited color palette is necessary to render appropriate effect.
;
; I propose to use a regular 32 bits depth for the screen and to solve this by calculating the final color of each point.
;
; Focus is made on how to address the drawing buffer directly.
;
; Purpose of this workshop is not to show that it is possible to do much better than PureBasic as it demonstrates the opposite.
; Only in some cases using ASM will help, but most of the time not. This workshop shows how to code in PureBasic well, and how
; few improvements can be obtained using ASM coding.
;
; For a better user experience, it is possible to parse methods execution by using left / right keyboard arrows, and to change
; drawing area size using NumPad4 / NumPad6
;
; The algorithm name, frames per second obtained and drawing size are displayed in real time.
;================================================================================
; Ce listing a pour but de montrer comment étudier la transposition en ASM de certaines parties de code.
; Rien d'exhaustif mais une prise en main qui peut donner de bonnes bases.
;
; Reprise du principe des taches de Martin
;
; LÃ j'ai mis l'accent sur la gestion directe du DrawingBuffer
;
; L'algorithme proposé est de même principe que celui d'origine pour les taches de Martin, c'est à dire
; pour chaque point P(X, Y) on associe une couleur calculée à partir de la moyenne des couleurs des 4 points
; voisins + 1
; Soit couleur(P(X, Y)) = (couleur(P1(X, Y - 1)) + couleur(P2(X - 1, Y)) + couleur(P3(X + 1, Y)) + couleur(P4(X, Y + 1))) / 4 + 1
;
; Pour rendre l'effet escompté on doit travailler dans une palette limitée.
;
; Pour faire les choses sans passer par un screen en 8 bits ou autre chose, je prends le mode par défaut de l'écran en 32 bits, et
; je convertis en recalculant couleur
;
; couleur = couleur % 64 + 192
; couleur = couleur << 10 + couleur
;
; Le but de cette démonstration ne consiste pas à montrer des carences de PureBasic, bien au contraire. Il ressort que l'utilisation de l'ASM
; n'apporte que peu d'améliorations si le codage PureBasic est bien conçu par le développeur.
;
; Pour une meilleure expérimentation des méthodes ici, il est possible de naviguer sur les différents types de code en utilisant les
; flèches gauche / droite du clavier et de changer la taille de la zone de dessin avec les touches 4 / 6 du clavier numérique.
;
; Un affichage temps réel de l'algorithme utilisé, du nombre de trames par seconde et de la taille du dessin est effectué.
;
; This enumeration is made to make the different codes to executes easier to access
; Also the codes names are placed in strings to display stats
;
; Cette énumération est mise en place pour rendre l'accès aux différents algorithmes plus aisés.
; Les noms des codes à exécuter sont également placés dans un tableau de chaînes pour l'affichage des stats.
;
; Here is a chart of experimental results (inFPS) I found on my design PC
; Voici un tableau des résultats expérimentaux (en FPS) obtenus sur mon PC de développement
;
; FlipBuffers(1) 128x128 256x256 320x240 480x360 640x480 800x600
; PureBasic_Regular_Code 4 2 1 - - -
; PureBasic_Better_Code 60 30 30 21 10 8
; PureBasic_Optimized_Code 60 30 30 22 10 8
; PureBasic_LowLevel_Code 60 30 30 22 10 8
; PureBasic_Chewed_Code 60 30 30 19 9 7
; ASM_Code 60 30 30 23 10 8
; PureBasic_LowLevel_Code2 60 59 59 45 20 15
; ASM_LowLevel_Code2 60 60 59 50 22 16
;
; FlipBuffers(0) 128x128 256x256 320x240 480x360 640x480 800x600
; PureBasic_Regular_Code 5 2 1 - - -
; PureBasic_Better_Code 260 55 46 21 12 8
; PureBasic_Optimized_Code 251 50 49 22 11 8
; PureBasic_LowLevel_Code 251 50 49 22 11 8
; PureBasic_Chewed_Code 216 44 42 19 10 7
; ASM_Code 255 55 52 23 12 9
; PureBasic_LowLevel_Code2 604 126 100 45 27 17
; ASM_LowLevel_Code2 627 143 113 51 30 20
;
; Results measured on my 1.2GHz / 32MB graphic PC
; Résultats mesurés sur mon PC 1,2GHz / Graphique 32MO
;
Enumeration
#PureBasic_Regular_Code
#PureBasic_Better_Code
#PureBasic_Optimized_Code
#PureBasic_LowLevel_Code
#PureBasic_Chewed_Code
#ASM_Code
#PureBasic_LowLevel_Code2
#ASM_LowLevel_Code2
EndEnumeration
#LastCode = #ASM_LowLevel_Code2
Global tz.l, FPS.l, NFrames.l, AFrames.l, TFrames.l ; Stats
;
; ResetAll allows to clear the screen's buffers and thearrays used in the program
; ResetAll permet d'effacer les buffers et de remettre les tableaux utilisés à zéro.
Procedure ResetAll()
; FlipBuffers(1)
; ClearScreen(0)
; FlipBuffers(1)
; ClearScreen(0)
Dim DrawingArray.l(1024, 768)
Dim DrawingArea.l(1024 * 768)
tz = ElapsedMilliseconds()
FPS = 0
NFrames = 0
AFrames = 0
TFrames = 0
EndProcedure
ExecuteCode = #ASM_Code
Dim CodeType.s(10)
Dim DrawingWidth.l(10)
Dim DrawingHeight.l(10)
Global FontID1 = LoadFont(23, "Verdana", 8, #PB_Font_HighQuality | #PB_Font_Bold)
; A list of code parts names is placed in the DataSection
; Une liste des noms des parties du code est placée en DataSection.
For i = 0 To #LastCode
Read CodeType(i)
CodeType(i) + Space(40 - Len(CodeType(i)))
Next
LastSize = 5
WidthHeight = 3
; A list of drawing sizes is placed in DataSection
; Une liste des tailles de zone de dessin est donnée en DataSection
For i = 0 To LastSize
Read DrawingWidth(i)
Read DrawingHeight(i)
Next
;
; DrawingArray is a 2 dimensions array to store screen's x, y pixels in some part of the program
; DrawingArea is a single dimension array used in the same purpose in some other parts
;
; DrawinArray est un tableau à 2 dimensions utilisé pour mémoriser les pixels x, y de l'écran dans certaines parties du programme
; DrawingArea est un tableau à une seule dimension utilisé dans le même but, mais dans d'autres parties.
;
Dim DrawingArray.l(1024, 768)
Dim DrawingArea.l(1024 * 768)
; The current drawing width and heigth are set and xTop, yTop, xBottom, yBottom are bounds
; La largeur et la hauteur courante pour le dessin sont initalisées ainsi que les limites xTop, yTop, xBottom, yBottom
DrawingWidth = DrawingWidth(WidthHeight)
DrawingHeight = DrawingHeight(WidthHeight)
ScreenXSize = GetSystemMetrics_(#SM_CXSCREEN)
ScreenYSize = GetSystemMetrics_(#SM_CYSCREEN)
xTop = (ScreenXSize - DrawingWidth) / 2 + 1
yTop = (ScreenYSize - DrawingHeight) / 2 + 1
xBottom = xTop + DrawingWidth - 2
yBottom = yTop + DrawingHeight - 2
;
;
;
If InitKeyboard() And InitSprite() And OpenScreen(ScreenXSize, ScreenYSize, 32, "Taches de Matin")
StartDrawing(ScreenOutput())
DrawingFont(FontID1)
StopDrawing()
Repeat
;
; FlipBuffers is used with two possible argument value : 0 without buffer buffer sync which is shorter but
; may generate more flickering on the screen, or 1 to wait the buffer ready before to display it.
;
; Mode change is accesible using up / down arrows
;=========================================================================
; On utilise la commande FlipBuffers(0) (sans synchronisation plus rapide mais qui peut produire des scintillements
; ou FlipBuffers(1) qui attend que le buffer soit prêt avant affichage.
;
; Le changement de mode se fait en appuyant les flèches haut ou bas.
;
FlipBuffers(FlipBuffers)
StartDrawing(ScreenOutput())
Select ExecuteCode
;
; To start the following code just do what the top comments describe, using Point(x, y) to know a pixel value. Neighbors are
; injected in a formula and the given point set using Plot.
;=====================================================================================
; Pour commencer voici dans une écriture conventionnelle le code correspondant à la spécification donnée en commentaire ci-dessus.
;
; Pour l'ensemble des points à traiter, on calcule la somme des valeurs des 4 points adjacents que l'on injecte dans une formule.
;
; Le point courant est ensuite simplement dessiné à la position voulue.
;
Case #PureBasic_Regular_Code
For x = 1 To DrawingWidth - 1
For y = 1 To DrawingHeight - 1
Value = ((Point(x + xTop, y + yTop - 1) + Point(x + xTop, y + yTop + 1) + Point(x + xTop + 1, y + yTop) + Point(x + xTop - 1, y + yTop)) / 4 + 1) % 64 + 192
Color = Value << 10 + Value
Plot(x + xTop, y + yTop, Color)
Next
Next
;
; In #PureBasic_Better_Code, we do no more use Point(x, y) but an 2 dimensions array to store points values.
;
; This array contains elements corresponding to screen pixels.
;
; Using this makes the listing easy to understand but the performances are much better
;=======================================================================================
; Dans la version #PureBasic_Better_Code on ne va plus utiliser la fonction Point(x, y) mais un tableau qui permet de mémoriser les
; valeurs des points.
;
; Ce tableau est à deux dimensions et chaque élément x, y du tableau représente fidèlement un point de l'écran
;
; Par contre le tracé du point courant est fait avec la fonction Plot, dont les performances restent assez bonnes.
;
; De là l'écriture est encore assez lisible ... et les performances très différentes
;
Case #PureBasic_Better_Code
For x = 1 To DrawingWidth - 1
For y = 1 To DrawingHeight - 1
Value = ((DrawingArray(x, y - 1) + DrawingArray(x, y + 1) + DrawingArray(x - 1, y) + DrawingArray(x + 1, y)) / 4 + 1) & 63 + 192
Color = Value << 10 + Value
DrawingArray(x, y) = Color
Plot(x + xTop, y + yTop, Color)
Next
Next
;
; In #PureBasic_Optimized_Code a single dimension array is used.
;
; This makes the code a bit more difficult to understand but will make easier later optimization.
;=============================================================================
; Dans la version #PureBasic_Optimized_Code on utilise un tableau linéaire et non plus une matrice à deux dimensions.
;
; L'écriture du code est sensiblement plus lourde mais permettra d'aborder la phase d'optimisation suivante lus aisément.
;
Case #PureBasic_Optimized_Code
For x = 1 To DrawingWidth - 1
For y = 1 To DrawingHeight - 1
xy = y * DrawingWidth + x
Value = ((DrawingArea(xy - DrawingWidth) + DrawingArea(xy + DrawingWidth) + DrawingArea(xy - 1) + DrawingArea(xy + 1)) / 4 + 1) & 63 + 192
Color = Value << 10 + Value
DrawingArea(xy) = Color
Plot(x + xTop, y + yTop, Color)
Next
Next
;
; #PureBasic_LowLevel_Code uses both the array and a direct calculation of pixels addresses to the drawing buffer.
;
; This calculation will not make performances better right now, but will help to master direct copy of array values to pixels
;====================================================================================
; Dans #PureBasic_LowLevel_Code, on va utiliser simultanément un tableau pour mémoriser les points et un calcul de l'adresse des
; points dans le buffer d'écran.
;
; Ce calcul n'apportera pas directement d'améliorations de performances, mais permettra de maîtriser la copie directe d'une valeur du tableau sur l'écran.
;
Case #PureBasic_LowLevel_Code
DrawingBuffer = DrawingBuffer()
DrawingBufferPitch = DrawingBufferPitch()
For x = 1 To DrawingWidth - 1
X4 = DrawingBuffer + (x + xTop) << 2
For y = 1 To DrawingHeight - 1
xy = y * DrawingWidth + x
Value = ((DrawingArea(xy - DrawingWidth) + DrawingArea(xy + DrawingWidth) + DrawingArea(xy - 1) + DrawingArea(xy + 1)) / 4 + 1) & 63 + 192
Color = Value << 10 + Value
DrawingArea(xy) = Color
Color = (Color & $FF0000) >> 16 + (Color & $00FF00) + (Color & $0000FF) << 16
Address = DrawingBufferPitch * (y + yTop) + X4
PokeL(Address, Color)
Next
Next
;
; Here we try to "chew" the former code in order to get only simple low level instructions.
;
; Only one operation per line and no more than two variables in a single line.
;
; Thanks to PureBasic coding convention we can write :
;
; a + 1 instead of a = a + 1
; a + b instead of a = a + b
;
; etc
;
; c = a + b will be replaced by
; c = a
; c + b
;
; The resulting code will not be optimized as good as the compiler does, but it will be fast and close to machine level.
;===========================================================================
; Le but du code développé ici est de se rapprocher le plus possible des instructions les plus élémentaires.
;
; On essaye de proscrire toute écriture qui consiste à cumuler plusieurs opérations sur une même ligne
;
; Pour y parvenir il suffit d'ajouter des variables temporaires lorsque c'est nécessaire.
;
; Dans ce style d'écriture on utilisera de préférence la notation unaire de PureBasic, c'est à dire par exemple :
;
; a + 1 au lieu de a = a + 1
; a + b au lieu de a = a + b
;
; etc
;
; On s'interdit également d'utiliser trois variables sur une même ligne :
;
; c = a + b sera donc déployé en 2 lignes
; c = a
; c + b
;
; Cette écriture donnera un code très rapide, même si il n'est pas tout à fait aussi rapide que le modèle #PureBasic_LowLevel_Code précédent
;
; Cette étape est une manière réaliste de passer de l'optimisation langage évolué à l'optimisation assembleur. La tentative de traduire
; directement le code #PureBasic_Optimized_Code est généralement vouée à de malheureuses déconvenues et n'apporte jamais de meilleurs résultats
; que le code généré par le compilateur.
;
Case #PureBasic_Chewed_Code
DrawingBuffer = DrawingBuffer()
DrawingBufferPitch = DrawingBufferPitch()
For x = 1 To DrawingWidth - 1
X4 = x
X4 + xTop
X4 << 2
X4 + DrawingBuffer
For y = 1 To DrawingHeight - 1
xy = DrawingWidth
xy * y
xy + x
a = xy
a - DrawingWidth
Value = DrawingArea(a)
a = xy
a + DrawingWidth
Value + DrawingArea(a)
a = xy
a - 1
Value + DrawingArea(a)
a = xy
a + 1
Value + DrawingArea(a)
Value >> 2
Value + 1
Value & 63
Value + 192
Color = Value
Color << 10
Color + Value
DrawingArea(xy) = Color
Color1 = Color
Color1 & $FF0000
Color1 >> 16
Color2 = Color
Color2 & $00FF00
Color3 = Color
Color3 & $0000FF
Color3 << 16
Color = Color1
Color + Color2
Color + Color3
Address = y
Address + yTop
Address * DrawingBufferPitch
Address + X4
PokeL(Address, Color)
Next
Next
;
; Here we take the chewed code and translate it to ASM with some more optimization
;
; Especially we take care to avoid to store values in unnecessary variables.
;
; We can consider processor's registers as variables but with the limitation that any PureBasic instruction inserted between ASM lines
; may change registers values.
;
; So this is necessary to stay in ASM as far as possible to not loose registers values otherwise it is necessary to store registers all the time.
;=========================================================================================
; Le code #ASM_Code est la reprise du code #PureBasic_Chewed_Code avec quelques optimisations
;
; On s'attache en particulier à éliminer le report de valeurs de registres dans des variables temporaires.
;
; La limitation en nombre de registres oblige bien entendu à être très soigneux dans le choix des variables temporaires éliminées.
;
; On peut considérer pratiquement que les registres sont des variables, mais en conservant à l'esprit que l'exécution
; de toute instruction langage évolué remet en question l'état de tous les registres CPU.
;
; Il faut par conséquent rester en assembleur le plus longtemps possible pour éviter de risquer de perdre la valeur d'un registre en cours de route,
; ou inversement d'être contraint de sauvegarder tel ou tel registre dans une variable mémoire ce qui diminuerait la qualité d'optimisation.
;
Case #ASM_Code
DrawingBuffer = DrawingBuffer()
DrawingBufferPitch = DrawingBufferPitch()
X4.l
xy.l
For x = 1 To DrawingWidth - 1
! MOV eax, dword[v_x] ; eax = x
! ADD eax, dword[v_xTop] ; eax + xTop
! SAL eax, 2 ; eax << 2
! ADD eax, dword[v_DrawingBuffer] ; eax + DrawingBuffer
! MOV dword[v_X4], eax ; X4 = eax
For y = 1 To DrawingHeight - 1
! MOV eax, dword[v_DrawingWidth] ; eax = DrawingWidth
! IMUL eax, dword[v_y] ; eax * y
! ADD eax, dword[v_x] ; eax + x
! MOV ebp, dword[a_DrawingArea] ; ebp = @DrawingArea()
! MOV ecx, eax ; ecx = eax
! SUB ecx, dword[v_DrawingWidth] ; ecx - DrawingWidth
! SAL ecx, 2 ; ecx * 4
! MOV edi, dword[ebp+ecx] ; edi = PeekL(ebp + ecx)
! MOV ecx, eax ; ecx = eax
! ADD ecx, dword[v_DrawingWidth] ; ecx + DrawingWidth
! SAL ecx, 2 ; ecx * 4
! ADD edi, dword[ebp+ecx] ; edi + PeekL(ebp + ecx)
! MOV ecx, eax ; ecx = eax
! DEC ecx ; ecx - 1
! SAL ecx, 2 ; ecx * 4
! ADD edi, dword[ebp+ecx] ; edi + PeekL(ebp+ecx)
! ADD ecx, 8 ; ecx + 8 (soit ecx = ((eax - 1) + 2) * 4
! ADD edi, dword[ebp+ecx] ; edi + PeekL(ebp + ecx)
! SAR edi, 2 ; edi >> 2
! INC edi ; edi + 1
! And edi, 63 ; edi & 63
! ADD edi, 192 ; edi + 192
! MOV edx, edi ; edx = edi
! MOV ebx, edx ; ebx = edx
! SAL edx, 10 ; eax = edx << 10
! ADD edx, ebx ; edx = ebx
! MOV ecx, eax ; ecx = eax
! SAL ecx, 2 ; ecx * 4
! MOV [ebp+ecx], edx ; PokeL(ebp+ecx, edx)
! MOV ecx, dword[v_y] ; ecx = y
! ADD ecx, dword[v_yTop] ; ecx + yTop
! IMUL ecx, dword[v_DrawingBufferPitch] ; ecx * DrawingBufferPitch
! ADD ecx, dword[v_X4] ; ecx + X4
! BSWAP edx ; edx (00RRGGBB) => (BBGGRR00)
! SAR edx, 8 ; edx(BBGGRR00) => (00BBGGRR)
! MOV [ecx], edx ; PokeL(ecx, edx)
Next
Next
;
; In #PureBasic_LowLevel_Code2 the same idea is used than in former #PureBasic_LowLevel_Code but addressing is linearized
; Buffer addressing is no more x, y based but only a single variable is used.
;
; The address of the horizontal neighbor of a given point is the address of this point -/+ 1.
; The address of the vertical neighbor of a given point is the address of this point -/+ DrawingWidth.
;
; Using this method the point to draw is accessed the fastest.
;
; Meantime pixels values are stored in the array which is addressed using two variables to calculate unary index
; of the array easily, allowing to avoid the double address calculation.
;
; Obviously this does not look far from former code, it renders completely different results.
;
; In order to access to the best possible ASM optimization later, For / Next loops are replaced by Repeat / Until.
;
; Pixel value calculation is unchanged.
;=====================================================================
; Dans la version #PureBasic_LowLevel_Code2 on reprend le même principe mais on a linéarisé l'adressage
; Ici le buffer de l'écran est adressé avec une seule variable d'adresse qui est incrémentée de 4 octets pour passer
; point suivant et d'une ligne moins la DrawingWidth de tracé pour passer à la ligne suivante.
;
; Cette méthode permet d'adresser le pixel à tracer au plus vite.
;
; Dans le même temps les valeurs des points sont toujours stockées dans un tableau qui lui est adressé
; à partir de deux variables x et y en recalculant l'indice unaire du tableau pour éviter le double calcul d'adresse.
;
; La méthode paraît peu différente à priori, mais les résultats n'ont rien à voir.
;
; Pour amener à une meilleure optimisation ultérieure en assembleur, les boucles For / Next ont été remplacées par des Repeat / Until
;
; Le calcul de valeur d'un pixel reste inchangé.
;
Case #PureBasic_LowLevel_Code2
DrawingBuffer = DrawingBuffer()
DrawingBufferPitch = DrawingBufferPitch()
BufferAddress = DrawingBuffer + 4 * (xTop + 1) + yTop * DrawingBufferPitch
ArrayAddress = DrawingWidth + 1
y = 1
Repeat
x = 1
Repeat
Value = ((DrawingArea(ArrayAddress - DrawingWidth) + DrawingArea(ArrayAddress + DrawingWidth) + DrawingArea(ArrayAddress - 1) + DrawingArea(ArrayAddress + 1)) / 4 + 1) & 63 + 192
Color = Value << 10 + Value
DrawingArea(ArrayAddress) = Color
Color = (Color & $FF0000) >> 16 + (Color & $00FF00) + (Color & $0000FF) << 16
PokeL(BufferAddress, Color)
BufferAddress + 4
ArrayAddress + 1
x + 1
Until x > DrawingWidth - 1
ArrayAddress + 1
BufferAddress + DrawingBufferPitch - 4 * (DrawingWidth - 1)
y + 1
Until y > DrawingHeight - 1
;
; Here is the optimized ASM listing of the #PureBasic_LowLevel_Code2
;======================================================
; Voici une version assembleur optimisée pour le code #PureBasic_LowLevel_Code2
;
Case #ASM_LowLevel_Code2
DrawingBuffer = DrawingBuffer()
DrawingBufferPitch = DrawingBufferPitch()
! MOV ebx, dword[v_DrawingBuffer] ; ebx = DrawingBuffer
! MOV edi, dword[v_xTop] ; edi = xTop
! INC edi ; edi + 1
! SAL edi, 2 ; edi * 4
! ADD ebx, edi ; ebx + edi
! MOV edi, dword[v_yTop] ; edi = yTop
! IMUL edi, dword[v_DrawingBufferPitch] ; edi * DrawingBufferPitch
! ADD ebx, edi ; ebx + edi
! MOV dword[v_BufferAddress], ebx ; BufferAddress = ebx
! MOV ebx, dword[v_DrawingWidth] ; ebx = DrawingWidth
! INC ebx ; ebx + 1
! MOV dword[v_ArrayAddress], ebx ; ArrayAddress = ebx
! MOV dword[v_y], 1 ; y = 1
!_RepeatBN21: ; Repeat / Until return label
! MOV dword[v_x], 1 ; x = 1
!_RepeatBN22: ; Repeat / Until return label
! MOV ebp, dword[a_DrawingArea] ; ebp = DrawingArea
! MOV ecx, dword[v_ArrayAddress] ; ecx = @ArrayAddress
! MOV eax, ecx ; eax = ecx
! SUB eax, dword[v_DrawingWidth] ; eax - DrawingWidth
! SAL eax, 2 ; eax * 4
! MOV edi, dword[ebp+eax] ; edi = PeekL(ebp+eax]
! MOV eax, ecx ; eax = ecx
! ADD eax, dword[v_DrawingWidth] ; eax - DrawingWidth
! SAL eax, 2 ; eax * 4
! ADD edi, dword[ebp+eax] ; edi = PeekL(ebp+eax]
! MOV eax, ecx ; eax = ecx
! DEC eax ; eax - 1
! SAL eax, 2 ; eax * 4
! ADD edi, dword[ebp+eax] ; edi = PeekL(ebp+eax]
! ADD eax, 8 ; eax + 8
! ADD edi, dword[ebp+eax] ; edi = PeekL(ebp+eax]
! SAR edi, 2 ; edi / 4
! INC edi ; edi + 1
! And edi, 63 ; edi & 63
! ADD edi, 192 ; edi + 192
! MOV ebx, edi ; ebx = edi
! SAL ebx, 10 ; ebx << 10
! ADD ebx, edi ; ebx + edi
! MOV eax, ecx ; eax = ecx
! SAL eax, 2 ; eax * 4
! MOV dword[ebp+eax], ebx ; PokeL(ebp+eax, ebx)
! BSWAP ebx ; ebx (00RRGGBB) => (BBGGRR00)
! SAR ebx, 8 ; ebx(BBGGRR00) => (00BBGGRR)
! MOV eax,dword[v_BufferAddress] ; eax = @BufferAddress
! MOV [eax], ebx ; PokeL(eax, ebx)
! ADD dword[v_BufferAddress], 4 ; BufferAddress + 4
! INC dword[v_ArrayAddress] ; ArrayAddress + 1
! INC dword[v_x] ; x + 1
! MOV ebx, dword[v_x] ; ebx = x
! MOV edi, dword[v_DrawingWidth] ; edi = DrawingWidth
! DEC edi ; edi - 1
! CMP ebx, edi ; if ebx <= edi
! JLE _RepeatBN22 ; Goto RepeatBN22
! INC dword[v_ArrayAddress] ; ArrayAddress + 1
! MOV ebx, dword[v_DrawingWidth] ; ebx = DrawingWidth
! DEC ebx ; ebx - 1
! SAL ebx, 2 ; ebx / 4
! NEG ebx ; -ebx
! ADD ebx, dword[v_DrawingBufferPitch] ; ebx + DrawingBufferPitch
! ADD dword[v_BufferAddress], ebx ; BufferAddress + ebx
! INC dword[v_y] ; y + 1
! MOV edi, dword[v_DrawingHeight] ; edi = DrawingHeight
! ADD edi, -1 ; edi - 1
! MOV ebx, dword[v_y] ; ebx = y
! CMP ebx, edi ; if ebx <= edi
! JLE _RepeatBN21 ; Goto RepeatBN21
EndSelect
;
; Keyboard events part
;============================
; Section de gestion des évènements clavier
;
ExamineKeyboard()
; Change the code part to execute
; Modifie la section de code à exécuter
If KeyboardPushed(#PB_Key_Left)
ResetAll()
ExecuteCode - 1
If ExecuteCode < 0
ExecuteCode = 0
EndIf
Repeat
ExamineKeyboard()
Until KeyboardReleased(#PB_Key_Left)
EndIf
If KeyboardPushed(#PB_Key_Right)
ResetAll()
ExecuteCode + 1
If ExecuteCode > #LastCode
ExecuteCode = #LastCode
EndIf
Repeat
ExamineKeyboard()
Until KeyboardReleased(#PB_Key_Right)
EndIf
; Set / Unset the buffers synchronization
; Valide / invalide la synchronisation des buffers
If KeyboardPushed(#PB_Key_Up)
ResetAll()
FlipBuffers = 1 - FlipBuffers
Repeat
ExamineKeyboard()
Until KeyboardReleased(#PB_Key_Up)
EndIf
If KeyboardPushed(#PB_Key_Down)
ResetAll()
FlipBuffers = 1 - FlipBuffers
Repeat
ExamineKeyboard()
Until KeyboardReleased(#PB_Key_Down)
EndIf
; Change the drawing area size
; Modifie la taille de la zone de dessin
If KeyboardPushed(#PB_Key_Pad4)
ResetAll()
WidthHeight - 1
If WidthHeight < 0
WidthHeight = 0
EndIf
Repeat
ExamineKeyboard()
Until KeyboardReleased(#PB_Key_Pad4)
DrawingWidth = DrawingWidth(WidthHeight)
DrawingHeight = DrawingHeight(WidthHeight)
xTop = (ScreenXSize - DrawingWidth) / 2 + 1
yTop = (ScreenYSize - DrawingHeight) / 2 + 1
xBottom = xTop + DrawingWidth - 2
yBottom = yTop + DrawingHeight - 2
EndIf
If KeyboardPushed(#PB_Key_Pad6)
ResetAll()
WidthHeight + 1
If WidthHeight > LastSize
WidthHeight = LastSize
EndIf
Repeat
ExamineKeyboard()
Until KeyboardReleased(#PB_Key_Pad6)
DrawingWidth = DrawingWidth(WidthHeight)
DrawingHeight = DrawingHeight(WidthHeight)
xTop = (ScreenXSize - DrawingWidth) / 2 + 1
yTop = (ScreenYSize - DrawingHeight) / 2 + 1
xBottom = xTop + DrawingWidth - 2
yBottom = yTop + DrawingHeight - 2
EndIf
; Control the elapsed time since the last integer second
; Contrôle le temps écoulé depuis la dernière seconde entière
If ElapsedMilliseconds() - tz => 1000
tz = ElapsedMilliseconds()
FPS = NFrames
TFrames + FPS
NFrames = 0
AFrames + 1
EndIf
NFrames + 1
; Display statistics and parameters
; Affiche les statistiques et les paramètres
BackColor(0)
FrontColor(RGB(255, 255, 255))
DrawText(10, 40, "FPS " + Str(FPS) + " Average : " + StrF(TFrames / AFrames, 2))
DrawText(10, 60, CodeType(ExecuteCode) + " ")
DrawText(10, 80, "FlipBuffers(" + Str(FlipBuffers) + ")")
DrawText(10, 100, Str(DrawingWidth) + "x" + Str(DrawingHeight))
StopDrawing()
Until KeyboardReleased(#PB_Key_Escape)
EndIf
End
DataSection
Data.s "#PureBasic_Regular_Code", "#PureBasic_Better_Code", "#PureBasic_Optimized_Code", "#PureBasic_LowLevel_Code"
Data.s "#PureBasic_Chewed_Code", "#ASM_Code", "#PureBasic_LowLevel_Code2", "#ASM_LowLevel_Code2"
Data.l 128, 128
Data.l 256, 256
Data.l 320, 240
Data.l 480, 360
Data.l 640, 480
Data.l 800, 600
EndDataSection
"Menschenskinder, das Niveau dieses Forums singt schon wieder!" — GronkhLP ||| "ich hogffe ihr könnt den fehle endecken" — Marvin133 ||| "Ideoten gibts ..." — computerfreak ||| "Jup, danke. Gruss" — funkheld
-
- Beiträge: 180
- Registriert: 24.09.2010 10:39
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
@ts-soft
Ich glaube eine Möglichkeit zur Beschleunigung mit Pointern habe ich schon mal gefunden. Ich beschreib sie mal falls andere, die neu bei PB sind, das auch noch nicht wissen.
Ich habe mir wegen deinem Hinweis auf Pointer das Tutorial über Pointer durchgelesen was es hier gibt: http://www.purearea.net/pb/english/tutorials.htm
Allerdings wurde dort nicht auf Geschwindigkeit eingegangen.
In den Bereichen wo es in meinem Code auf Geschwindigkeit ankommt ist mir auch nichts aufgefallen wie Pointer die Sache beschleunigen könnten. Bei einer nicht geschwindigkeitsrelevanten Funktion habe ich dann versucht statt eines Strings einen Pointer auf den String zu übergeben. Weil dann anstatt eines Strings nur ein Zeiger in der Funktion neu erstellt werden muss glaube ich.
Ich habe es dann getestet... OHNE DEBUGGER
und es scheint wie wenn die neue Version mit einem Pointer schneller ist. Etwa 3/8 der Zeit. Vermutlich weil keine String-Variable erstellt werden musste samt String kopieren sondern nur eine Pointervariable die eine Zahl ist.
Ich habe mich gefragt welchen Einfluss es hat dass ich bei Übergabe per Pointer den String ja vorher in einer Variable speichern muss um einen Pointer zu erhalten. Beim Testen schien mir dass, wenn ich den String direkt im Funktionsaufruf an die Prozedur übergebe es außerdem ein wenig mehr Zeit braucht als wenn der String per Variable übergeben wird, also vorher einer Variable zugewiesen wird.
Aus einer Ahnung hab ich dann die beiden Codeteile umgedreht in der Reihenfolge. Anstatt 800 für direkte Übergabe und 600 per Var wie vorher waren es dann 600 per Var und 350 direkt. Und das reproduzierbar wenn ich es wieder umdrehe. Vielleicht hängt das irgendwie mit Speicher zusammen der nach der ersten Funktion besser nutzbar ist für die folgende? Der Testcode per Pointer bleibt von seiner Position unbeeindruckt. Er bleibt gleich egal wo er in der Reihenfolge er steht... Auf jeden Fall ist die Pointerversion immer noch am schnellsten bei mir.
Mir scheint man muss viel austesten wenn es um Geschwindigkeit geht. Trotzdem braucht man erst die Ideen...
Der Testcode:
Ich glaube eine Möglichkeit zur Beschleunigung mit Pointern habe ich schon mal gefunden. Ich beschreib sie mal falls andere, die neu bei PB sind, das auch noch nicht wissen.
Ich habe mir wegen deinem Hinweis auf Pointer das Tutorial über Pointer durchgelesen was es hier gibt: http://www.purearea.net/pb/english/tutorials.htm
Allerdings wurde dort nicht auf Geschwindigkeit eingegangen.
In den Bereichen wo es in meinem Code auf Geschwindigkeit ankommt ist mir auch nichts aufgefallen wie Pointer die Sache beschleunigen könnten. Bei einer nicht geschwindigkeitsrelevanten Funktion habe ich dann versucht statt eines Strings einen Pointer auf den String zu übergeben. Weil dann anstatt eines Strings nur ein Zeiger in der Funktion neu erstellt werden muss glaube ich.
Ich habe es dann getestet... OHNE DEBUGGER

Ich habe mich gefragt welchen Einfluss es hat dass ich bei Übergabe per Pointer den String ja vorher in einer Variable speichern muss um einen Pointer zu erhalten. Beim Testen schien mir dass, wenn ich den String direkt im Funktionsaufruf an die Prozedur übergebe es außerdem ein wenig mehr Zeit braucht als wenn der String per Variable übergeben wird, also vorher einer Variable zugewiesen wird.
Aus einer Ahnung hab ich dann die beiden Codeteile umgedreht in der Reihenfolge. Anstatt 800 für direkte Übergabe und 600 per Var wie vorher waren es dann 600 per Var und 350 direkt. Und das reproduzierbar wenn ich es wieder umdrehe. Vielleicht hängt das irgendwie mit Speicher zusammen der nach der ersten Funktion besser nutzbar ist für die folgende? Der Testcode per Pointer bleibt von seiner Position unbeeindruckt. Er bleibt gleich egal wo er in der Reihenfolge er steht... Auf jeden Fall ist die Pointerversion immer noch am schnellsten bei mir.
Mir scheint man muss viel austesten wenn es um Geschwindigkeit geht. Trotzdem braucht man erst die Ideen...
Der Testcode:
Code: Alles auswählen
Procedure In2(ValueToCheck.i,*ValueString)
EndProcedure
starttime.i = ElapsedMilliseconds()
For x=0 To 2000000
s$ = "1,2,3,4,5,6,7,8"
in2(2,@s$)
Next
MessageRequester("",Str(ElapsedMilliseconds()-starttime))
Procedure In1(ValueToCheck.i,ValueString$)
EndProcedure
starttime.i = ElapsedMilliseconds()
For x=0 To 2000000
in1(2,"1,2,3,4,5,6,7,8")
Next
MessageRequester("",Str(ElapsedMilliseconds()-starttime))
Procedure In3(ValueToCheck.i,ValueString$)
EndProcedure
starttime.i = ElapsedMilliseconds()
For x=0 To 2000000
s$ = "1,2,3,4,5,6,7,8"
in3(2,s$)
Next
MessageRequester("",Str(ElapsedMilliseconds()-starttime))
- ts-soft
- Beiträge: 22292
- Registriert: 08.09.2004 00:57
- Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel - Wohnort: Berlin
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
Das ist ja nicht wirklich eine Optimierung.
Hier nochmal meine Escape-Sequenzen: http://www.purebasic.fr/german/viewtopi ... =8&t=11858
Schreib das mal um mit ReplaceString und prüfe dann!
Hier nochmal meine Escape-Sequenzen: http://www.purebasic.fr/german/viewtopi ... =8&t=11858
Schreib das mal um mit ReplaceString und prüfe dann!
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.

Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.

-
- Beiträge: 180
- Registriert: 24.09.2010 10:39
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
@ts-soft
Etwa 5 mal so langsam mit ReplaceString. Ich werd mir deinen Code mal ansehen und sehen was ich nachmachen kann.
@c4s
Beeindruckende Statistik wenn ich da nichts falsch interpretiere. Aber wenn ich mir dann den Code ansehe...
Leicht ist das vermutlich nicht zu lernen.
Etwa 5 mal so langsam mit ReplaceString. Ich werd mir deinen Code mal ansehen und sehen was ich nachmachen kann.
@c4s
Beeindruckende Statistik wenn ich da nichts falsch interpretiere. Aber wenn ich mir dann den Code ansehe...

-
- Beiträge: 557
- Registriert: 29.11.2005 15:05
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
na..., freebasic erreicht ca 95% der geschwindigkeit von c++, das noch... gfa32-basic erreicht ca 97% der geschwindigkeit von c++ und purebasic erreicht ca 82% der geschwindigkeit von c++...
gruss
gruss
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
Und deine Angaben beziehen sich auf was? Was für Algos werden da getestet? Oder saugst du dir das alles aus den Fingern?super_castle hat geschrieben:na..., freebasic erreicht ca 95% der geschwindigkeit von c++, das noch... gfa32-basic erreicht ca 97% der geschwindigkeit von c++ und purebasic erreicht ca 82% der geschwindigkeit von c++...
gruss

Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster
PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
-
- Beiträge: 180
- Registriert: 24.09.2010 10:39
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
Ja, gibt es den Code für den Test einzusehen? Es dürfte ja kein Anwendungsprogramm sein weil dann das eine oder andere mehr oder weniger optimiert sein könnte. Vermutlich müsste man einzelne Befehle mit Schleifen ausführen und davon ein möglichst breites Spektrum und dann schauen was am schnellsten ist. Aber ich denke trotzdem wird auf jeden Fall bei dem einen Befehl im Testprogramm mal die eine und beim nächsten wieder eine andere Sprache schneller sein.
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
Offtopic:

...Und diese Aussage ist nur annähernd 5% richtig. Zudem sind 98,76% deiner Beiträge Schwachfug.super_castle hat geschrieben:na..., freebasic erreicht ca 95% der geschwindigkeit von c++, das noch... gfa32-basic erreicht ca 97% der geschwindigkeit von c++ und purebasic erreicht ca 82% der geschwindigkeit von c++...
gruss

"Menschenskinder, das Niveau dieses Forums singt schon wieder!" — GronkhLP ||| "ich hogffe ihr könnt den fehle endecken" — Marvin133 ||| "Ideoten gibts ..." — computerfreak ||| "Jup, danke. Gruss" — funkheld
Re: PB im Vergleich mit anderen Sprachen in Bezug auf Speed
Optimist!c4s hat geschrieben:Offtopic:...Und diese Aussage ist nur annähernd 5% richtig. Zudem sind 98,76% deiner Beiträge Schwachfug.super_castle hat geschrieben:na..., freebasic erreicht ca 95% der geschwindigkeit von c++, das noch... gfa32-basic erreicht ca 97% der geschwindigkeit von c++ und purebasic erreicht ca 82% der geschwindigkeit von c++...
gruss