Rechenintensive Prozesse auf GPU auslagern

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Sunny
Beiträge: 290
Registriert: 19.02.2009 06:02

Rechenintensive Prozesse auf GPU auslagern

Beitrag von Sunny »

Hi@all,
ich hoffe, dass der Betreff meines Anliegens richtig gewählt ist...

Gleich mal zu meinem Problem.
Ich habe hier mal einen kleinen Code:

Code: Alles auswählen

min = 1
max = 1000000
qs = 17

For i = min To max
  
  Value$ = Str(i)
  value = 0
  
  For n = 1 To Len(Value$)
    value + Val(Mid(Value$, n, 1))
  Next
  
  If value = qs
    x + 1
  EndIf
Next

Debug "Zwischen " + Str(min) + " und " + Str(max) + " gibt es " + Str(x) + " Zahlen, deren Quersumme 17 ist."
Dieser Code funktioniert ja tadellos und und wenn die Variable "max" einen Wert von "1.000.000" hat, ist das auch in einigen Sekunden durchgelaufen.
Wenn ich jetzt allerdings den Wert von "max" auf "100.000.000" setze, sieht die sache schon ganz anders aus.
Jetzt wollte ich mal wissen, ob ich mit PB die Grafikkarte ansprechen kann um diese Berechnung (Zähling / Inventierung / was auch immer ^^) auf die GPU auszulagern?
Wenn das möglich ist, wie müsste dann der Code dafür aussehen?
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Rechenintensive Prozesse auf GPU auslagern

Beitrag von STARGÅTE »

Meiner Meinung nach würde es schon mal viel brinden, wenn du diesen Code beschleunigst.
Das heißt alle String-Funktionen raus nehmen und nur mit Zahlen arbeiten!
Die Zahl kannst du auch numerisch in ihre Ziffern aufteilen

Danach ist der Code schon mal ca 200 mal schneller!

Danach kannst du noch überlegen die Min-Max sache auf mehrere zwischen Intervalle auf Theads aufzuteilen.
dann kannst du mehrere Prozessoren benutzen.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
c4s
Beiträge: 1235
Registriert: 19.09.2007 22:18

Re: Rechenintensive Prozesse auf GPU auslagern

Beitrag von c4s »

Probier es mal ohne Debugger (komplett ausgeschaltet!) und entferne die Stringfunktionen. Sonst gibt es eventuell hier etwas für dein Anliegen: http://www.purebasic.fr/german/viewtopic.php?t=19399
"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
Benutzeravatar
Sunny
Beiträge: 290
Registriert: 19.02.2009 06:02

Re: Rechenintensive Prozesse auf GPU auslagern

Beitrag von Sunny »

Ähm...
Tut mir leid, dass ich mich diesbezüglich etwas unverständlich ausgedrückt hab.
Es geht mir hierbei nicht um diesen Code (der diente bloß als ein halbwegs sinnvolles Beispiel).
Mir geht es hauptsächlich um das ansprechen der GPU.

Edit:
@c4s - Sieht ganz nett aus, hilft mir aber leider nicht so wirklich weiter, da diese Library nur vordefinierte Operationen (Berechnungen oder was auch immer) ausführt. Ich möchhte mir aber eigene Dinge auf kosten der GPU durchrechnen lassen.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Rechenintensive Prozesse auf GPU auslagern

Beitrag von STARGÅTE »

Trotzdem solltest du dir überlegen, ob es überhaupt sinnvoll ist, die GPU mit ggf. "Müll" zu belasten.
Die GPU würd wohl nicht sehr glücklich sein, wenn es darum geht, zB einen Text nach Rechtschreibfehler zu durchsuchen, um das mal auf die Spitze zu treiben, wenn du weißt was ich meine.

Der Vollständigkeithalber hier mal eine schnellere Variante

Code: Alles auswählen

Procedure DigitSum(Value.i)
	Protected Total.i
	Repeat
		Total + Value%10
		Value/10
	Until Value = 0
	ProcedureReturn Total
