Das mit der aktuellen Qt-Version hab ich heute auch schon überlegt. Kann ich aber leider erst auf Arbeit ausprobieren, weil ich zu Hause nur Win2000 oder Linux habe und der neue QtCreator nicht unter Win2000 läuft :/
Das Abspecken habe ich auch schon probiert, aber habe noch nichts rausgefunden. Werd ich aber noch weiter probieren.
Bin sonst aber auch für weiter Vorschläge offen...
[gelöst, die 2.] Seltsame Probleme mit DLL
Hi,
Also das Problem scheint "gelöst" zu sein. Hab jetzt das Qt 4.6-SDK installiert und das Programm neu kompiliert und es funktioniert. Zumindest soweit ich das jetzt testen konnte. Sehr seltsam...
Danke Dir, Christian81, für deine geduldige Hilfsbereitschaft. Würd dir ja gerne n Bier dafür ausgeben
Grüße,
Kay
Also das Problem scheint "gelöst" zu sein. Hab jetzt das Qt 4.6-SDK installiert und das Programm neu kompiliert und es funktioniert. Zumindest soweit ich das jetzt testen konnte. Sehr seltsam...
Danke Dir, Christian81, für deine geduldige Hilfsbereitschaft. Würd dir ja gerne n Bier dafür ausgeben
Grüße,
Kay
Wo wird der Speicher denn angefordert?
In der *.dll oder in der *.exe die eine *.dll benutzt.
Ich vermute mal hier gibt es einfach ein Design-Problem, denn Objekte in c++ über DLL/Modul-Grenzen, zumindest unter Windows, zu geben geht nur :
1.)
Wenn die *.exe und die *.dll mit dem gleichen Compiler (Version) und den gleichen Settings gebaut wurde. (deshalb geht vermutlich zufällig Dein Code)
2.)
C-Style API, ala Win32-API (Bsp.:CreateWindow und DestroyWindow) wo der angeforderte Speicher auch wieder im Modul freigegeben wird.
3.)
Oder ein sauberes Design mit Interfaces (abstrakte-Klassen, pure virtual und keine Daten-Member) ala COM.
In der *.dll oder in der *.exe die eine *.dll benutzt.
Ich vermute mal hier gibt es einfach ein Design-Problem, denn Objekte in c++ über DLL/Modul-Grenzen, zumindest unter Windows, zu geben geht nur :
1.)
Wenn die *.exe und die *.dll mit dem gleichen Compiler (Version) und den gleichen Settings gebaut wurde. (deshalb geht vermutlich zufällig Dein Code)
2.)
C-Style API, ala Win32-API (Bsp.:CreateWindow und DestroyWindow) wo der angeforderte Speicher auch wieder im Modul freigegeben wird.
3.)
Oder ein sauberes Design mit Interfaces (abstrakte-Klassen, pure virtual und keine Daten-Member) ala COM.
Hm, finde den Einwurf prinzipiell einleuchtend. Kann durchaus sein, dass mein Design unter diesen Gesichtspunkten mies ist.
Der eigentliche Speicher (für die Daten mit denen SSE-Operationen ausgeführt werden) wird in der DLL angefordert. Und zwar meist im Konstruktor der Vektorklasse. Auf die Vektoren greife ich ja über den []-operator der Matrixklasse zu. Auch von der *.exe aus.
zu 1.) Die *.dll und die *.exe sind mit dem gleichen Compiler gebaut (aktueller MinGW aus dem Qt 4.6-SDK). Die *.dll wurde mittels den Qt-Möglichkeiten zur Libraryprogrammierung gebaut.
zu 2.) Den SSE-Speicher gebe ich erst bei Zerstörung des Objekts (also der Matrix) frei. Wollte eigentlich schon gerne eine C++ - API haben, damit ich die Matrizenklasse mit ihren Operatoren nutzen kann.
zu 3.) fällt mir leider nichts dazu ein. Kannst du mir da vielleicht nen Link oder so geben, wo das Prinzip mal ausführlich erklärt ist? Denke ja nicht, dass das in drei Sätzen hier im Forum geht
Ich denke, in deinen Punkten steckt mehr Wahrheit als mir lieb ist
Ich würde mich freuen, wenn du mir da weitere Infos geben könntest oder Tipps, wie ich das vermeiden kann oder vielleicht sogar erklären, warum es im Release-Mode geht und im Debug-Mode nicht?
Bin wirklich für jeden Hinweis dankbar, da sich das selbe Problem gerade wieder einstellen will. (muss ich aber erst noch genauer prüfen).
Der eigentliche Speicher (für die Daten mit denen SSE-Operationen ausgeführt werden) wird in der DLL angefordert. Und zwar meist im Konstruktor der Vektorklasse. Auf die Vektoren greife ich ja über den []-operator der Matrixklasse zu. Auch von der *.exe aus.
zu 1.) Die *.dll und die *.exe sind mit dem gleichen Compiler gebaut (aktueller MinGW aus dem Qt 4.6-SDK). Die *.dll wurde mittels den Qt-Möglichkeiten zur Libraryprogrammierung gebaut.
zu 2.) Den SSE-Speicher gebe ich erst bei Zerstörung des Objekts (also der Matrix) frei. Wollte eigentlich schon gerne eine C++ - API haben, damit ich die Matrizenklasse mit ihren Operatoren nutzen kann.
zu 3.) fällt mir leider nichts dazu ein. Kannst du mir da vielleicht nen Link oder so geben, wo das Prinzip mal ausführlich erklärt ist? Denke ja nicht, dass das in drei Sätzen hier im Forum geht
Ich denke, in deinen Punkten steckt mehr Wahrheit als mir lieb ist
Bin wirklich für jeden Hinweis dankbar, da sich das selbe Problem gerade wieder einstellen will. (muss ich aber erst noch genauer prüfen).
Hi,
Habe in letzter Zeit versucht, etwas Abstand zu gewinnen und mit anderen Entwicklern mal geredet.
Also den SSE2-fähigen Speicher gibt die Matrixklasse eigentlich in der DLL wieder frei. Da wird er ja auch im Konstruktor angefordert. Also sollte das eigentlich funktionieren.
Die Punkte von odenter habe ich "überprüft" indem ich die Matrixlibrary (h- und cpp-Files) einfach mit ins Projekt reincompiliert habe. Wenn es dann fehlerfrei funktioniert hätte, läge es an dem DLL-Interface. Leider trat da der selbe Fehler auf. Was mir persönlich schon komisch vorkommt.
Naja, auf Anraten eines befreundeten Entwicklers habe ich die Optimierungsstufe im Debugmodus erhöht. Wenn ich das Programm normal kompiliere und die Matrix-DLL im Debug-Modus mit O1-Optimierung kompiliere, dann funktioniert alles soweit. Hoffentlich bleibt das so.
Wäre aber interessant ob jemand ne Erklärung für dieses Verhalten hat. Ich mein, ich bin froh, dass dieser Workaround funktioniert und mir das Debuggen weiter ermöglicht, aber seltsam ist es doch schon, oder?
Grüße,
Kay
Habe in letzter Zeit versucht, etwas Abstand zu gewinnen und mit anderen Entwicklern mal geredet.
Also den SSE2-fähigen Speicher gibt die Matrixklasse eigentlich in der DLL wieder frei. Da wird er ja auch im Konstruktor angefordert. Also sollte das eigentlich funktionieren.
Die Punkte von odenter habe ich "überprüft" indem ich die Matrixlibrary (h- und cpp-Files) einfach mit ins Projekt reincompiliert habe. Wenn es dann fehlerfrei funktioniert hätte, läge es an dem DLL-Interface. Leider trat da der selbe Fehler auf. Was mir persönlich schon komisch vorkommt.
Naja, auf Anraten eines befreundeten Entwicklers habe ich die Optimierungsstufe im Debugmodus erhöht. Wenn ich das Programm normal kompiliere und die Matrix-DLL im Debug-Modus mit O1-Optimierung kompiliere, dann funktioniert alles soweit. Hoffentlich bleibt das so.
Wäre aber interessant ob jemand ne Erklärung für dieses Verhalten hat. Ich mein, ich bin froh, dass dieser Workaround funktioniert und mir das Debuggen weiter ermöglicht, aber seltsam ist es doch schon, oder?
Grüße,
Kay
Zur Lösung des Problems:
Richtig gelöst ist es eigentlich nicht. Aber ich habe einfach die Matrix-DLL immer im Releasemodus kompiliert und verwende diese dann auch in dem Debug-kompilierten Hauptprogramm. Ich weiß, dass das nicht schön ist und eigentlich unter Windows so auch nicht funktionieren sollte, aber es funktioniert. Ist also mehr ein Workaround.
Falls ich dann doch noch Fehler in der Matrix-DLL suche, kompiliere ich sie im Debug-Modus und kann mit meinen Testprogrammen dann in die Library hinein debuggen.
Richtig gelöst ist es eigentlich nicht. Aber ich habe einfach die Matrix-DLL immer im Releasemodus kompiliert und verwende diese dann auch in dem Debug-kompilierten Hauptprogramm. Ich weiß, dass das nicht schön ist und eigentlich unter Windows so auch nicht funktionieren sollte, aber es funktioniert. Ist also mehr ein Workaround.
Falls ich dann doch noch Fehler in der Matrix-DLL suche, kompiliere ich sie im Debug-Modus und kann mit meinen Testprogrammen dann in die Library hinein debuggen.
Bessere Lösung
Ich habe mal noch etwas recherchiert und herausgefunden, dass folgendes Compilerflag das Problem beseitigt: "-mpreferred-stack-boundary=2"
Den Hinweis darauf habe ich von folgender Seite:
http://old.nabble.com/ATLAS-on-win32,-p ... 28585.html
und
http://sourceforge.net/tracker/index.ph ... tid=102435
Es funktioniert auch das Compilerflag "-mstackrealign".
Das Problem mit dem SIGSEGV trat immer noch auf und zwar häufig bei Operationen mit zwei __m128d - Datentypen. Beim Disassembly zeigte sich, dass er an dieser Stelle einmal auf ein SSE-Register und auf den Stack zugreift. Und die Stack-Adresse war an dieser Stelle nicht 16byte-Aligned. Der Stackzugriff war an dieser Stelle vom Compiler automatisch generiert worden.
Jedenfalls sorgen die beiden Compilerflags dafür, dass der Stack in der DLL an festen Grenzen ausgerichtet wird. Bei Windows werden DLL-Stacks normalerweise an 4-byte-Grenzen ausgerichtet, was bei bestimmten Konstellationen eben dazu führt, dass manche Variablen eben nicht an einer 16-byte-Grenze liegen. Das Flag "-mstackrealign" ordnet dabei den Stack neu, so dass 4-byte-Code mit 16-byte-Code vermischt werden kann (s. GCC-Doku) und "-mpreferred-stack-boundary" richtet den Stack an einer beliebigen Byte-Grenze aus. Die Bytegrenze berechnet sich dabei aus 2 hoch dem übergebenen Parameterwert. Nun übergebe ich nur eine 2, was also eine 4-byte-Ausrichtung zur Folge hat. An dieser Stelle bin ich auch überfragt. Wenn ich 4 als Parameter übergebe funktioniert die Library jedenfalls nicht mehr.
Welche Variante nun performanter ist muss ich noch sehen.
Vielleicht hilft diese Information auch anderen mal...
Grüße,
Kay
Den Hinweis darauf habe ich von folgender Seite:
http://old.nabble.com/ATLAS-on-win32,-p ... 28585.html
und
http://sourceforge.net/tracker/index.ph ... tid=102435
Es funktioniert auch das Compilerflag "-mstackrealign".
Das Problem mit dem SIGSEGV trat immer noch auf und zwar häufig bei Operationen mit zwei __m128d - Datentypen. Beim Disassembly zeigte sich, dass er an dieser Stelle einmal auf ein SSE-Register und auf den Stack zugreift. Und die Stack-Adresse war an dieser Stelle nicht 16byte-Aligned. Der Stackzugriff war an dieser Stelle vom Compiler automatisch generiert worden.
Jedenfalls sorgen die beiden Compilerflags dafür, dass der Stack in der DLL an festen Grenzen ausgerichtet wird. Bei Windows werden DLL-Stacks normalerweise an 4-byte-Grenzen ausgerichtet, was bei bestimmten Konstellationen eben dazu führt, dass manche Variablen eben nicht an einer 16-byte-Grenze liegen. Das Flag "-mstackrealign" ordnet dabei den Stack neu, so dass 4-byte-Code mit 16-byte-Code vermischt werden kann (s. GCC-Doku) und "-mpreferred-stack-boundary" richtet den Stack an einer beliebigen Byte-Grenze aus. Die Bytegrenze berechnet sich dabei aus 2 hoch dem übergebenen Parameterwert. Nun übergebe ich nur eine 2, was also eine 4-byte-Ausrichtung zur Folge hat. An dieser Stelle bin ich auch überfragt. Wenn ich 4 als Parameter übergebe funktioniert die Library jedenfalls nicht mehr.
Welche Variante nun performanter ist muss ich noch sehen.
Vielleicht hilft diese Information auch anderen mal...
Grüße,
Kay