Debugging und Threads allgemein?
Debugging und Threads allgemein?
Hallo
Die IDE ist ja mittlerweile sehr gut vorangeschritten und Sachen wie Callstack usw. haben mir sehr geholfen. Aber...ich bastel seit einer Weile wieder an einem Featuritis reichen Projekt und habe große Schwierigkeiten Fehlerquellen in Threads zu ermitteln.
Was ist denn die Beste vorgehensweise um eine Multi-Threaded Applikation zu Debuggen?
Problem: die SW (webserver) kann in verschiedenen multi- single- oder no-threaded Variationen ausgeführt werden (hatte bis jetzt auch immer seine Vorteile zur Fehlersuche und Optimierung). Der Server soll wahlweise das "Hauptprojekt" sein können, oder als Nebenschnittstelle fungieren können. Das Backend für eine WebApp oder für ein Hauptprojekt oder als sonstige Schnittstelle für ein Spielchen.
Es gibt leider mehrere Abstraktionsschichten welche das Debugging in Echtzeit verlangsamen "wegen" Purifier. Ich habe alle Datei Operation beispielsweise in Module verkappselt, damit man transparent aus dem RAM, Datei oder sonstiger Quelle "streamen" kann, z.B. StreamLOF(), das ganze noch mit einem Cache System verkompliziert. Oder ein "Archive2D" das noch dazwischen geschaltet sein kann ... Daher dauert das verarbeiten von kleinen INI Dateien (eigene Implementation) eben fast eine Minute mit Debugger wenn es eigentlich nur 0ms ohne dauert.
Nun es sind jetzt über 600kb an Code geworden über dutzende Module verteilt. Fehler treten viel seltener auf (bis gar nicht) wenn ich ohne Threads alles laufen lasse. Ich begnüge mich meistens mit OnError wenn dann was abranzt. Wenn der Purifier auf <=64 eingestellt ist, ist alles unbrauchbar langsam - insbesondere für den Stresstest.
Ich benutze viel eingebettete PB Listen und Maps und nutze diese auch als Eingabe/Rückgabe Parameter. z.B. ListServerConntections(*Server, List result.i()) oder sowas. Auch viel String- und Speicher- Manipulation. Ich bin mir manchmal nicht ganz sicher, ob es auch nicht an PB liegt. Weil ich denke es könnte sein, daß wenn PB maps und listen pre-alloziiert, es dann beim nächsten neuen Block stecken bleibt oder sowas weil das über einen anderen (?) thread passiert. Reinste Spekulation! EnableThreads is selbstverständlich auch immer an, sonst geht es ganz schnell nicht mehr weiter.
Fehler sind Endlosschleifen (bei List oder Map ForEach Next), Invalid Memory (meist bei Procedure Rücksprung, oder bei AllocateMemory/AllocateStructure) - aber erst nach einer unbestimmt langen Wartezeit oder nach vielen Anfragen (+10,000 requests) mit Stresstest. Manchmal passiert nichts Sichtbares, es wird nichts auf der Console ausgegeben oder in die Logdatei geschrieben. Und die OnError Zeilen sind wie gesagt nicht immer zielführend.
Es gibt nur einen Sourcecode den ich benutze, und der nicht von mir geschrieben wurde - das sind die numerischen Listen von wilbert im englischen Forum. Aber da hängt es nur äußerst selten und es dürfte eigentlich nicht (so wie ein IMA bei AllocateMemory eben). Das Mysterium besteht allgemein und ich vermute irgend welche memory leaks oder ein Stack Problem weil ich irgendwo meine Prototypen und Prozeduren nicht harmoniert habe. Doch das sollte dann eigentlich einfacher erkennbar sein!!!
Schämen sollte ich mich, weil ich noch keinen Chat in das System eingebaut habe. Ich will einen Chat erstmal per selbstverbockten Templates + Sqlite lösen, bevor ich Fast/CGI implementiere. Der Chat sollte eben nicht hard-coded sein. Und es müssen ja erst die Grundlagen funzen, ohne GUI weil ja möglicherweise reine Consolen oder Fullscreen Anwendungen dabei entstehen sollten.
Wenn es etwas gibt was mir jemand anraten oder abraten kann... ich bitte inständig um Aufkärung
Edit: NewList macht auch probleme. Seit 5,73 beta zeigt mir PB auch an wenn eine Liste mehrfach instanziiert wurde. Das hat auch solche Probleme verursacht, ist jetzt aber beseitigt worden. Trotzdem gibt es Fehler bei "Protected Newlist txt.s()" und Ähnlichen Code-stellen.
Die IDE ist ja mittlerweile sehr gut vorangeschritten und Sachen wie Callstack usw. haben mir sehr geholfen. Aber...ich bastel seit einer Weile wieder an einem Featuritis reichen Projekt und habe große Schwierigkeiten Fehlerquellen in Threads zu ermitteln.
Was ist denn die Beste vorgehensweise um eine Multi-Threaded Applikation zu Debuggen?
Problem: die SW (webserver) kann in verschiedenen multi- single- oder no-threaded Variationen ausgeführt werden (hatte bis jetzt auch immer seine Vorteile zur Fehlersuche und Optimierung). Der Server soll wahlweise das "Hauptprojekt" sein können, oder als Nebenschnittstelle fungieren können. Das Backend für eine WebApp oder für ein Hauptprojekt oder als sonstige Schnittstelle für ein Spielchen.
Es gibt leider mehrere Abstraktionsschichten welche das Debugging in Echtzeit verlangsamen "wegen" Purifier. Ich habe alle Datei Operation beispielsweise in Module verkappselt, damit man transparent aus dem RAM, Datei oder sonstiger Quelle "streamen" kann, z.B. StreamLOF(), das ganze noch mit einem Cache System verkompliziert. Oder ein "Archive2D" das noch dazwischen geschaltet sein kann ... Daher dauert das verarbeiten von kleinen INI Dateien (eigene Implementation) eben fast eine Minute mit Debugger wenn es eigentlich nur 0ms ohne dauert.
Nun es sind jetzt über 600kb an Code geworden über dutzende Module verteilt. Fehler treten viel seltener auf (bis gar nicht) wenn ich ohne Threads alles laufen lasse. Ich begnüge mich meistens mit OnError wenn dann was abranzt. Wenn der Purifier auf <=64 eingestellt ist, ist alles unbrauchbar langsam - insbesondere für den Stresstest.
Ich benutze viel eingebettete PB Listen und Maps und nutze diese auch als Eingabe/Rückgabe Parameter. z.B. ListServerConntections(*Server, List result.i()) oder sowas. Auch viel String- und Speicher- Manipulation. Ich bin mir manchmal nicht ganz sicher, ob es auch nicht an PB liegt. Weil ich denke es könnte sein, daß wenn PB maps und listen pre-alloziiert, es dann beim nächsten neuen Block stecken bleibt oder sowas weil das über einen anderen (?) thread passiert. Reinste Spekulation! EnableThreads is selbstverständlich auch immer an, sonst geht es ganz schnell nicht mehr weiter.
Fehler sind Endlosschleifen (bei List oder Map ForEach Next), Invalid Memory (meist bei Procedure Rücksprung, oder bei AllocateMemory/AllocateStructure) - aber erst nach einer unbestimmt langen Wartezeit oder nach vielen Anfragen (+10,000 requests) mit Stresstest. Manchmal passiert nichts Sichtbares, es wird nichts auf der Console ausgegeben oder in die Logdatei geschrieben. Und die OnError Zeilen sind wie gesagt nicht immer zielführend.
Es gibt nur einen Sourcecode den ich benutze, und der nicht von mir geschrieben wurde - das sind die numerischen Listen von wilbert im englischen Forum. Aber da hängt es nur äußerst selten und es dürfte eigentlich nicht (so wie ein IMA bei AllocateMemory eben). Das Mysterium besteht allgemein und ich vermute irgend welche memory leaks oder ein Stack Problem weil ich irgendwo meine Prototypen und Prozeduren nicht harmoniert habe. Doch das sollte dann eigentlich einfacher erkennbar sein!!!
Schämen sollte ich mich, weil ich noch keinen Chat in das System eingebaut habe. Ich will einen Chat erstmal per selbstverbockten Templates + Sqlite lösen, bevor ich Fast/CGI implementiere. Der Chat sollte eben nicht hard-coded sein. Und es müssen ja erst die Grundlagen funzen, ohne GUI weil ja möglicherweise reine Consolen oder Fullscreen Anwendungen dabei entstehen sollten.
Wenn es etwas gibt was mir jemand anraten oder abraten kann... ich bitte inständig um Aufkärung
Edit: NewList macht auch probleme. Seit 5,73 beta zeigt mir PB auch an wenn eine Liste mehrfach instanziiert wurde. Das hat auch solche Probleme verursacht, ist jetzt aber beseitigt worden. Trotzdem gibt es Fehler bei "Protected Newlist txt.s()" und Ähnlichen Code-stellen.
- NicTheQuick
- Ein Admin
- Beiträge: 8679
- Registriert: 29.08.2004 20:20
- Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti - Wohnort: Saarbrücken
- Kontaktdaten:
Re: Debugging und Threads allgemein?
Kennst du dich denn allgemein gut mit Threads aus? Weißt du wie man Ressourcen sauber mit Locks (Mutex), Semaphoren und Co schützt?
- juergenkulow
- Beiträge: 188
- Registriert: 22.12.2016 12:49
- Wohnort: :D_üsseldorf-Wersten
Re: Debugging und Threads allgemein?
Hallo Benubi,
wie sieht denn Dein OnError ErrorHandler aus?
Edit: @myThread() und Ergebnisse
wie sieht denn Dein OnError ErrorHandler aus?
Code: Alles auswählen
; Thread ErrorHandler 64 bit
CompilerIf #PB_Compiler_Debugger=1 Or #PB_Compiler_LineNumbering=0 Or #PB_Compiler_Thread=0
CompilerError "Debugger ausschalten und OnError Unterstüztung, Thread sicheres Executable einschalten."
CompilerEndIf
Procedure myThread(*ptr.Byte)
*ptr\b=42 ; Verursacht einen Fehler in Zeile Nummer 7.
EndProcedure
Procedure ErrorHandler()
Protected Fehlermeldung$=FormatDate("%dd.%mm.%yyyy %hh:%ii:%ss ", Date())+Str(ElapsedMilliseconds())+" ms "+
ErrorMessage()+" "+ErrorFile()+" Zeile:"+ErrorLine()+" "+ErrorAddress()+" "+
Hex(ErrorRegister(#PB_OnError_RSP))+" "+Hex(ErrorTargetAddress())
Protected Datei=OpenFile(#PB_Any,"FehlerDatei.txt",#PB_File_Append)
WriteStringN(Datei,Fehlermeldung$)
CloseFile(Datei)
MessageRequester("keine Fehlermeldung!", Fehlermeldung$)
End -1
EndProcedure
MessageRequester("OnError Test", "Test starten")
OnErrorCall(@ErrorHandler())
CreateThread(@myThread(),4711)
Delay(5000)
; 09.12.2020 09:26:07 248 ms Segmentation violation /mnt/myErrorHandler.pb Zeile:7 4207724 7F3A08131B60 1267
; 09.12.2020 09:27:51 20 ms Segmentation violation /mnt/myErrorHandler.pb Zeile:7 4207724 7F732EB55B60 1267
Zuletzt geändert von juergenkulow am 09.12.2020 10:32, insgesamt 1-mal geändert.
Bitte stelle Deine Fragen, denn den Erkenntnisapparat einschalten entscheidet über das einzig bekannte Leben im Universum.
Jürgen Kulow Wersten :D_üsseldorf NRW D Europa Erde Sonnensystem Lokale_Flocke Lokale_Blase Orion-Arm
Milchstraße Lokale_Gruppe Virgo-Superhaufen Laniakea Sichtbares_Universum
Jürgen Kulow Wersten :D_üsseldorf NRW D Europa Erde Sonnensystem Lokale_Flocke Lokale_Blase Orion-Arm
Milchstraße Lokale_Gruppe Virgo-Superhaufen Laniakea Sichtbares_Universum
- HeX0R
- Beiträge: 2959
- Registriert: 10.09.2004 09:59
- Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 - Kontaktdaten:
Re: Debugging und Threads allgemein?
Hier gibt's das Ganze etwas weniger rudimentär.
Hab's bei der Gelegenheit ein wenig aktualisiert (das Fenster war ziemlich winzig hier).
Wahnsinn... vor 14 Jahren hab ich das gepostet
Hab's bei der Gelegenheit ein wenig aktualisiert (das Fenster war ziemlich winzig hier).
Wahnsinn... vor 14 Jahren hab ich das gepostet
{Home}.:|:.{Codes}.:|:.{Downloads}.:|:.{History Viewer Online}
Re: Debugging und Threads allgemein?
Danke für die Rückmeldung!
@NicTheQuick
Ich gebe zu meine Erfahrungen mit Threads sind limitiert. Einen ThreadPool habe ich schon vor Jahren geschrieben, aber außerhalb von ein paar Tests damit nichts gemacht.
Ich Sperre immer das, worauf ich zugreifen möchte per Mutex. Es könnte aber immer sein, daß ich irgendwo etwas übersehe. Semaphoren benutze ich derzeit nicht - vielleicht irgendwo in einer nicht oder kaum genutzten queue, aber das weiß ich auf anhieb jetzt nicht. Ich benutze Referenz-Zähler für die kritischen Objekte, weil auf die mit mehreren Threads zugegriffen wird, ich die zu leb- und tot- zeiten in console/logfile/web-zugang auflisten/debuggen könnte. Außerdem werden beispielsweise die Cache-Dateien im RAM von mehreren Clients gleichzeitig gelesen. Da habe ich mich als unglücklicher "Assemblero" versucht, dann wieder auf Mutex umgestiegen. Damit meine ich ALLE Referenz-Zähler haben eine gemeinsame AddRef() procedure die per mutex jetzt geblockt wird um jedes einzelne objekt seine Referenzen zu erhöhen/dekrementieren. Es können keine 2 Objekte parallel inkrementiert/dekrementiert werden so zu sagen. Hierbei wird auch jedesmal nachgeschaut ob der Objekt-Zeiger in einer Registry steckt (ein Zeiger + AutoKey vergleich). Bringt aber auch nix.
Beispiel 1:1 kopiert. Das wird beispielsweise benutzt um einen "Job" hinzuzufügen. Das tut der (optionale) "Server thread". Der (optionale) Worker generiert dann die Antwort und sendet sie ab, indem er die Jobs in den Client-Listen abarbeitet (jeder Client hat eine Jobliste). Jobs haben einen Callback in ihrer Structure, je nach "Datei Handler" oder sonstwas geschehen soll (admin, statische Inhalte, Templates, später z.B. CGI).
Meine kritischen Objekte sehen so aus (im Header)
@juergenkulow
Wurde jetzt gerade eingebaut. Stresstest läuft (10 Seiten auf dem Browser die auf refreshpage=0 die letzten 1000 requests sich ausgebelen lassen). Mir fehlt "leider" ein Paket logger.
Ini (Auszug). Es liefen 2 Server threads (80, 8080) auf der Eingangsseite und jeder Server hat einen WorkerThread auf der Ausgangsseite. SpamThread öffnet X URLs auf dem Browser für Stresstest.
Zweiter test
Dritter Versuch (vorletzer) : Vorführeffekt jetzt geht es mal wieder auch über die Externe... Dialog Fenster taucht nicht auf! Threads laufen im Hintergrund weiter. Auch die Logdatei wird nicht geschrieben. Letzte Zeile der Log-Datei:
*Logdatei -> String-manipulation (inkl. Lokalisierung/Mehrsprachmodul) -> *Streamverkappsellung -> Dateiklasse
*= mit extra Mutex "verpackt".
Wenn das am Mehrsprachmodul liegt... Normalerweise bekommt jedes request eine Kopie per CopyMap(), und die sind dann auch ge-mutext. Aber es könnte auch sein daß ich irgendwo was dort übersehen habe. Aber die LogFile bockt ja erst nach dem fatalen Fehler, und wer weiß schon... Sorry, daß ich laut denken muß ;D
Ich setze die ErrorDialog() jetzt an den Anfang meiner selbstverhunzten OnError Procedure!
Es sind immer eine Handvoll von Zeilen auf die ich verwiesen werde. Diese ändern sich Heisenbug-artig. An den ersten Fehler mit NumericKeyMap kann ich mich nicht erinnern. Den zweiten kannte ich schon. Beim dritten bin ich mir weniger sicher, weil ich hatte schon viele Zombiethread-Kombinationen. Ai caramba.
Danke an alle, auch wenn ich immer noch im Dunkeln tappe.
Melde mich später wieder. Wenn jemand einen Tipp hat, immer her damit. Ich bin eine quasi Null in Assembler also bitte etwas Nachsichtig sein.
@NicTheQuick
Ich gebe zu meine Erfahrungen mit Threads sind limitiert. Einen ThreadPool habe ich schon vor Jahren geschrieben, aber außerhalb von ein paar Tests damit nichts gemacht.
Ich Sperre immer das, worauf ich zugreifen möchte per Mutex. Es könnte aber immer sein, daß ich irgendwo etwas übersehe. Semaphoren benutze ich derzeit nicht - vielleicht irgendwo in einer nicht oder kaum genutzten queue, aber das weiß ich auf anhieb jetzt nicht. Ich benutze Referenz-Zähler für die kritischen Objekte, weil auf die mit mehreren Threads zugegriffen wird, ich die zu leb- und tot- zeiten in console/logfile/web-zugang auflisten/debuggen könnte. Außerdem werden beispielsweise die Cache-Dateien im RAM von mehreren Clients gleichzeitig gelesen. Da habe ich mich als unglücklicher "Assemblero" versucht, dann wieder auf Mutex umgestiegen. Damit meine ich ALLE Referenz-Zähler haben eine gemeinsame AddRef() procedure die per mutex jetzt geblockt wird um jedes einzelne objekt seine Referenzen zu erhöhen/dekrementieren. Es können keine 2 Objekte parallel inkrementiert/dekrementiert werden so zu sagen. Hierbei wird auch jedesmal nachgeschaut ob der Objekt-Zeiger in einer Registry steckt (ein Zeiger + AutoKey vergleich). Bringt aber auch nix.
Beispiel 1:1 kopiert. Das wird beispielsweise benutzt um einen "Job" hinzuzufügen. Das tut der (optionale) "Server thread". Der (optionale) Worker generiert dann die Antwort und sendet sie ab, indem er die Jobs in den Client-Listen abarbeitet (jeder Client hat eine Jobliste). Jobs haben einen Callback in ihrer Structure, je nach "Datei Handler" oder sonstwas geschehen soll (admin, statische Inhalte, Templates, später z.B. CGI).
Code: Alles auswählen
Procedure.i AddSocketJob(*Job.N2D_Job, *Socket.N2D_Socket,TopOfList=#False,IsBlocking=#True)
Shared _REG
Protected *SERVER.N2D_Server
If Not *Socket
ProcedureReturn #False
EndIf
*SERVER = *Socket\SERVER
If *SERVER = #Null
*Job\JobType =#JOBTYPE_OUTSOCKET
Else
*Job\JobType =#JOBTYPE_SOCKET
EndIf
;N2D_LogFile::MSG("add socket job")
*Job\IsBlocking = IsBlocking
If *Job
N2D_LogFile::DBG("Adding job to list")
LockSocket(*Socket)
ResetList(*Socket\Job())
If TopOfList
InsertElement(*Socket\Job())
*Socket\Job() = *Job
Else
AddElement(*Socket\Job())
*Socket\Job() = *Job
EndIf
UnlockSocket(*Socket)
N2D_LogFile::DBG("Job added to list")
ProcedureReturn *Job
EndIf
n2d::Release(*Job)
ProcedureReturn #Null
; n2d::MakeRefer(*Socket,@*Job\SocketRef,1)
EndProcedure
Code: Alles auswählen
Structure N2D_Ref
iVT.i ; optional, ungenutzt
Ref.i ; Referenz-Zähler
OnFree.N2D_OnFree ; Objekt-Freigabe Procedure (wird von Garbage collector bei gc(0) ausgeführt, wenn das objekt in der Freigabeliste ist)
RefAutoKey.i ; Objekt-Autokey (ID)
gcExtra.i ; Garbage collection Verzögerung in ms (optional)
TypeID.s{16} ; ID ... z.B. "socket" "cache-file" "server" ...
EndStructure
@juergenkulow
@HeXOR
Procedure MainOnError()
Protected NewList objids.s()
N2D_LogFile::LOGLINE("FATAL ERROR")
N2D_LogFile::FATAL("FATAL ERROR --- ON ERROR")
N2D_LogFile::FATAL("Error Address: "+N2D_String::StrPointer(ErrorAddress()))
N2D_LogFile::FATAL("Error Code: "+Str(ErrorCode()))
N2D_LogFile::FATAL("Error Message: "+ErrorMessage())
N2D_LogFile::FATAL("Error Target Address: "+N2D_String::StrPointer(ErrorAddress()))
N2D_LogFile::FATAL("Error File: "+ErrorFile())
N2D_LogFile::FATAL("Error Line: "+Str(ErrorLine()))
N2D_LogFile::LOGLINE("Registered object pointers")
n2d::ListPointers(objids())
ForEach objids()
N2D_LogFile::FATAL(objids())
Next
N2D_LogFile::LOGLINE("End of object pointers registry")
ErrorDialog() ; <- HeXOR
N2D_LogFile::Close()
Delay(1000)
End
EndProcedure
Wurde jetzt gerade eingebaut. Stresstest läuft (10 Seiten auf dem Browser die auf refreshpage=0 die letzten 1000 requests sich ausgebelen lassen). Mir fehlt "leider" ein Paket logger.
Ini (Auszug). Es liefen 2 Server threads (80, 8080) auf der Eingangsseite und jeder Server hat einen WorkerThread auf der Ausgangsseite. SpamThread öffnet X URLs auf dem Browser für Stresstest.
Das ist neu aber wie immer sagt es mir nichts.MainThread=false
ServerThread=true
WorkerThread=true
CronJobThread=false
CacheThread=false
SpamThread=true
Zeile 144Error Message: Invalid memory access
Error Code: -1073741819
Code Address: 4376397
Target Address: 60
Sourcecode line: 144
Sourcecode file: F:\PB_Sources\Nubi2D\src\NumericKeyMapModule.pb
Register content:
EAX = 0x18F59E0
EBX = 0x0
ECX = 0x18F59E0
EDX = 0x1E
EBP = 0x0
ESI = 0x0
EDI = 0x0
ESP = 0x24BFDDC
Procedure.i NKMap_GetValue(*Map.NKMap, Key)
Zweiter test
Zeile 198Error Message: Invalid memory access
Error Code: -1073741819
Code Address: 4363290
Target Address: 84
Sourcecode line: 198
Sourcecode file: F:\PB_Sources\Nubi2D\src\Nubi2D_LogFile.pb
Register content:
EAX = 0x8
EBX = 0x3E8
ECX = 0x0
EDX = 0x0
EBP = 0x0
ESI = 0x1D6CE2A
EDI = 0xFFFFFFFFFFFFFFFF
ESP = 0x13FDB4
Mir fällt gerade auf, daß sowas anscheinend erst passiert wenn ich über meine externe Adresse zugreifen möchte (jene vom Internet Provider). Oder es geht einfach früher etwas schief. Der Stresstest läuft über localhost:80 und localhost:8080, pc-LAN-IP:80, pc-LAN-IP:8080. Nunja...Format$ = FormatDate(N2D_LOG_FORMAT$,Date())
Dritter Versuch (vorletzer) : Vorführeffekt jetzt geht es mal wieder auch über die Externe... Dialog Fenster taucht nicht auf! Threads laufen im Hintergrund weiter. Auch die Logdatei wird nicht geschrieben. Letzte Zeile der Log-Datei:
Unbekannte Zeile09/12/2020 14:13:24 ::MainOnError FTL [55] FATAL ERROR --- ON ERROR########################################################################################################################
*Logdatei -> String-manipulation (inkl. Lokalisierung/Mehrsprachmodul) -> *Streamverkappsellung -> Dateiklasse
*= mit extra Mutex "verpackt".
Wenn das am Mehrsprachmodul liegt... Normalerweise bekommt jedes request eine Kopie per CopyMap(), und die sind dann auch ge-mutext. Aber es könnte auch sein daß ich irgendwo was dort übersehen habe. Aber die LogFile bockt ja erst nach dem fatalen Fehler, und wer weiß schon... Sorry, daß ich laut denken muß ;D
Ich setze die ErrorDialog() jetzt an den Anfang meiner selbstverhunzten OnError Procedure!
Es sind immer eine Handvoll von Zeilen auf die ich verwiesen werde. Diese ändern sich Heisenbug-artig. An den ersten Fehler mit NumericKeyMap kann ich mich nicht erinnern. Den zweiten kannte ich schon. Beim dritten bin ich mir weniger sicher, weil ich hatte schon viele Zombiethread-Kombinationen. Ai caramba.
Danke an alle, auch wenn ich immer noch im Dunkeln tappe.
Melde mich später wieder. Wenn jemand einen Tipp hat, immer her damit. Ich bin eine quasi Null in Assembler also bitte etwas Nachsichtig sein.
Re: Debugging und Threads allgemein?
Es geht weiter... diesmal mit MessageBox Version von HeXOR und diese dann gleich an den Kopf der Procedure.
Ein Stresstest-Durchgang dauert ca. eine Minute, bis ich dann alles erfolgreich sabotiere oder es sich von selbst aufhängt.
Target Address ist wieder 84. Habe ich doch irgendwo anders schon gesehen. Was kann das bedeuten?
Log Datei ging auch durch. Hier ein Ausschnitt aus dem untersten Ende. Es werden Dutzende Streams je Request erzeugt. Header, Body von Anfrage und Antwort haben jeweils einen Stream als Minimalkonfiguration - das macht also 4 mindestens pro Request (wenn eine Antwort hard-coded wird wie beispiel ein 500 oder 404 Fehler). Ein Template kann aus X Schnippseln bestehen, welche ebenso als streams "transparent" included werden. Das alles, so wie andere volatile Objekte tragen dazu bei, daß die Autokeys schnell in die 10.000er gehen. Die Logdatei ist 7840 Zeilen lang und ab 3800 kommt die Fehlermeldung + Objekt-Auflistung. Es sind also tausende Objekte da die darauf warten recycled zu werden - ca. 4000. Und ca. 2000 requests rein und 2000 antworten raus.
(Ausschnitt/Beispiel)
Ich kann auch die Threads anders konfigurieren. Oder einen Server abschalten (habe in der MainApp nur 2 vorgesehen). Wird sowieso schief gehen.
Jetzt läuft es wieder Minuten lang ohne Probleme.
OOOOH... 2 MessageRequester mit OnError. Das hatte ich auch noch nie. Habe aber auch 4 Threads die das vielleicht können? kA
Wieder Target Address: 84. Beim zweiten. Den ersten (älteren) muß ich weiter unten abtippen.
Letzte on error
Erster OnError aufruf (von screenshot abtippen )
Glaubt ihr ich sollte das anders machen zum Beispiel nur mit einem Server auf einmal? Dann mache ich das beim nächsten mal. Für heute ist schluß!
Ein Stresstest-Durchgang dauert ca. eine Minute, bis ich dann alles erfolgreich sabotiere oder es sich von selbst aufhängt.
Zeile 598 =>Hi Unknown Autor,
i discovered an Error with Unknown Application V 0.1 :
Error Message: Invalid memory access
Error Code: -1073741819
Code Address: 4363295
Target Address: 84
Sourcecode line: 598
Sourcecode file: F:\PB_Sources\Nubi2D\src\Nubi2D_HTTP.pb
Register content:
EAX=0x8
EBX=0x3E8
ECX=0x0
EDX=0x0
EBP=0x0
ESI=0x1D6CE3B
EDI=0xFFFFFFFFFFFFFFFF
ESP=0x13FDB4
Hatte ich schon öfter.tFileSize =FileSize(*A\Filename + "/" + fname$ )
Target Address ist wieder 84. Habe ich doch irgendwo anders schon gesehen. Was kann das bedeuten?
Log Datei ging auch durch. Hier ein Ausschnitt aus dem untersten Ende. Es werden Dutzende Streams je Request erzeugt. Header, Body von Anfrage und Antwort haben jeweils einen Stream als Minimalkonfiguration - das macht also 4 mindestens pro Request (wenn eine Antwort hard-coded wird wie beispiel ein 500 oder 404 Fehler). Ein Template kann aus X Schnippseln bestehen, welche ebenso als streams "transparent" included werden. Das alles, so wie andere volatile Objekte tragen dazu bei, daß die Autokeys schnell in die 10.000er gehen. Die Logdatei ist 7840 Zeilen lang und ab 3800 kommt die Fehlermeldung + Objekt-Auflistung. Es sind also tausende Objekte da die darauf warten recycled zu werden - ca. 4000. Und ca. 2000 requests rein und 2000 antworten raus.
(Ausschnitt/Beispiel)
09/12/2020 16:02:45 ::MainOnError FTL [70] 0x07DE5C74:[http-response] Ref[1] AutoKey[29267]################################################################################################
09/12/2020 16:02:45 ::MainOnError FTL [70] 0x0535715C:[stream] Ref[1] AutoKey[29879]#######################################################################################################
09/12/2020 16:02:45 ::MainOnError FTL [70] 0x04FDF28C:[stream] Ref[1] AutoKey[27772]#######################################################################################################
09/12/2020 16:02:45 ::MainOnError FTL [70] 0x04EB79AC:[stream] Ref[1] AutoKey[26835]#######################################################################################################
09/12/2020 16:02:45 ::MainOnError FTL [70] 0x083BF09C:[stream] Ref[1] AutoKey[30588]#######################################################################################################
09/12/2020 16:02:45 ::MainOnError FTL [70] 0x0512E514:[http-response] Ref[1] AutoKey[28915]################################################################################################
Ich kann auch die Threads anders konfigurieren. Oder einen Server abschalten (habe in der MainApp nur 2 vorgesehen). Wird sowieso schief gehen.
Jetzt läuft es wieder Minuten lang ohne Probleme.
OOOOH... 2 MessageRequester mit OnError. Das hatte ich auch noch nie. Habe aber auch 4 Threads die das vielleicht können? kA
Wieder Target Address: 84. Beim zweiten. Den ersten (älteren) muß ich weiter unten abtippen.
Letzte on error
Zeile 1919 : Hier könnte *server=#Null sein, wäre aber unlogisch.Error Message: Invalid memory access
Error Code: -1073741819
Code Address: 4363295
Target Address: 84
Sourcecode line: 1919
Sourcecode file: F:\PB_Sources\Nubi2D\src\Nubi2D_HTTP.pb
Register content:
EAX=0x8
EBX=0x3E8
ECX=0x0
EDX=0x0
EBP=0x0
ESI=0x1D6CE3C
EDI=0xFFFFFFFFFFFFFFFF
ESP=0x13FDB4
N2D_LogFile::LOGFILE("OUT "+RSet(Str(*Server\ServerPort),5)+" "+HistoryLine$,"HTTP")
Erster OnError aufruf (von screenshot abtippen )
Zeile 3013Error Message: Invalid memory access
Error Code: -1073741819
Code Address: 4338940
Target Address: 112
Sourcecode line: 3013
Sourcecode file: F:\PB_Sources\Nubi2D\src\Nubi2D_HTTP.pb
Register content:
EAX=0x0
EBX=0x0
ECX=0x6BF0060
EDX=0x0
EBP=0x0
ESI=0x0
EDI=0x0
ESP=0x2BFFE98
Und diesmal steht nix in der Log-Datei von Fehlern... Naja egal eben.Protected NewList Batch.s(), NewMap Pairs.s(), NewList txt.s()
Glaubt ihr ich sollte das anders machen zum Beispiel nur mit einem Server auf einmal? Dann mache ich das beim nächsten mal. Für heute ist schluß!
- NicTheQuick
- Ein Admin
- Beiträge: 8679
- Registriert: 29.08.2004 20:20
- Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti - Wohnort: Saarbrücken
- Kontaktdaten:
Re: Debugging und Threads allgemein?
Puh, das ist viel zu lesen und etwas abstrakt um sich reinzudenken.
Aber die ständige 84 lässt mich vermuten, dass du vielleicht irgendwo mit @ einen Pointer zu einem Structure-Field erhältst, dass zufällig an Byte-Position 84 in der Struktur zu finden ist. Und der Pointer, zu dem die Struktur gehört, ist aber 0.
Blödes Beispiel:
Zum Beispiel deine Zeile 598:
Wo kommt das *A denn eigentlich her?
Bei deiner AddSocketJob-Procedure finde ich komisch, dass du am Anfang schon *Job\JobType zuweist und später erst testest, ob *Job überhaupt ungleich 0 ist.
Aber die ständige 84 lässt mich vermuten, dass du vielleicht irgendwo mit @ einen Pointer zu einem Structure-Field erhältst, dass zufällig an Byte-Position 84 in der Struktur zu finden ist. Und der Pointer, zu dem die Struktur gehört, ist aber 0.
Blödes Beispiel:
Code: Alles auswählen
Structure Belag
dies.s
und.s
das.s
EndStructure
Structure Pizza
a.q[10]
b.l
belag.Belag
EndStructure
Define *pizza.Pizza = 0
Define *belag.Belag = @*pizza\belag
Debug *belag
Code: Alles auswählen
tFileSize =FileSize(*A\Filename + "/" + fname$ )
Bei deiner AddSocketJob-Procedure finde ich komisch, dass du am Anfang schon *Job\JobType zuweist und später erst testest, ob *Job überhaupt ungleich 0 ist.
- juergenkulow
- Beiträge: 188
- Registriert: 22.12.2016 12:49
- Wohnort: :D_üsseldorf-Wersten
Re: Debugging und Threads allgemein?
Hallo Benubi,
Du suchst soetwas wie PeekI(60), PeekI(84) oder PeekI(112) aber in ASM-Code in Deinem Programm.
Vielleicht hilft schon "pbcompiler -c".
Gruß
Du suchst soetwas wie PeekI(60), PeekI(84) oder PeekI(112) aber in ASM-Code in Deinem Programm.
Vielleicht hilft schon "pbcompiler -c".
Gruß
Re: Debugging und Threads allgemein?
@NicTheQuick
Genau das ist auch meine Vermutung. Ich habe den Eindruck auf nicht-initialisierte Strukturen zuzugreifen, oder daß sich durch einen Überlauf irgendwie dies ergibt. Ich glaube die 84 bezieht sich auf "leere" PB Objekte (PBListe/PBMap +84), oder es hat etwas mit Task-Switching zu tun.
@jurgenkulow
Ich werde mich daran machen. Poke und peek benutze ich sehr selten - ich werde aber nach den magischen Fehlerzahlen suchen.
Bis hierhin erstmal danke für die Antworten. Sollte ich Erfolg damit haben oder einen anderen Ansatz zur Fehlersuche finden melde ich mich.
Genau das ist auch meine Vermutung. Ich habe den Eindruck auf nicht-initialisierte Strukturen zuzugreifen, oder daß sich durch einen Überlauf irgendwie dies ergibt. Ich glaube die 84 bezieht sich auf "leere" PB Objekte (PBListe/PBMap +84), oder es hat etwas mit Task-Switching zu tun.
@jurgenkulow
Ich werde mich daran machen. Poke und peek benutze ich sehr selten - ich werde aber nach den magischen Fehlerzahlen suchen.
Bis hierhin erstmal danke für die Antworten. Sollte ich Erfolg damit haben oder einen anderen Ansatz zur Fehlersuche finden melde ich mich.
- juergenkulow
- Beiträge: 188
- Registriert: 22.12.2016 12:49
- Wohnort: :D_üsseldorf-Wersten
Re: Debugging und Threads allgemein?
Hallo,
ich habe die Fährte zu *pointer84.Byte=84 : *pointer84\b=42 gesucht:
ich habe die Fährte zu *pointer84.Byte=84 : *pointer84\b=42 gesucht:
Code: Alles auswählen
; ErrorHandler der Threadfehler überlebt und Zeilen um den Fehler ausgiebt.
; Informationen werden in FehlerDatei.txt geschrieben, Schreibrecht im Verzeichnis sollten da sein.
; Teste Pointer mit der Speicheraddresse 84.
CompilerIf #PB_Compiler_Debugger=1 Or #PB_Compiler_LineNumbering=0 Or #PB_Compiler_Thread=0
CompilerError "Debugger ausschalten und OnError Unterstüztung, Thread sicheres Executable einschalten."
CompilerEndIf
CompilerIf #PB_Processor_x64<>#PB_Compiler_Processor
CompilerError "x64 wird unterstützt."
CompilerEndIf
EnableExplicit
Global AlleFehler$
Global MutexErrorHandler
Structure variant_Typ
Typ.i
StructureUnion
aWert.a : bWert.b : cWert.c : dblWert.d : fltWert.f : iWert.i : lWert.l : qWert.q : *ptr : uWert.u : wWert.w ;#PB_Word
EndStructureUnion
sWert.s
Zeilennr.l
EndStructure ; offen Array, Interface, List, Map, Structure
Define *zeilen.variant_Typ=AllocateMemory(1000000*SizeOf(variant_Typ)) ; P)latz für 1. Mio
Define *ptrzeilen.variant_Typ=*zeilen
Define *ptrCLN.long ; Pointer auf Zeilennummer besorgen.
! MOV rax,CLN
! MOV [p_ptrCLN],rax
#PB_Zeilennr=$100
Macro Zeile
*ptrzeilen\Zeilennr=*ptrCLN\l
*ptrzeilen\Typ=#PB_Zeilennr
*ptrzeilen+SizeOf(variant_Typ)
EndMacro
Macro Wertl(dw) ;#PB_Long
*ptrzeilen\lWert=dw
*ptrzeilen\Zeilennr=*ptrCLN\l
*ptrzeilen\Typ=#PB_Long
*ptrzeilen+SizeOf(variant_Typ)
EndMacro
Procedure Thread_Pointer84(Wert)
Shared *zeilen.variant_Typ
Shared *ptrzeilen.variant_Typ
Shared *ptrCLN.long
WertL(84) : Protected *pointer84.Byte=84
;*pointer84\b=42
Zeile : Protected b.b=*pointer84\b
EndProcedure
Procedure ErrorHandlerThread()
Shared AlleFehler$
Shared *zeilen.variant_Typ
Shared *ptrzeilen.variant_Typ
Shared MutexErrorHandler
OnErrorCall(@ErrorHandlerThread())
LockMutex(MutexErrorHandler)
Protected Fehlermeldung$=FormatDate("Thread %dd.%mm.%yyyy %hh:%ii:%ss ", Date())+Str(ElapsedMilliseconds())+" ms "+
ErrorMessage()+" "+ErrorFile()+" Zeile:"+ErrorLine()+" "+ErrorAddress()+" "+
Hex(ErrorRegister(#PB_OnError_RSP))+" "+ErrorTargetAddress()
Protected *zptr.variant_Typ=*zeilen
While *zptr<*ptrzeilen
Select *zptr\Typ ; offen: weitere Case.
Case #PB_Zeilennr
Protected s$=Str(*zptr\Zeilennr)
Case #PB_Long
s$=Str(*zptr\Zeilennr)+" L:"+Str(*zptr\lWert)
Default
s$="Fehler: unbekannter Typ"
EndSelect
Fehlermeldung$+" "+s$
*zptr+SizeOf(variant_Typ)
Wend
Protected Datei=OpenFile(#PB_Any,"FehlerDatei.txt",#PB_File_Append)
WriteStringN(Datei,Fehlermeldung$)
CloseFile(Datei)
AlleFehler$+Fehlermeldung$+#LF$
UnlockMutex(MutexErrorHandler)
Repeat : Delay(1000) : ForEver
; Hier ist hat MessageRequester keine Wirkung.
; Es gibt auch andere Auswirkungen im Hauptprogramm.
EndProcedure
Procedure ErrorHandler()
Shared AlleFehler$
Protected Fehlermeldung$=FormatDate("Haupt %dd.%mm.%yyyy %hh:%ii:%ss ", Date())+Str(ElapsedMilliseconds())+" ms "+
ErrorMessage()+" "+ErrorFile()+" Zeile:"+ErrorLine()+" "+ErrorAddress()+" "+
Hex(ErrorRegister(#PB_OnError_RSP))+" "+ErrorTargetAddress()
Protected Datei=OpenFile(#PB_Any,"FehlerDatei.txt",#PB_File_Append)
WriteStringN(Datei,Fehlermeldung$)
CloseFile(Datei)
MessageRequester("pointer84 Fehler",Fehlermeldung$)
End
EndProcedure
If #PB_MessageRequester_Yes=MessageRequester("pointer84 Fehler auslösen","Thread(ja) oder Hauptprogramm(nein)",#PB_MessageRequester_YesNo)
MutexErrorHandler=CreateMutex()
OnErrorCall(@ErrorHandlerThread())
;MessageRequester("Thread","Thread")
CreateThread(@Thread_Pointer84(),0)
CreateThread(@Thread_Pointer84(),0)
CreateThread(@Thread_Pointer84(),0)
Delay(5000)
MessageRequester("fertig",AlleFehler$)
Else
OnErrorCall(@ErrorHandler())
;MessageRequester("HP","HP")
Define *pointer84.Byte=84:
;*pointer84\b=42
Define b.b=*pointer84\b
EndIf
; Haupt 16.12.2020 03:01:54 55 ms Segmentation violation /mnt/p84.pb Zeile:111 4207086 7FFF619579C0 84
; Thread 16.12.2020 03:01:58 0 ms Segmentation violation /mnt/p84.pb Zeile:49 4207440 7F45DDD33B40 84 47 L:84 49 47 L:84 49 47 L:84 49
; Thread 16.12.2020 03:01:58 0 ms Segmentation violation /mnt/p84.pb Zeile:49 4207440 7F45DDD33B40 84 47 L:84 49 47 L:84 49 47 L:84 49
; Thread 16.12.2020 03:01:58 0 ms Segmentation violation /mnt/p84.pb Zeile:49 4207440 7F45DDD33B40 84 47 L:84 49 47 L:84 49 47 L:84 49
; offen: Anzeige von Fehlern im Thread in der Hauptschleife unter (Console, Console mit
; EnableGraphicalConsole, OpenWindow, ORGE, ORGE mit OpenScreen, OpenWindow3D, OpenGL, ...)
; Makros WertTyp und Auswertung *zptr\Typ
; Problem: Ein für Thread und Hauptprogramm gemeinsamer ErrorHandler müßte prüfen ob der aktuelle
; Stack der Hauptprogramm-Stack ist.