Passing array of struct to a threaded procedure

Just starting out? Need help? Post your questions and find answers here.
ker2x
User
User
Posts: 38
Joined: Sat May 10, 2008 7:52 am
Location: SecondLife

Passing array of struct to a threaded procedure

Post by ker2x »

Hello ! I can'tt make it works, i have an invalid memory access error.

Here is the definition

Code: Select all

Structure ExposureStruct
  R.f
  G.f
  B.f
  A.f
EndStructure

Global Dim exposure.ExposureStruct(screenSize2)


In the main code i call the thread :

Code: Select all

CreateThread(@iterateThread(), exposure())
Here is the procedure :

Code: Select all

Procedure iterateThread(Array exposure.ExposureStruct(1))
  
  Define.f x = 0.0
  Define.f y = 0.0
  Define.f xnew ;= 0.0
  Define.f ynew ;= 0.0
  Define.f ix   ;= 0
  Define.f iy   ;= 0
  Define.u i
  ;Define.f originX, originY
  ;Define.f cR, cG, cB
  
  Repeat
    
    Define.f x0 = (Random(#RandMax)/(#RandMaxBy4)) - 2.0
    Define.f y0 = (Random(#RandMax)/(#RandMaxBy4)) - 2.0
    
    If(isInMSet(x0, y0) = 0)
      
      x = 0.0
      y = 0.0 
      For i = 0 To bailout
        exposures+1
        xnew = (x * x) - (y * y) + x0
        ynew = 2 * (x*y) + y0
        
        If ((i > miniter))
          ix = Int(screenSize * (xnew + 2.25) / 3.5)
          iy = Int(screenSize * (ynew + 1.5) / 3.0)
          If ((xnew*xnew + ynew*ynew) > 4)
            Break
          EndIf
          If ((ix >= 0) And (iy >= 0) And (ix < screenSize) And (iy < screenSize))
            Define.l pos = ix*screenSize+iy
            Debug i
            If ((i < bailoutRmax) And (i > bailoutRmin)) : exposure(pos)\R+1 : EndIf  ; <- FAIL WITH INVALID MEMORY ACCESS
            If ((i < bailoutGmax) And (i > bailoutGmin)) : exposure(pos)\G+1 : EndIf
            If ((i < bailoutBmax) And (i > bailoutBmin)) : exposure(pos)\B+1 : EndIf
          EndIf
        EndIf
        
        
        x = xnew
        y = ynew
      Next i
      
    EndIf
    
  ForEver
  
  ProcedureReturn 0
EndProcedure

The non-threaded version, with a function without argument (the array is global) is working and i checked that pos isn't out of bound.
Any idea ?
ker2x
User
User
Posts: 38
Joined: Sat May 10, 2008 7:52 am
Location: SecondLife

Re: Passing array of struct to a threaded procedure

Post by ker2x »

Sure, as soon as i ask i find the solution ^^
(i'm on it since 1h ...)

Code: Select all

Procedure iterateThread(Array *exposure.ExposureStruct(1))
ker2x
User
User
Posts: 38
Joined: Sat May 10, 2008 7:52 am
Location: SecondLife

Re: Passing array of struct to a threaded procedure

Post by ker2x »

The full code. It's ugly and in progress :)
(but it produce a nice fractal)

Code: Select all

;
; Buddhabrot generator

EnableExplicit


;RunProgram(#PB_Compiler_Home+"\Compilers\pbcompiler.exe",  Chr(34)+ "E:\purebasic\buddhabrot3\main.pb" + Chr(34) + " /COMMENTED /SSE2 /EXE " + Chr(34)+ "E:\purebasic\buddhabrot3\buddha3.exe" +Chr(34) , "", #PB_Program_Open|#PB_Program_Read|#PB_Program_Hide)
;RunProgram(#PB_Compiler_Home+"\Compilers\pbcompiler.exe",  Chr(34)+ "E:\purebasic\buddhabrot3\main.pb" + Chr(34) + " /REASM /SSE2 /EXE " + Chr(34)+ "E:\purebasic\buddhabrot3\buddha3.exe" +Chr(34) , "", #PB_Program_Open|#PB_Program_Read|#PB_Program_Hide)
;Return

Define.q StartTime ;= ElapsedMilliseconds() 
StartTime = ElapsedMilliseconds() 

#plots = 100000
#RandMax = 2147483647 
#RandMaxBy4 = 536870911



; Define constant
Global.u screenSize = 1200
Global.l screenSize2 = screenSize * screenSize
Global.u bailout =  1000
;
Global.u bailoutRmin = 100
Global.u bailoutRmax = 150
;
Global.u bailoutBmin = 100
Global.u bailoutBmax = 500

Global.u bailoutGmin = 400
Global.u bailoutGmax = 1000

;
Global.u miniter = 0
;Global.l plots = 100000
Global.l RandMax = 2147483647 
Global.l RandMaxBy4 = 536870911

; Define global var
Global.f maxexposure = 0
Global.f maxexposureR = 0
Global.f maxexposureG = 0
Global.f maxexposureB = 0
Global.q exposures = 0
Global.l performance = 0

Global.i Buffer
Global.i Pitch
Global.i PixelFormat
Global.i refresh = 0

;Define.q screeno
Define.q i

Structure ExposureStruct
  R.f
  G.f
  B.f
  A.f
EndStructure

Structure RandomStruct
  x.f
  y.f
EndStructure

Structure Pixel
  Pixel.l
EndStructure

Define *Line.Pixel

Global Dim exposure.ExposureStruct(screenSize2)

;Threaded Dim randomBuffer.RandomStruct(#plots)

; Generate a random number
Procedure.f mrdrand()
  Define r.f
  Define d.f = 536870911
  Define two.f = 2
  ;r = ((Random(2147483647)/(536870911)) - 2.0)
  ;ProcedureReturn r
  ;EnableASM
  EnableASM
  ! RDRAND eax
  ! MOV dword [p.v_r], eax
  ! FILD dword [p.v_r]
  ! FDIV dword [p.v_d]
  ! FSUB dword [p.v_two]
  ! FST dword [p.v_d]
  ! MOV EAX, [p.v_d]
  DisableASM
  ProcedureReturn
  
  ;ProcedureReturn ((Random(2147483647)/(536870911)) - 2.0)
  
EndProcedure

; Check if point is in Mandelbrot Set
Procedure isInMSet(xi.f, yi.f)
  Define.f x ;= 0.0
  Define.f y ;= 0.0
  Define.f xnew ;= 0.0
  Define.f ynew ;= 0.0
  Define.u i
  Define.f q = (xi-0.25)*(xi-0.25) + (yi*yi)
  
  ;Quick rejection check If point is in main cardioid
  If( q*(q+(xi-0.25)) < 0.25*(yi*yi))
    ProcedureReturn 1
  EndIf
  
  ;Quick rejection check If point is in 2nd order period bulb
  If ( (xi+1.0) * (xi+1.0) + yi*yi < 0.0625)
    ProcedureReturn 1
  EndIf
  
  ;test For the smaller bulb left of the period-2 bulb
  If (( ((xi+1.309)*(xi+1.309)) + yi*yi) < 0.00345)
    ProcedureReturn 1
  EndIf
  
  ;check For the smaller bulbs on top And bottom of the cardioid
  If ((((xi+0.125)*(xi+0.125)) + (yi-0.744)*(yi-0.744)) < 0.0088)
    ProcedureReturn 1
  EndIf
  
  If ((((xi+0.125)*(xi+0.125)) + (yi+0.744)*(yi+0.744)) < 0.0088)
    ProcedureReturn 1
  EndIf
  
  For i = 0 To bailout
    xnew = (x*x) - (y*y) + xi
    y = 2 * (x*y) + yi
    x = xnew
    If ((x*x + y*y) > 4) : ProcedureReturn 0 : EndIf
  Next i
  ProcedureReturn 1
EndProcedure



; Iterate and draw the orbit
Procedure iterate(x0.f, y0.f)
  
  Define.f x = 0.0
  Define.f y = 0.0
  Define.f xnew ;= 0.0
  Define.f ynew ;= 0.0
  Define.f ix   ;= 0
  Define.f iy   ;= 0
  Define.u i
  Define.f originX, originY
  Define.f cR, cG, cB
  
;   originX = Int(screenSize * (x0 + 2.25) / 3.5)
;   originY = Int(screenSize * (y0 + 1.5) / 3.0)
;   cR = originX / (screenSize)
;   cB = originY / (screenSize)
;   cG = (originX + originY) / (screenSize*2)
;   
  For i = 0 To bailout
    exposures+1
    xnew = (x * x) - (y * y) + x0
    ynew = 2 * (x*y) + y0
    
    If ((i > miniter))
      ix = Int(screenSize * (xnew + 2.25) / 3.5)
      iy = Int(screenSize * (ynew + 1.5) / 3.0)
      If ((ix >= 0) And (iy >= 0) And (ix < screenSize) And (iy < screenSize))
        Define.l pos = ix*screenSize+iy
        If ((i < bailoutRmax) And (i > bailoutRmin)) : exposure(pos)\R+1 : EndIf
        If ((i < bailoutGmax) And (i > bailoutGmin)) : exposure(pos)\G+1 : EndIf
        If ((i < bailoutBmax) And (i > bailoutBmin)) : exposure(pos)\B+1 : EndIf
      EndIf
    EndIf
    
    If ((xnew*xnew + ynew*ynew) > 4)
      ProcedureReturn 1
    EndIf
    x = xnew
    y = ynew
  Next i
  
  ProcedureReturn 0
EndProcedure

Procedure iterateThread(Array *exposure.ExposureStruct(1))
  
  Define.f x = 0.0
  Define.f y = 0.0
  Define.f xnew ;= 0.0
  Define.f ynew ;= 0.0
  Define.f ix   ;= 0
  Define.f iy   ;= 0
  Define.u i
  ;Define.f originX, originY
  ;Define.f cR, cG, cB
  
  Repeat
    
    Define.f x0 = mrdrand() ;(Random(#RandMax)/(#RandMaxBy4)) - 2.0
    Define.f y0 = mrdrand() ;(Random(#RandMax)/(#RandMaxBy4)) - 2.0
    
    If(isInMSet(x0, y0) = 0)
      
      x = 0.0
      y = 0.0 
      For i = 0 To bailout
        exposures+1
        xnew = (x * x) - (y * y) + x0
        ynew = 2 * (x*y) + y0
        
        If ((i > miniter))
          ix = Int(screenSize * (xnew + 2.25) / 3.5)
          iy = Int(screenSize * (ynew + 1.5) / 3.0)
          If ((xnew*xnew + ynew*ynew) > 4)
            Break
          EndIf
          If ((ix >= 0) And (iy >= 0) And (ix < screenSize) And (iy < screenSize))
            Define.l pos = ix*screenSize+iy
            Debug i
            If ((i < bailoutRmax) And (i > bailoutRmin)) : exposure(pos)\R+1 : EndIf
            If ((i < bailoutGmax) And (i > bailoutGmin)) : exposure(pos)\G+1 : EndIf
            If ((i < bailoutBmax) And (i > bailoutBmin)) : exposure(pos)\B+1 : EndIf
          EndIf
        EndIf
        
        
        x = xnew
        y = ynew
      Next i
      
    EndIf
    
  ForEver
  
  ProcedureReturn 0
EndProcedure



; Generate a random buffer continuously
Procedure randomGenerator(*Value)
  Define k, j
  Define *pointeur.randomStruct = *Value
  
  Repeat
    *pointeur.randomStruct = *Value
    For k = 0 To #plots
      *pointeur\x = (Random(#RandMax)/(#RandMaxBy4)) - 2.0;
      *pointeur\y = (Random(#RandMax)/(#RandMaxBy4)) - 2.0;
      *pointeur + SizeOf(randomStruct)
    Next k
  ForEver  
EndProcedure





; MAIN
; initialize the sprite engine
If InitSprite() = 0
  MessageRequester("Error", "Can't open screen & sprite enviroment!", 0)
  End
EndIf

; open window
If OpenWindow(0, 0, 0, screenSize, screenSize, "Buddhabrot", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If OpenWindowedScreen(WindowID(0), 0, 0, screenSize, screenSize, 0, 0, 0, #PB_Screen_NoSynchronization)
    CreateImage(0,screenSize,screenSize,32)
    If StartDrawing(ScreenOutput())
      Buffer      = DrawingBuffer()             ; Get the start address of the screen buffer
      Pitch       = DrawingBufferPitch()        ; Get the length (in byte) took by one horizontal line
      PixelFormat = DrawingBufferPixelFormat()  ; Get the pixel format. 
      StopDrawing()
    EndIf
  Else
    MessageRequester("Error", "Can't open windowed screen!", 0)
    End
  EndIf
EndIf



; Local var
Define.i Event
Define.l k
Define.u x
Define.u y

Define.f x0
Define.f y0
Define.f ramp
Define.l rampR
Define.l rampG
Define.l rampB

Define.l pos

;CreateThread(@randomGenerator(), @randomBuffer())
CreateThread(@iterateThread(), exposure())
CreateThread(@iterateThread(), exposure())
CreateThread(@iterateThread(), exposure())
CreateThread(@iterateThread(), exposure())
CreateThread(@iterateThread(), exposure())
CreateThread(@iterateThread(), exposure())

Repeat
  
  Repeat
    Event = WindowEvent()
    Select Event 
      Case #PB_Event_CloseWindow
        ;    FreeMemory(*RandomBuffer)
        End 
    EndSelect
  Until Event = 0
  
;   For k = 0 To #plots
;     x0 = randomBuffer(k)\x
;     y0 = randomBuffer(k)\y
;     If(isInMSet(x0,y0) = 0)
;       iterate(x0,y0)
;     EndIf
;   Next k
  
  refresh+1
  
  ;If((refresh % 100) = 0)
  Delay(1000)
    
    refresh = 0
    
    ;findMaxExposure()
    For i = 0 To screenSize2
      If (exposure(i)\R > maxexposureR) : maxexposureR = exposure(i)\R : EndIf
      If (exposure(i)\G > maxexposureG) : maxexposureG = exposure(i)\G : EndIf
      If (exposure(i)\B > maxexposureB) : maxexposureB = exposure(i)\B : EndIf
    Next i
    
    StartDrawing(ScreenOutput())
    
    For x = 0 To screenSize -1
      *Line.Pixel = Buffer+Pitch*x
      For y = 0 To screenSize - 1
        pos = x*screenSize+y
        
         rampR = exposure(pos)\R / (maxexposureR / 3.0) * 255
         rampG = exposure(pos)\G / (maxexposureG / 3.0) * 255
         rampB = exposure(pos)\B / (maxexposureB / 3.0) * 255
         
       
        If (rampR > 255) : rampR = 255 : EndIf
        If (rampG > 255) : rampG = 255 : EndIf
        If (rampB > 255) : rampB = 255 : EndIf
        
        *Line\Pixel = rampB + (rampG << 8) + (rampR << 16)
        *Line+4
      Next y
    Next x
    
    
    performance =  exposures / (ElapsedMilliseconds() - StartTime) 
    DrawText(0,0, "(Bailout : " + Str(bailout) + ")   (millions of Iterations : " + Str(exposures / 1000000.0) + ")    (iterations/ms : " + Str(performance) + ")", RGB(255,255,255))
    StopDrawing()
    FlipBuffers() 
  ;EndIf
  
ForEver



ker2x
User
User
Posts: 38
Joined: Sat May 10, 2008 7:52 am
Location: SecondLife

Re: Passing array of struct to a threaded procedure

Post by ker2x »

i know there is no lock on the array, it produce slightly inaccurate (imperceptible) result but that's on purpose.
It's massive performance tradeoff (i have a C++ version of this code that was profiled with Intel VTune)
Post Reply