EndProcedure

Define Min = 1
Define Max = 1000000
Define DigitSum = 17
Define Count.i

For Number = Min To Max
  If DigitSum(Number) = DigitSum
    Count + 1
  EndIf
Next

MessageRequester("", "Zwischen " + Str(Min) + " und " + Str(Max) + " gibt es " + Str(Count) + " Zahlen, deren Quersumme "+Str(DigitSum)+" ist.")
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
Sunny
Beiträge: 290
Registriert: 19.02.2009 06:02

Re: Rechenintensive Prozesse auf GPU auslagern

Beitrag von Sunny »

OK...
Um weitere Diskusionen über die Richtigkeit meines Codes zu vermeiden, nehmen wir jetzt einfach mal STARGÅTE's Code als Beispiel... ^^
Dennoch bleibe ich bei meiner Frage, wie man das auf die GPU auslagern kann?
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: Rechenintensive Prozesse auf GPU auslagern

Beitrag von DarkDragon »

Sunny hat geschrieben:@c4s - Sieht ganz nett aus, hilft mir aber leider nicht so wirklich weiter, da diese Library nur vordefinierte Operationen (Berechnungen oder was auch immer) ausführt. Ich möchhte mir aber eigene Dinge auf kosten der GPU durchrechnen lassen.
Nein, du kannst doch selbst ein Skript definieren, das dir das ganze berechnet.
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
Sunny
Beiträge: 290
Registriert: 19.02.2009 06:02

Re: Rechenintensive Prozesse auf GPU auslagern

Beitrag von Sunny »

Nein, du kannst doch selbst ein Skript definieren, das dir das ganze berechnet.
Eben nicht, das ist ja das Problem ^^

Ich hab halt keine Ahnung, wie ich die Grafikkarte für solche Berechnungen ansteuere.
Vieleicht muss ich mich dafür ein bischen mit Assembler oder so befassen? Keine Ahnung...
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: Rechenintensive Prozesse auf GPU auslagern

Beitrag von DarkDragon »

Gut, dieses eine Problem lässt sich mit der oben genannten Bibliothek nicht gut beschleunigen, aber um zu beweisen, dass es überhaupt geht und dass du sehr wohl ein eigenes Skript verfassen kannst:

Code: Alles auswählen

XIncludeFile "GPUCalc.pbi"

Procedure WaitForLastCommand(*context.GPUCalcContext)
  Protected result

  result = 1

  While Not *context\hasFinishedLastCommand()
    gpuCalcYield()
  Wend

  If Not *context\wasLastCommandSuccessful()
    Select *context\getLastErrorCode()
      Case #GPUCALC_ERR_NO_ERROR
        PrintN("#GPUCALC_ERR_NO_ERROR")
      Case #GPUCALC_ERR_RENDERINGCONTEXT
        PrintN("#GPUCALC_ERR_RENDERINGCONTEXT")
      Case #GPUCALC_ERR_MULTITEXTURING
        PrintN("#GPUCALC_ERR_MULTITEXTURING")
      Case #GPUCALC_ERR_SHADERS
        PrintN("#GPUCALC_ERR_SHADERS")
      Case #GPUCALC_ERR_FRAMEBUFFEROBJECTS
        PrintN("#GPUCALC_ERR_FRAMEBUFFEROBJECTS")
      Case #GPUCALC_ERR_VERTEXBUFFEROBJECTS
        PrintN("#GPUCALC_ERR_VERTEXBUFFEROBJECTS")
      Case #GPUCALC_ERR_COMPILE_VERTEX
        PrintN("#GPUCALC_ERR_COMPILE_VERTEX")
        PrintN(PeekS(*context\getCompilerErrorVertex()))
      Case #GPUCALC_ERR_COMPILE_FRAGMENT
        PrintN("#GPUCALC_ERR_COMPILE_FRAGMENT")
        PrintN(PeekS(*context\getCompilerErrorFragment()))
      Case #GPUCALC_ERR_LINK_SHADERS
        PrintN("#GPUCALC_ERR_LINK_SHADERS")
        PrintN(PeekS(*context\getLinkerError()))
      Case #GPUCALC_ERR_FLOATTEXTURE
        PrintN("#GPUCALC_ERR_FLOATTEXTURE")
      Case #GPUCALC_ERR_INTEGERTEXTURE
        PrintN("#GPUCALC_ERR_INTEGERTEXTURE")
      Case #GPUCALC_ERR_INVALIDDATATYPE
        PrintN("#GPUCALC_ERR_INVALIDDATATYPE")
    EndSelect
    result = 0
  EndIf

  ProcedureReturn result
