Frage

Unten ist mein C-Wrapper für eine Fortran ZHEEVR Routine aus bekannter LAPACK numerischer Bibliothek:

void zheevr(char jobz, char range, char uplo, int n, doublecomplex* a, int lda, double vl, double vu, int il, int iu, double abstol, double* w, doublecomplex* z, int ldz, int* info)
{
    int m;
    int lwork = -1;
    int liwork = -1;
    int lrwork = -1;
    int* isuppz = alloc_memory(sizeof(int) * 2 * n);
    zheevr_(&jobz, &range, &uplo, &n, a, &lda, &vl, &vu, &il, &iu, &abstol, &m, w, z, &ldz, isuppz, small_work_doublecomplex, &lwork, small_work_double, &lrwork, small_work_int, &liwork, &info);
    lwork = (int) small_work_doublecomplex[0].real;
    liwork = small_work_int[0];
    lrwork = (int) small_work_double[0];
    doublecomplex* work = alloc_memory(sizeof(doublecomplex) * lwork);
    double* rwork = alloc_memory(sizeof(double) * lrwork);
    int* iwork = alloc_memory(sizeof(int) * liwork);
    zheevr_(&jobz, &range, &uplo, &n, a, &lda, &vl, &vu, &il, &iu, &abstol, &m, w, z, &ldz, isuppz, work, &lwork, rwork, &lrwork, iwork, &liwork, info);
    free(iwork);
    free(rwork);
    free(work);
    free(isuppz);
}

Diese Funktion wird Hunderttausende Male in meiner Anwendung, die so genannten komplexe Matrix „a“ für die gleiche Matrixgröße (Parameternamen der Fortran-Konvention für diese Funktion folgen) diagonalisieren. Ich denke, dass die Arbeit Arrays Größen die gleiche meiste Zeit sein, da die diagonalisierte Matrizen derselben Struktur sein wird. Meine Fragen sind:

  1. Kann die wiederholte Alloc / frei ( "alloc_memory" ist ein einfacher Wrapper um glibc malloc) verletzt Leistung fordert, und wie schlecht?
  2. Ist die Reihenfolge der Materie ist frei? Sollte ich die letzte zugeordnete Array frei ersten oder an?
War es hilfreich?

Lösung

  • Können Sie C99 benutzen? (Antwort: Ja. Sie bereits verwenden C99 Notationen - Variablen deklarieren, wenn erforderlich)
  • Sind die Größen der Arrays sane (nicht zu groß)?

Wenn beide Antworten ‚Ja‘, sollten Sie mit VLAs - variabler Länge Arrays:

void zheevr(char jobz, char range, char uplo, int n, doublecomplex* a, int lda, double vl, double vu, int il, int iu, double abstol, double* w, doublecomplex* z, int ldz, int* info)
{
    int m;
    int lwork = -1;
    int liwork = -1;
    int lrwork = -1;
    int isuppz[2*n];
    zheevr_(&jobz, &range, &uplo, &n, a, &lda, &vl, &vu, &il, &iu, &abstol, &m, w, z, &ldz, isuppz, small_work_doublecomplex, &lwork, small_work_double, &lrwork, small_work_int, &liwork, &info);
    lwork = (int) small_work_doublecomplex[0].real;
    liwork = small_work_int[0];
    lrwork = (int) small_work_double[0];
    doublecomplex work[lwork];
    double rwork[lrwork];
    int iwork[liwork];
    zheevr_(&jobz, &range, &uplo, &n, a, &lda, &vl, &vu, &il, &iu, &abstol, &m, w, z, &ldz, isuppz, work, &lwork, rwork, &lrwork, iwork, &liwork, info);
}

Eine nette Sache über VLAs ist, dass es keine Befreiung von Ihnen durchgeführt werden soll.

(Ungeprüfte Code!)

Andere Tipps

1) Ja, sie können.

2) Jeder vernünftige libc sollte nicht über Bestellung von Sorgen frei (). Performance weise, der sollte nicht wichtig.

würde ich empfehlen, von dieser Funktion Speicherverwaltung zu entfernen - so Anrufer die Matrixgröße und zugeordneten temporären Puffer liefern. Das wird geschnitten Anzahl von mallocs deutlich, wenn diese Funktion von derselben Stelle auf Matrix mit der gleichen Größe genannt wird.

Es wird sicherlich die Leistung auswirken - wie viel Youb nur sicher durch die zeitliche Regelung herausfinden können. So erstellen Sie eine Version, die die meisten Zuweisungen vermeidet, weisen auf einen statischen Zeiger und denken Sie daran, die Größe in einer anderen statischen integer. Wenn der nächste Aufruf die gleiche Größe verwendet, nur wiederverwendet werden, was beim letzten Mal zugeteilt wurde. Nur frei, alles, wenn Sie eine neue Matrix erstellen müssen, da die Größe geändert hat.

Beachten Sie diese Lösung nur für Single-Threaded-Code ist.

In Ordnung. Sie werden bald die Profiler Antwort zu jeder Zeit bekommen. Wenn Sie einen AMD-Rechner haben, empfehle ich den Codeanalyst kostenlosen AMD.

Wie für Ihr Gedächtnis Problem, denke ich, dass Sie mit dem lokalen Speicherverwaltung in diesem Fall funktionieren könnten. bestimmt nur die maximale Anzahl der Speicher, die Sie für diese Funktion zuordnen können. Als Nächstes werden Sie einen statischen Puffer deklarieren und Sie arbeiten mit ihm ein bisschen wie, wie ein Compiler den Stack behandelt. Ich habe einen Wrapper wie diese über VirtualAlloc einmal und es ist sehr schnell.

Wenn Sie die gleiche Größe Artikel Hunderttausende von Zeiten Zuteilung, warum dann nicht nur einen Haufen Ihre Objekte halten (da diese scheinen relativ einfach zu sein, dh keine Hinweise auf andere zugewiesenen Speicher enthalten) und frei auf Ihre eigenen Heap (oder Stack eigentlich)?

Der Haufen träge können neue Objekte zuweisen, die glib malloc verwenden, aber wenn man sich nur schieben Sie das Element auf dem Heap zu befreien. Wenn Sie zuweisen müssen, wenn es ein befreites Objekt vorhanden ist, kann es nur, dass man zuweisen.

Dies wird Ihnen auch mehrere Anrufe auf Zuweisung speichern (da Sie keine Zuordnung tun müssen und es sieht aus wie Ihre Routine mehrere Anrufe auf malloc macht) und wird auch Fragmentierung vermeiden (in gewissem Maße) zumindest auf der re -verwendeter Speicher. Natürlich sind die ursprünglichen Mittelzuweisungen (und andere Zuweisungen wie das Programm ausgeführt wird, wenn es diesen Speicher erweitern muss) kann die Fragmentierung führen, aber wenn Sie wirklich besorgt darüber sind, können Sie einige Statistiken und den Durchschnitt / max / typische Größe Ihres laufen Heap während Läufe und vorbelegt dies sofort, wenn das Programm startet, Fragmentierung zu vermeiden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top