6

Abbiamo interagito con una libreria creata dal compilatore Matlab. Il nostro problema è relativo a un array restituito dalla libreria.Chiamare mxDestroyArray su oggetti mxArray restituiti da Matlab Compiler Runtime

Una volta terminato l'array, vorremmo liberare la memoria, tuttavia, ciò causerebbe occasionali errori di segmentazione.

Ecco la libreria Matlab (bugtest.m) ::

Ecco il comando che abbiamo usato per costruirlo (creando libbugtest.so, e libbugtest.h) ::

mcc -v -W lib:libbugtest -T link:lib bugtest.m 

ecco il nostro C programma di test (bug_destroyarray.c) ::

#include <stdio.h> 
#include <stdlib.h> 

#include "mclmcrrt.h" 
#include "libbugtest.h" 

#define TESTS 15000 

int main(int argc, char **argv) 
{ 
    const char *opts[] = {"-nojvm", "-singleCompThread"}; 
    mclInitializeApplication(opts, 2); 
    libbugtestInitialize(); 

    mxArray *output; 
    mxArray *input; 
    double *data; 
    bool result; 
    int count; 

    for (count = 0; count < TESTS; count++) { 

     input = mxCreateDoubleMatrix(4, 1, mxREAL); 
     data = mxGetPr(input); data[0] = 0.5; data[1] = 0.2; data[2] = 0.2; data[3] = 0.1; 

     output = NULL; 
     result = mlfBugtest(1, &output, input); 
     if (result) { 
      /* HERE IS THE PROBLEMATIC LINE */ 
      /*mxDestroyArray(output);*/ 
     } 

     mxDestroyArray(input); 
    } 

    libbugtestTerminate(); 
    mclTerminateApplication(); 
} 

Qui è come si compila il programma C (creando bug_destroyarray) ::

mbuild -v bug_destroyarray.c libbugtest.so 

Crediamo che mxDestroyArray(output) è problematica.

Abbiamo eseguire il seguente per testare crash:

  • Su ciascuno dei 32 nodi del cluster.
  • Corsa bug_destroyarray.
  • Uscita monitor per errori di segmentazione.

Circa il 10% delle volte si verifica un incidente. Se questo è indipendente tra i nodi , si potrebbe supporre che si stia arrestando circa lo 0,3% delle volte.

Quando eliminiamo questa riga problematica, non siamo in grado di causarne l'arresto.

Tuttavia, l'utilizzo della memoria aumenta gradualmente quando questa linea non è inclusa.

Dalla ricerca che abbiamo fatto, sembra che siamo non supposti per distruggere l'array restituito, in caso contrario, come ci fermiamo dalla perdita di memoria?

Grazie.

+0

Sei sicuro di avere la firma del 'mlfBugtest' corretta? La documentazione sembra indicare che le funzioni di 'mlf' restituiscono' void', non 'bool'. – wakjah

risposta

0

Alcune note:

  • non vedo singleCompThread nella lista delle opzioni consentite per mclInitializeApplication.

  • Il modo recommended di compilare il programma C è quello di collegare in modo dinamico contro la libreria compilata:

    mbuild -v -I. bug_destroyarray.c -L. -lbugtest 
    
  • Nella parte superiore del vostro programma C, è sufficiente includere il file di intestazione generato, includerà altre intestazioni a sua volta.Guardando l'intestazione generato, esso ha:

    #pragma implementation "mclmcrrt.h" 
    #include "mclmcrrt.h" 
    

    non so l'esatto significato di questa linea pragma, ma forse le questioni con i compilatori GCC ..

  • Il fatto che sia MLX/MLF generato le funzioni return booleans è undocumented. Ma guardando i file header, entrambe le firme effettivamente restituiscono un bool:

    extern bool mlxBugtest(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]); 
    extern bool mlfBugtest(int nargout, mxArray** x, mxArray* y); 
    

ho provato il codice e funziona bene senza segfaults. Poiché non ho accesso a un cluster di computer, il mio test è stato eseguito solo sulla mia macchina locale (WinXP con R2013a).

Ho dovuto rimuovere entrambe le opzioni di inizializzazione MCR per farlo funzionare (in particolare il nojvm ha causato un errore di runtime). Di seguito è riportato il codice completo con leggere modifiche. Ci sono voluti circa 10 secondi per eseguire:

#include <stdio.h> 
#include <stdlib.h> 
#include "libbugtest.h" 

#define TESTS 15000 

