ich habe ein Problem mit einer mex Funktion, die ich geschrieben habe. Sie berechnet den Wert eines vierfach Integrals. Da das in Matlab eher lange dauert, habe ich das als mex Funktion (Test.cpp) geschrieben.
void mexFunction(int nlhs, mxArray *plhs[], int nrhs,
const mxArray *prhs[]){
/* For matrix A (m x n) the element A[a, b]is accessed
* lineraly in Matlab by A[(b - 1) * m + a]. Since indices
* in C++ start with zero, the same element corresponds
* to A[b * m + a].
*
* delta : double scalar
* path : (1 x nSteps + 1)double vector
* mat_A : (nSteps x nSteps + 1)double matrix
* mat_B : (nSteps x nSteps + 1)double matrix
*/
double delta = *mxGetPr(prhs[0]);
double *path = mxGetPr(prhs[1]);
double *mat_A = mxGetPr(prhs[2]);
double *mat_B = mxGetPr(prhs[3]);
starten.
Das komische ist nun die Laufzeit. 'time' ist verschwinded klein, 'time1' ist ca 6 Sekunden und der ganz Call von Test() auch in etwa 6 Sekunden dauert.
Warum liefert die innere Messung kaum Zeit, während die äußere erheblich länger dauert?
Hat jemand eine Idee, wie man das beschleunigen kann?
, dann, in der v-Schleife brauchen wir diese Summeund multiplizieren sie, etc, etc...
Meiner Meinung nach ist das so verschachtelt, dass man nicht vektorisieren kann. Natürlich bin ich aber gerne bereit, mich vom Gegenteil überzeigen zu lassen .
Viele Grüße
Vladi
Vladi
Gast
Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
Verfasst am: 03.12.2015, 13:15
Titel:
Ach übrigens sind die konstanten Matritzen natürlich nur zum testn. Im eigentlichen Programm sind die Zahlen komplett unterschiedlich! Sorry dafür!!!
Wenn Du mat_A und mat_B transponierst, ersparst Du dem Rechner eine Menge Multiplikationen und er kann auf benachbarte Speicher-Bereiche zugreifen, die in Blöcken in den Prozessor-Cache geladen werden.
Code:
for(int v = t; v < nSteps; v++){ double I_dWr = 0.0;
for(int r = t; r < v + 1; r++){
I_dWr += mat_A[r * nSteps + s];
}
I_dv += mat_B[v * nSteps + t] * I_dWr;
}
Mit OpenMP kannst du bestimmt auch noch was rausholen. Zumindest wenn du nicht schon am Bandbreitenlimit hängst bzw. dir durch Parallelisierung deine Cachelines zerschiesst.
Vladi
Gast
Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
Verfasst am: 04.12.2015, 11:10
Titel:
Hallo zusammen.
Schonmal vielen Dank für die verschiedenen Vorschläge.
Hier ist noch der zur mex äquivalente Matlab code.
Code:
tic
I_ds = 0;
for s = 1 : nSteps
I_dt = 0;
for t = s : nSteps
I_dv = 0;
for v = t : nSteps
I_dWr = 0;
for r = t : v
I_dWr = I_dWr + mat_A(s, r);
end
I_dv = I_dv + mat_B(t, v) * I_dWr;
end
I_dv = I_dv * delta;
I_dt = I_dt + path(t) * I_dv;
end
I_dt = I_dt * delta;
I_ds = I_ds + path(s) * I_dt;
end
I_ds = I_ds * delta;
toc
Die Laufzeitunterschiede werden (logisch) mit größerem nSteps extremer.
Wie ich bereits geschrieben habe, denke ich, dass vektorisieren schwierig ist, bin aber bereits meine Meinung zu ändern
Damit hätte man die beiden inneren Schleifen vektorisiert und das sollte sich in der Laufzeit bemerkbar machen.
Auch hier tritt der gleiche Effekt auf wie in einer Mex-Funktion: Der Zugriff auf das langsame RAM bremst stark, wenn die beiden Matrizen nicht mehr in den Prozessor-Cache passen. Ein Transponieren der Matrizen würde es erlauben, dass auf benachbarte Speicherzellen zugegriffen wird, was im Allgemeinen die Bearbeitungsgeschwindigkeit deutlich steigert.
Gruß, Jan
Vladi
Gast
Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
Verfasst am: 04.12.2015, 14:35
Titel:
Hallo Jan,
deine Version funktioniert super! Danke hierfür. Stimmt, an cumsum hatte ich gar nicht gedacht Auch werde ich das mit dem Transponieren probieren. Vielleicht bringt das auch noch etwas...
An all die Matlab-Profis: Geht vielleicht noch mehr? Kan noch mehr zusammengefasst werden?
Vielen Dank schonmal an alle!
Vladi
Gast
Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
Verfasst am: 04.12.2015, 15:08
Titel:
Ok, getestet: Transponieren führt nochmal zu einer Verbesserung. Der aktuelle Code (nur Matlab) sieht jetzt (dank Jan S) so aus:
Damit sinkt die Laufzeit von 1.72 auf 0.55 Sekunden.
Die eigentlichen Berechnungen in der innersten Schleife sind nun sehr elementar. Das ist einer der seltenen Fälle, in denen der C-Code hübscher aussieht als der Matlab Code! :-)
Gruß, Jan
Zuletzt bearbeitet von Jan S am 13.12.2015, 01:28, insgesamt einmal bearbeitet
Vladi
Gast
Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
Verfasst am: 06.12.2015, 01:09
Titel:
Hallo Jan,
Respekt!
Vielen Dank für die gute Analyse und deine Mühe, auch besonders für die mex Datei. Ich werde das testen sobald ich Matlab wieder griffbereit habe. Nach deinen Laufzeiten zu schließen bin ich bereits sehr optimistisch!
Das beste an der Sache... Insgesamt habe ich 11 von diesen 4-fach Integralen, so dass die Laufzeit des Codes erheblich reduziert wird.
Gerne!
Das war ein sehr schönes Beispiel für Code-Optimierung:
1. Den Matlab-Code so weit entschlacken, wie möglich.
2. Dann wird der Bottleneck klar.
3. Nur diesen in ein C-Mex auslagern.
Wenn die hauptsächliche Arbeit nicht von einer BLAS/LAPACK-Funktion ausgeführt wird, ist der C-Code oft schneller.
Der Zugriff auf benachbarte Speicher-Zellen ist effizienter als durch das RAM zu springen.
Wenn Du nun noch die äußeren Schleifen dur PARFOR-Loops ersetzt, sollte der Rechner sein bestes gegen.
Anmerkungen: Da einem C-Mex-Code um die Ohren fliegt, wenn die Inputs falsch sind, lohnt es sich nich ein paar Micro-Sekunden in die Prüfung der Inputs zu investieren: Sitmmen Typ und Dimension?
"path" ist eine wichtige Matlab-Funktion. Den Namen für eine Variable zu verwenden, kann sehr verwirrende Auswirkungen haben, z.B. während des Debuggens.
Gruß, Jan
Einstellungen und Berechtigungen
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.