Page 1 sur 1
multiple coeurs
Publié : ven. 28/févr./2014 11:38
par zazoux
Bonjour,
j'aimerais savoir si en Purebasic il est possible de gerer le nombre de cooeurs du processeur, ou au moins établir à participer au déroulement du programme tous les coeurs disponibles. Et si oui, dans quel menu ça se passe ?
Merci en avance pour vos éclaircissements
Re: multiple coeurs
Publié : ven. 28/févr./2014 12:15
par Mesa
J'avais trouvé ça quelque part dans le forum anglais, il y a 3 ou 4 ans.
Code : Tout sélectionner
;ATTENTION METTRE MULTITHREAD DANS LE COMPILATEUR
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows ;{
Global Total_CPU = Val(GetEnvironmentVariable("NUMBER_OF_PROCESSORS"))-1
;}
CompilerCase #PB_OS_Linux ;{
grep = RunProgram("grep","-c processor /proc/cpuinfo","./",#PB_Program_Open|#PB_Program_Read)
If grep
Sortie$ + ReadProgramString(grep) + Chr(13)
Global Total_CPU = Val(Sortie$)-1
EndIf
;}
CompilerEndSelect
Global wait_thread = CreateSemaphore()
Global mutex = CreateMutex()
Macro P_For(variable, start)
For variable=start+core
EndMacro
Macro P_Next(variable)
variable+Total_CPU
Next variable
EndMacro
Structure ParallelFor
thread.i
core.i
parent.i
wait.b
return_procedure.i
EndStructure
Global NewList Working_Threads.ParallelFor()
Prototype ProtoLoop(core, parametre)
Global Loop.ProtoLoop
Procedure WorkerThread(parametre)
thread_id = Working_Threads()\thread
core = Working_Threads()\core
wait = Working_Threads()\wait
SignalSemaphore(wait_thread)
Resultat = Loop(core, parametre)
;Fin du thread
LockMutex(mutex)
ForEach Working_Threads()
If Working_Threads()\thread = thread_id
If wait = #False
;efface le thread
DeleteElement(Working_Threads())
Break
Else
;procedure return
If Working_Threads()\return_procedure = 0
Working_Threads()\return_procedure = Resultat
Break
EndIf
EndIf
EndIf
Next
UnlockMutex(mutex)
EndProcedure
Procedure ParallelFor(id, wait.b, *procedure_ptr, parametre)
Loop.ProtoLoop = *procedure_ptr
LockMutex(mutex)
For x=0 To Total_CPU
AddElement(Working_Threads())
Working_Threads()\core = x
Working_Threads()\thread = CreateThread(@WorkerThread(), parametre)
Working_Threads()\parent = id
Working_Threads()\wait = wait
If x=0
first_thread = Working_Threads()\thread
EndIf
WaitSemaphore(wait_thread)
Next x
UnlockMutex(mutex)
If wait = #True
For x=0 To Total_CPU
WaitThread(first_thread+x)
Next x
;procedurereturn et efface les threads
LockMutex(mutex)
ForEach Working_Threads()
If Working_Threads()\parent = id
Resultat = Working_Threads()\return_procedure
If Resultat
return_procedure = Resultat
EndIf
DeleteElement(Working_Threads())
EndIf
Next
UnlockMutex(mutex)
ProcedureReturn return_procedure
Else
ProcedureReturn id
EndIf
EndProcedure
Procedure IsParallelFor(id)
LockMutex(mutex)
ForEach Working_Threads()
If Working_Threads()\parent = id
ProcedureReturn 1
EndIf
Next
UnlockMutex(mutex)
EndProcedure
Procedure KillParallelFor(id)
LockMutex(mutex)
ForEach Working_Threads()
If Working_Threads()\parent = id
KillThread(Working_Threads()\thread)
DeleteElement(Working_Threads())
EndIf
Next
UnlockMutex(mutex)
EndProcedure
Procedure PauseParallelFor(id)
LockMutex(mutex)
ForEach Working_Threads()
If Working_Threads()\parent = id
PauseThread(Working_Threads()\thread)
EndIf
Next
UnlockMutex(mutex)
EndProcedure
Procedure ResumeParallelFor(id)
LockMutex(mutex)
ForEach Working_Threads()
If Working_Threads()\parent = id
ResumeThread(Working_Threads()\thread)
EndIf
Next
UnlockMutex(mutex)
EndProcedure
;---------------------------------
;IncludeFile "Multicore.pbi"
Structure zbuffer
*depth_buffer;.i
w.l
h.l
EndStructure
ProcedureDLL.i zbuffer(w.l, h.l, mFar.f)
*zb.zbuffer = AllocateMemory(SizeOf(zbuffer))
*zb\depth_buffer = AllocateMemory( w * h * 4 )
*zb\w = w
*zb\h = h
FillMemory(*zb\depth_buffer , MemorySize(*zb\depth_buffer), mFar, #PB_Long)
ProcedureReturn *zb
EndProcedure
ProcedureDLL zbuffer_write(*zb.zbuffer)
For i = 0 To 50
For y = 0 To 480-1
For x = 0 To 640
If x=>0 And x < *zb\w And y=>0 And y < *zb\h
PokeF(*zb\depth_buffer + (x*4) + *zb\w * (y*4), Random(1500))
EndIf
Next
Next
Next
EndProcedure
ProcedureDLL zbuffer_write_multi(core, *zb.zbuffer)
P_For(i, 0) To 50
For y=0 To 480-1
For x=0 To 640
If x=>0 And x < *zb\w And y=>0 And y < *zb\h
PokeF(*zb\depth_buffer + (x*4) + *zb\w * (y*4), Random(1500))
EndIf
Next x
Next y
P_Next(i)
EndProcedure
Buffer = zbuffer(640,480,1500)
;Single thread
A = ElapsedMilliseconds()
zbuffer_write(Buffer)
B = ElapsedMilliseconds()
WriteTime = B-A
MessageRequester("Single thread", Str(WriteTime))
;Multi thread
A = ElapsedMilliseconds()
ParallelFor(0, #True, @zbuffer_write_multi(), Buffer)
B = ElapsedMilliseconds()
WriteTime = B-A
MessageRequester("Multi thread", Str(WriteTime))
M.
Re: multiple coeurs
Publié : ven. 28/févr./2014 13:57
par djes
Un petit commentaire vite fait, car ça m'arrache les yeux :
Code : Tout sélectionner
ProcedureDLL zbuffer_write_multi(core, *zb.zbuffer)
P_For(i, 0) To 50
For y=0 To 480-1
For x=0 To 640
If x=>0 And x < *zb\w And y=>0 And y < *zb\h
PokeF(*zb\depth_buffer + (x*4) + *zb\w * (y*4), Random(1500))
EndIf
Next x
Next y
P_Next(i)
EndProcedure
Il y a là matière à une foule d'optims qui devraient être naturelles pour le codeur, en plus il y a des erreurs. Déjà, quand il y a des *4, on sait qu'il va y avoir de l'optim. On pourrait faire la multiplication dans le "for" une fois pour toutes. En plus le buffer est dépassé (y'a clairement un bug!!!), alors il met une horrible condition
répétée à chaque itération!!!!!!! Si on sait la taille de son buffer, il n'y a pas à mettre de condition, c'est inutile et coûteux en terme de performances. Enfin voilà quoi, un peu de qualité dans le code SVP...