int main() 
{ 
    mxArray *output, *input; 
    double *data; 
    int count; 
    bool result; 

    if(!mclInitializeApplication(NULL,0)) { 
     fprintf(stderr, "Could not initialize the application.\n"); 
     return EXIT_FAILURE; 
    } 
    if (!libbugtestInitialize()) { 
     fprintf(stderr, "Could not initialize the library.\n"); 
     return EXIT_FAILURE; 
    } 

    for (count = 0; count < TESTS; count++) { 
     input = mxCreateDoubleMatrix(4, 1, mxREAL); 
     data = mxGetPr(input); 
     data[0] = 0.5; data[1] = 0.2; data[2] = 0.2; data[3] = 0.1; 

     output = NULL; 
     result = mlfBugtest(1, &output, input); 
     if (!result) { 
      fprintf(stderr, "call failed on count=%d\n", count); 
      return EXIT_FAILURE; 
     } 

     mxDestroyArray(output); output = NULL; 
     mxDestroyArray(input); input = NULL; 
    } 

    libbugtestTerminate(); 
    mclTerminateApplication(); 

    return EXIT_SUCCESS; 
} 

Anche la fase di compilazione è un po 'diverso su Windows, dal momento che colleghiamo staticamente contro la lib di importazione (che inserisce uno stub per caricare dinamicamente la DLL in fase di esecuzione):

mbuild -v -I. bug_destroyarray.c libbugtest.lib 
0

Grazie per la risposta dettagliata Amro.

Abbiamo provato a modificare i passaggi della compilazione a quelli consigliati, senza successo.

Il seguente fissa nostro seg-faulting problema:

  • Non impostare output = NULL ad ogni iterazione, invece farlo una volta al di fuori del ciclo.
  • Non chiamare mxDestroyArray(output) all'interno del ciclo, riferimento: here.

Il nostro fraintendimento era che (sembra) si suppone di riutilizzare i puntatori mxArray che si passano alle funzioni MATLAB. Rende le cose leggermente ingombranti dalla nostra parte, poiché dobbiamo fare attenzione a riutilizzare questo puntatore.

Tuttavia, la memoria è completamente stabile e da allora non si è verificato un arresto anomalo.

+0

Penso che tu confonda le cose su questo secondo punto. La pagina a cui ti sei collegato è intesa nel contesto delle funzioni MEX (dove non vuoi liberare il lato sinistro restituito a MATLAB). Per quanto riguarda l'altro punto, i [doc] (http://www.mathworks.com/help/compiler/matlab-compiler-generated-interface-functions.html#f2-1008549) dicono chiaramente che "Se le variabili di output che si passare a una funzione mlf non è NULL, la funzione mlf tenterà di liberarli usando mxDestroyArray. ". Quindi non ci dovrebbe essere alcuna differenza se si libera in modo esplicito la memoria da soli o lasciare che la funzione di FML farlo – Amro

+0

Ahh ok, grazie per la spiegazione. Non avrei dovuto dire mai, intendevo solo non all'interno del ciclo. Tutto ha senso ora e funziona correttamente. Saluti. – user2427155

1

Va bene, so che questo è un po 'vecchio ora, ma nel caso in cui aiuta a chiarire le cose per tutti coloro che passano da ...

Amro fornisce le informazioni più pertinenti, ma per espandere su di essa, se si don' t chiamare la funzione mxDestroyArray allo stato attuale, quindi si verificherà una perdita di memoria, poiché l'uscita è stata impostata su NULL e quindi la funzione mlf non tenterà di chiamare mxDestroyArray. Il corollario di questo è che se hai chiamato mxDestroyArray E poi prova a chiamare la funzione mlf AND output NON è NULL, quindi la funzione mlf proverà a chiamare mxDestroyArray su output. La domanda quindi è su cosa deve fare il punto output? È un angolo un po 'buio quello che succede a output dopo averlo passato a mxDestroyArray. Direi che è una supposizione ingiustificata che sia impostato su NULL; non è certamente documentato che mxDestroyArray imposta il suo argomento su NULL.Pertanto, sospetto che ciò che sta accadendo sia che tra la tua chiamata a mxDestroyArray e il codice che riattiva la funzione mlf, a qualcos'altro è stata assegnata la memoria puntata da output e quindi la tua funzione mlf prova a liberare memoria appartenente a qualcos'altro. Voila, seg colpa. E naturalmente questo accadrà solo se la memoria è stata riassegnata. A volte sarai fortunato, a volte no.

La regola d'oro è che se si sta chiamando mxDestroyArray te stesso per qualcosa che sta per essere riutilizzate, impostare il puntatore NULL subito dopo. Hai solo davvero bisogno di distruggere roba alla fine della tua funzione in ogni caso, perché puoi tranquillamente riutilizzare le variabili di output nelle chiamate mlf.

Guy

+0

Vorrei poter trovare un buon riferimento per questo. Il meglio che posso trovare è [Integrate C Shared Libraries] (http://www.mathworks.com/help/compiler/c-shared-library-target.html) –