EndProcedure

OpenConsole()

Define *initialContext.GPUCalcContext
Define *context.GPUCalcContext
Define code.s = ""

code + "int calcDigitSum(int i)" + #LF$
code + "{" + #LF$
code + "  int result = 0;" + #LF$
code + "  while(i > 0)" + #LF$
code + "  {" + #LF$
code + "    int nextI = (i / 10);" + #LF$
code + "    result += i - 10 * nextI;" + #LF$
code + "    i = nextI;" + #LF$
code + "  }" + #LF$
code + "  return result;" + #LF$
code + "}" + #LF$

code + "ivec4 calc(int startOffset)" + #LF$
code + "{" + #LF$
code + "  int result = 0;" + #LF$
code + "  if(startOffset == 0) {" + #LF$
code + "    int digitSum = 17;" + #LF$
code + "    for(int i = 1; i < 1000000 - min(startOffset, 1) * 1000000; i ++) {" + #LF$
code + "      if(calcDigitSum(i) == digitSum) {" + #LF$
code + "        result ++;" + #LF$
code + "      }" + #LF$
code + "    }" + #LF$
code + "  }" + #LF$
code + "  return ivec4(result, 0, 0, 0);" + #LF$
code + "}" + #LF$

If LoadGPUCalcSymbols()
  *initialContext = gpuCalcCreateContext(#GPUCALC_TYPE_FLOAT32, 0, 0)
  If *initialContext
    If WaitForLastCommand(*initialContext)
      If Not *initialContext\integerCalculationSupported()
        PrintN("Your gpu isn't able to handle integers")
      Else
        *context = gpuCalcCreateContext(#GPUCALC_TYPE_INT32, 0, 1)
        WaitForLastCommand(*context)
        *resultMemory = *context\allocateDatasetMemory()
        WaitForLastCommand(*context)
        *context\loadCode(0, code, Len(code))
        WaitForLastCommand(*context)
        *context\bindCode(0)
        WaitForLastCommand(*context)
        *context\calculate(*resultMemory, 1)
        WaitForLastCommand(*context)
        PrintN("Result: " + Str(PeekI(*resultMemory)))
        gpuCalcReleaseContext(*context)
      EndIf
    EndIf
    
    gpuCalcReleaseContext(*initialContext)
  EndIf
  ReleaseGPUCalcSymbols()
Else
  PrintN("Error: couldn't open the library.")
EndIf
Input()

End
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
Kiffi
Beiträge: 10714
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Rechenintensive Prozesse auf GPU auslagern

Beitrag von Kiffi »

<OT>
STARGÅTE hat geschrieben:Trotzdem solltest du dir überlegen, ob es überhaupt sinnvoll ist, die GPU mit ggf. "Müll" zu belasten.
Die GPU würd wohl nicht sehr glücklich sein, wenn es darum geht, zB einen Text nach Rechtschreibfehler zu durchsuchen, um das mal auf die Spitze zu treiben, wenn du weißt was ich meine.
auch mal ein interessanter Aspekt der Programmierung. :D Also werde ich mir
in Zukunft gut überlegen müssen, ob ich meinen sensiblen Prozessoren
meinen Code zumuten kann. :lol:

</OT>
a²+b²=mc²
Antworten