2 Exen paralel rechnen lassen

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

 

PhillipK

Betreff: 2 Exen paralel rechnen lassen

BeitragSo, Sep 18, 2011 7:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Heyho! Smile

Es ist meines wissens nach nicht möglich, einen Dualcore zb mit Blitzmax auszunutzen.
Nun hatte ich, mehr als nette idee, weniger ein wirkliches vorhaben, die überlegung angestellt, das man berechnungen etc die nicht wirklich wichtig aber leistungsfressend sind, auf ein weiteres programm auszulagern.

Dazu bräuchte man "nur" die möglichkeit, 2 exen miteinander kommunizieren zu lassen.
Gibt es einen solchen weg, möglichst ohne TCP Stream?

Mein erster, noobischer, ansatz, war die idee, ptr als parameter an exen zu übergeben, das scheinen aber keine tatsächlichen mempointer zu sein. Naja seis drum, gibt sicher noch andere wege.. Mein blick fällt da insbesondere auf DLL's oder C/C++ funktionen, mit denen man den RAM auslesen kann.

Grobe idee zusammengefasst:

Bei spielen hat man ein Programm, welches sich um Grafik etc kümmert. Nebenher läuft allerdings noch eine Landschafts-update-exe.
Diese verwendet kaum/kein eigenen speicher, sondern agiert nur über mempointer, die man ihm irgendwei (vielleicht als Parameter beim exen' start? Very Happy) mitgegeben hat.
Diese 2te exe berechnet nun schonmal nebenher unter gleichmäßiger ausnutzung eines 2ten Core's ein geplantes update.

Oder auch:
Man hat sich ein paar Schöne surface's mit landschaftsteilen gebaut und möchte diese nun updaten. Jede surface von nur einem Core misshandeln zu lassen könnte ein paar fps einbrüche bringen. Für sowas könnte man nun zb jede 2te surface der anderen Exe überlassen um usern, die einen DualCore (oder mehr kerne, allerdings üwrde diese idee nur 1-2 nutzen) zu entlasten.

Allerdings ist es grade bei solchen vorhaben äussert wichtig, das man mit Pointern arbeiten kann. Erstmal groß die daten hin und herzu schieben und im Mainprogramm immer brav die antworten abfangen (Dh also TCP/UDP lokale verbindung) würde warhscheinlich mehr leistung ziehen als man im endeffekt gutmachen könnte.

Irgendwelche vorschläge zum speicher auslesen und wrappen auf blitzmax? Smile

BladeRunner

Moderator

BeitragSo, Sep 18, 2011 9:01
Antworten mit Zitat
Benutzer-Profile anzeigen
BMax ist seit einiger Zeit mit einem Modul für Multithreading versehen, Du kannst also threads etc. erstellen. Man sollte der Fairness halber erwähnen dass es nicht das ausgereifteste aller Module ist.
Aber dennoch kann man mit Max Mehrkerner beschäftigen Wink
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

PhillipK

BeitragSo, Sep 18, 2011 9:14
Antworten mit Zitat
Benutzer-Profile anzeigen
o.O

Meinst du die Build-option? "Build Threaded"? Smile

Die habe ich noch nie zum laufen gekreigt.. aber vllt fehlt auch ein entsprechender Import.

Das wäre dann wieder ein punkt den man sich anschauen könnte Very Happy Nichts desto trotz, die idee 2 Exen miteinander arbeiten zu lassen Fasziniert mich schon länger, hier bin ich auch für vorschläge offen Smile

ZEVS

BeitragSo, Sep 18, 2011 11:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Was du suchst ist eine sog. named Pipe. Würde ich als experimentell durchgehen lassen, das mit bMax zu probieren, aber man kann es ja mal versuchen. Threads scheinen mir aber angebrachter.

ZEVS

Der Eisvogel

BeitragSo, Sep 18, 2011 12:52
Antworten mit Zitat
Benutzer-Profile anzeigen
Zu Named Pipes: EPS hat da mal was geschrieben gehabt für Blitz3D. Da ich das auch letztens mal für irgendwas gebraucht hatte, hab ich mir das für BlitzMax als Modul geschrieben:
BlitzMax: [AUSKLAPPEN]
SuperStrict

Rem
bbdoc: NamedPipe
End Rem

Module eisvogel.namedpipe

ModuleInfo "Version: 1.00"
ModuleInfo "Author: Marc-Peter Eisinger"
ModuleInfo "License: Open Source"
ModuleInfo "Copyright: Eisvogel, Marc-Peter Eisinger 2010"


Import brl.retro


Extern "Win32"
Function pipe_MulDiv:Int(nNumber:Byte Ptr, nNumerator:Int, nDenominator:Int) = "MulDiv@12"
Function pipe_CloseHandle:Int(hObject:Int) = "CloseHandle@4"

Function pipe_PeekNamedPipe:Int(hNamedPipe:Int, lpBuffer:Byte Ptr, nBufferSize:Int, lpBytesRead:Int, lpTotalBytesAvail:Byte Ptr, lpBytesLeftThisMessage:Int) = "PeekNamedPipe@24"
Function pipe_CreateNamedPipe:Int(lpName:Byte Ptr, dwOpenMode:Int, dwPipeMode:Int, nMaxInstances:Int, nOutBufferSize:Int, nInBufferSize:Int, nDefaultTimeOut:Int, lpSecurityAttributes:Int) = "CreateNamedPipeA@32"
Function pipe_WaitNamedPipe:Int(lpNamedPipeName:Byte Ptr, nTimeOut:Int) = "WaitNamedPipeA@8"
Function pipe_DisconnectNamedPipe:Int(hNamedPipe:Int) = "DisconnectNamedPipe@4"

Function pipe_ReadFile:Int(hFile:Int, lpBuffer:Byte Ptr, nNumberOfBytesToRead:Int, lpNumberOfBytesRead:Byte Ptr, lpOverlapped:Byte Ptr) = "ReadFile@20"
Function pipe_WriteFile:Int(hFile:Int, lpBuffer:Byte Ptr, nNumberOfBytesToWrite:Int, lpNumberOfBytesWritten:Byte Ptr, lpOverlapped:Byte Ptr) = "WriteFile@20"
Function pipe_CreateFile:Int(lpFileName:Byte Ptr, dwDesiredAccess:Int, dwShareMode:Int, lpSecurityAttributes:Int, dwCreationDisposition:Int, dwFlagsAndAttributes:Int, hTemplateFile:Int) = "CreateFileA@28"
End Extern



' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
' NamedPipe
'==============================================================================================================

Global hPipe:Int '--> Handle auf die Pipe

Global lpSec:Byte Ptr = MemAlloc(12)
Global lpTotalBytesAvail:Byte Ptr = MemAlloc(4)
Global lpBytesRead:Byte Ptr = MemAlloc(4)
Global lpOverlapped:Byte Ptr = MemAlloc(20)
Global lpNumberOfBytesWritten:Byte Ptr = MemAlloc(4)



Function Pipe_Create:Int(name:String)
'==============================================================================================================
' Erstellt einen Server und öffnet eine Pipe.
'==============================================================================================================
Local retval:Int

If hPipe <> 0 Then DebugLog "Verbindung zu einer Pipe besteht noch." ; Return False

retval = pipe_CreateNamedPipe("\\.\pipe\" + name, $3, 0, 1, 2048, 2048, 100, Pipe_Pointer(lpSec))
If retval <> - 1 Then hPipe = retval ; Return True

Return False
End Function



Function Pipe_Write:Int(txt:String)
'==============================================================================================================
' Schreibt Nachricht in die Pipe.
'==============================================================================================================
If hPipe = 0 Then DebugLog "Keine Pipe zum Schreiben vorhanden." ; Return False

Local lBytesToWrite:Int = Len(txt:String)
Local otbuf:Byte Ptr = MemAlloc(lBytesToWrite)

For Local i:Int = 1 To lBytesToWrite
otbuf[i - 1] = Asc(Mid(txt, i, 1))
Next

pipe_WriteFile(hPipe, otbuf, lBytesToWrite, lpNumberOfBytesWritten, Byte Ptr(Pipe_Pointer(lpOverlapped)))

MemFree(otbuf)
Return True
End Function


Function Pipe_Read:String()
'==============================================================================================================
' Liest Nachricht von der Pipe.
'==============================================================================================================
Local retval:Int
Local txt:String
Local inbuf:Byte Ptr

If hPipe = 0 Then DebugLog "Keine Pipe zum Lesen vorhanden." ; Return ""

retval = pipe_PeekNamedPipe(hPipe, Null, 0, 0, lpTotalBytesAvail, 0)

If retval <> 0 And Int Ptr(lpTotalBytesAvail)[0] > 0 Then
inbuf = MemAlloc(Int Ptr(lpTotalBytesAvail)[0])
pipe_ReadFile(hPipe, inbuf, Int Ptr(lpTotalBytesAvail)[0], lpBytesRead, Byte Ptr(Pipe_Pointer(lpOverlapped)))
For Local i:Int = 1 To Int Ptr(lpTotalBytesAvail)[0]
txt = txt + Chr(inbuf[i - 1])
Next
MemFree(inbuf)
EndIf

Return txt
End Function



Function Pipe_Connect:Int(name:String)
'==============================================================================================================
' Verbindet als Client mit dem Server.
'==============================================================================================================
Local retval:Int
Local nPipe:String = "\\.\pipe\" + name

If hPipe <> 0 Then DebugLog "Verbindung zu einer Pipe besteht noch." ; Return 0

retval = pipe_WaitNamedPipe(nPipe, 0)
If retval = 0 Then DebugLog "Pipe ist nicht frei." ; Return False

retval = pipe_CreateFile(nPipe, $C0000000, 0, Pipe_Pointer(lpSec), 3, 0, 0)

If retval <> - 1 Then hPipe = retval ; Return True
End Function



Function Pipe_Disconnect:Int()
'==============================================================================================================
' Client und/oder Server beenden.
'==============================================================================================================
If hPipe = 0 Then DebugLog "Keine Pipe zum Schließen vorhanden." ; Return 0

pipe_DisconnectNamedPipe(hPipe)
pipe_CloseHandle(hPipe)

hPipe = 0
End Function



Function Pipe_DataAvail:Int()
'==============================================================================================================
' Prüft ob Daten auf der Pipe bereit stehen.
'==============================================================================================================
Local retval:Int = False

If hPipe = 0 Then DebugLog "Keine Pipe geöffnet." ; Return 0

retval = pipe_PeekNamedPipe(hPipe, Null, 0, 0, lpTotalBytesAvail, 0)

If retval <> 0 And Int Ptr(lpTotalBytesAvail)[0] > 0 Then Return True
End Function



Function Pipe_Pointer:Int(b:Byte Ptr)
'==============================================================================================================
' Hilfsfunktion für Pointerzugriff in BB
'==============================================================================================================
Return pipe_MulDiv(b, 1, 1)
End Function


Wie das funktioniert und weitere Informationen findest du auf www.east-power-soft.de.

MfG
Der Eisvogel
Ungarische Notation kann nützlich sein.
BlitzMax ; Blitz3D
Win 7 Pro 64 Bit ; Intel Core i7-860 ; 8 GB Ram ; ATI HD 5750 1 GB
Projekte: Window-Crasher
Ich liebe es mit der WinAPI zu spielen.

mpmxyz

BeitragSo, Sep 18, 2011 14:34
Antworten mit Zitat
Benutzer-Profile anzeigen
Zum Thema Threads:
Mit dem Aktivieren des "Threaded Build" ist noch nicht alles getan.
Man muss erst einmal "Threads" erstellen. (Diese werden parallel zueinander abgearbeitet. Standardmäßig gibt es nur einen Mainthread. Das ist das, was du schon die ganze Zeit genutzt hast.)
Für einen Thread braucht man eine Funktion der Art "beliebigerName:Object(obj:Object)".
Der Parameter "obj" ist hierbei das, was du beim Starten des Threads angibst:
BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.Threads
Import brl.StandardIO
Import brl.Random

SeedRnd(MilliSecs())

Function func:Object(obj:Object)
For Local i:Int=0 Until 10
Print obj.toString()
Delay Rand(0,1000) 'Man tut so, als ob man etwas zu tun hätte.
Next
EndFunction

For Local i:Int=0 Until 10
CreateThread(func,"Thread #"+i)
Next
Input("") 'den Threads ein bisschen Zeit geben
End

Hierbei noch ein Hinweis: Wenn man mit Threads arbeitet, muss man von mehreren Threads genutzte Ressourcen sichern. Ansonsten kann zum Beispiel das hier passieren:
Code: [AUSKLAPPEN]
Thread #2
Thread #Th1read
 #0
Thread #2

Es wurden hier parallel zueinander 2 Print-Aufrufe getätigt. Das unordentliche Ergebnis ist aber noch eine harmlose Folge fehlender Absicherung. Es kann hierbei die schlimmsten Fehler geben. Man muss bedenken, dass Threads vom Betriebssystem beliebig angehalten werden können. So kann es passieren, dass eine Variable zweimal um 1 erhöht wird, aber deren Wert nur einmal steigt. Lese dir durch, wie man diese Zugriffe absichern kann! Wenn man das und die anderen Dinge, die mit Threads möglich sind, kann, sind Threads nichts, wovor man sich fürchten muss. Smile
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
 

PhillipK

BeitragSo, Sep 18, 2011 14:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Okay, das klingt schonmal nach ansätzen.
Das heißt ich hab einmal das Pipeding zum spielen sowie evtl ganz vielleicht (irgendwann) mal Threads.

Das problem, was ich mit threads hab, ist... : ich krieg nicht alle benötigten module mit -h compilet Sad
Es gibt einfach keine ausgabe - vonwegen "Compiling: ModulFile.bmx" - etwa die hälte der module lies sich compilen, die andere hälfte nicht. Teilweise sind es .i und .a dateien, wo ich nichtmal weiß, was das sein soll Very Happy

Hier als beispiel:
Code: [AUSKLAPPEN]
echo "blabla"
bmk makemods -h zeke.luajit1
pause

als bat datei -> Es gibt n kurzen moment wo meine Festplatte arbeitet, dann erscheint einfach nur "Weiter mit beliebiger Taste..." als nächste zeile in der Konsole Sad

Threads fällt also (scheinbar) flach - es sei denn, solche i/a dateien lassen sich anderweitetig mit Threaded erweitern Smile

Sobald mir ein Spezifischer test eingefallen ist, werde ich mich mal dransetzen und versuchen, meine beiden kerne voll auszureizen - und ein programm in 2versionen zu testen (als gegenüberstellung, ob es auf einem Kern genauso gut läuft Very Happy )

Danke aufjedenfall schoneinmal für die antworten Smile

Noobody

BeitragSo, Sep 18, 2011 15:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Du solltest jedoch bedenken, dass du Grafikresourcen (wie etwa den OpenGL-Kontext oder das D3D-Device) nicht in verschiedenen Threads verwenden darfst und diese auch nicht an mehrere Exen verteilen kannst. Die einzelnen Surface-Updates auf mehrere Kerne zu verteilen geht also nicht so direkt.

Was du tun kannst, ist, die benötigten Geometriedaten parallel zu generieren, um die fertigen Daten dann an den Hauptthread zu schicken, welcher dann die Grafikaufrufe erledigt. Ich weiss nicht, wie schnell so eine Named Pipe läuft, aber mit Multithreading zumindest funktioniert das ganz gut (das verwendete ich so in ZauberCraft).
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun
 

PhillipK

BeitragSo, Sep 18, 2011 15:26
Antworten mit Zitat
Benutzer-Profile anzeigen
So in der art war es gedacht.

Als beispiel:

In einem früheren projekt hatten wir eine Landschaftsveränderung implementiert. Jede landschaftsstelle hatte einen "wasser" wert, welcher sich gleichmäßig in die nachbarfelder ausgebreitet hat, sowie unkraut, welches gewachsen ist und ab einer gewissne größe samen verteilen konnte. Erde wurde bei hoher feuchtigkeit zu schlamm, bei ausgewogener feuchtigkeit ist evtl gras gewachsen, gras konnte unkraut hervorrufen, unkraut hat sich teile des wasser gespeichert und und und und.. Eine richtig gut aussehden Flora war das Very Happy DAs ganze war so konzipiert, das man die funktion mehrmals aufrufen konnte und es schier zeit unabhängige updates im system gab. Man hat keine regelmäßigkeit in den updates erkannt. Leider war das aber ein so großes abfragengefrickel, das es am ende einfach nicht lohnenswert war, da man bei jedem update einen leichten "ruckler" verspürt hat.

Wenn man dieses system nun in einen weiteren Prozess oder Thread auslagern könnte, könnte man es so umschreiben, das ein Thread/PRozess/Whatever stetig die daten erneuert und die geänderten daten an einer schnittstelle bereitstellt. Das würde eben wieder die fähigkeit der zeitlosigkeit hervorrufen: In dem einem Frame sind 30 stellen berechnet worden, im nächsten zwar nur 15, aber schon siehts wieder "willkürlich" aus .
Der mainprozess muss dann keinerlei der aufwändigen berechnungen und abfragen anstellen sondern kann ganz einfach seine vorhandenen daten updaten.


Aufgrund eigener Recherchen habe ich bereits in erfahrung brigenn können, was man mit Threads nicht kann. Leider noch nicht, wie ich ein Threaded build nutzen kann^^

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group