11
$\begingroup$

Bug introduced in 9.0 or earlier and fixed in 10.3


Update

As Todd Gayley commented under halirutan's answer, this is a bug.


I'm trying link one of Lapack's function to Mathematica through LibraryLink, and the Library function works great at the first execution but crashes at the second time.

Here is the code (modified from here)

MMASrc="
#include <WolframLibrary.h>
#include <WolframCompileLibrary.h>

DLLEXPORT mint WolframLibrary_getVersion(){
  return WolframLibraryVersion;
}
DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData){
  return 0;
}

EXTERN_C void zspsv_(char* UPLO, const mint* N, mint* NRHS, mcomplex* A, mint* IPIV, mcomplex* B, mint* LDB, mint* INFO);


EXTERN_C DLLEXPORT int lpkSolveAXBS(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res){

  MTensor ta=MArgument_getMTensor(Args[0]);
  MTensor tb=MArgument_getMTensor(Args[1]);
  mint N=*MTensor_getDimensionsMacro(tb);
  mcomplex* A=MTensor_getComplexDataMacro(ta);
  mcomplex* B=MTensor_getComplexDataMacro(tb);

  char U='U';
  mint IPIV[N];
  mint NRHS=1;
  mint LDA=N,LDB=N;
  mint INFO;
  mint i,j;

  mcomplex AP[N*(N+1)/2];

  for(j=0;j<N;j++)
    for(i=0;i<=j;i++)
      AP[i + (j+1)*j/2] = A[i*N+j];

  zspsv_(&U,&N,&NRHS,AP,IPIV,B,&LDB,&INFO);

  MArgument_setMTensor(Res,tb);
  return LIBRARY_NO_ERROR;
}


";
Needs["CCompilerDriver`"];

CreateLibrary[MMASrc,"lpk","Debug"->True,"TargetDirectory"->"/tmp",
        "CompileOptions"->"-llapack"];

A={{1. +0. I,0. +0. I,0. -6.94908*^-13 I,0. -6.94908*^-13 I},
           {0. +0. I,1. +0.0352595 I,0. -4.51893*^-11 I,0. -4.51893*^-11 I},
           {0. -6.94908*^-13 I,0. -4.51893*^-11 I,1. +0.0376938 I,0. +0. I},
           {0. -6.94908*^-13 I,0. -4.51893*^-11 I,0. +0. I,1. +0.0378932 I}};

B={1. +0. I,0. +0. I,0. +6.94908*^-13 I,0. +6.94908*^-13 I};

lpkSolve=LibraryFunctionLoad["/tmp/lpk.dylib","lpkSolveAXBS",
        {{Complex,2},{Complex,1}},{Complex,1}]
(*LibraryFunction[<>,lpkSolveAXBS,{{Complex,2},{Complex,1}},{Complex,1}]*)

Abs[LinearSolve[A,B]-lpkSolve[A,B]]//Max
(*2.02047*10^-28*)

Table[LinearSolve[A,B],{40000}];//AbsoluteTiming
(*{0.470767,Null}*)

Table[lpkSolve[A,B],{40000}];//AbsoluteTiming
(*{0.086038,Null}*)

Table[lpkSolve[A,B],{40000}];//AbsoluteTiming

In executing In[10], I hear a beep sound and then the kernel crashes and there is no output. Why the kernel crashes at the second time of invoking the LibraryLink function? How to fix that?

$\endgroup$
12
  • $\begingroup$ The link to the source of the code is missing. $\endgroup$ Jul 25, 2013 at 6:42
  • $\begingroup$ @b.gatessucks thanks for point it out, I meant to use lpkSolve instead of LinearSolve in In[10], but I see both cause the kernel to crash. I'll correct it so that it wouldn't cause confusion. $\endgroup$ Jul 25, 2013 at 6:49
  • $\begingroup$ @SjoerdC.deVries I've corrected that. Thanks for pointing out. $\endgroup$ Jul 25, 2013 at 6:55
  • $\begingroup$ @xslittlegrass, I don't know the answer to your question, but would you be interested in a top level interface to BLAS and/or LAPACK? Concerning the crash, I'd send that to the technical support. $\endgroup$
    – user21
    Jul 25, 2013 at 9:30
  • 2
    $\begingroup$ @xslittlegrass For the sake of future visitors, could you reconsider taking any of the current answers as accepted answer? I explained in chat that what you experience is clearly a bug and cloning the tensor is not a solution neither is the documentation wrong. I talked to Todd Gayley, one of the persons in charge of LibraryLink at Wolfram. Please look at his comment under my answer. $\endgroup$
    – halirutan
    Aug 6, 2013 at 1:13

2 Answers 2

7
$\begingroup$

An observation, rather than an answer to the why question.

The question suggests, that the problem might have something to do with the used lapack library. As it turns out, at least on my machine it doesn't. We can replace the C-code with the most simple routine which is taking an input tensor and returning exactly the same tensor as result.

MTensor ta = MArgument_getMTensor(Args[0]);
MArgument_setMTensor(Res,ta);
return LIBRARY_NO _ERROR;

Now, the underlying problem seems to be the very small numbers which were used as input. We can pin it down to 0. + 6.94908*^-13 I which seems to be the cause. Unfortunately, there is another important ingredient to crash the kernel: it's the usage of Table. When I try the same with Do or ConstantArray it works. Array crashed my Mathematica completely. Therefore, to make it more fun for you too, please ensure that you really have some unsaved notebooks open, when you try this.

So while this crashes the kernel

Table[testFunc[{0. - 6.94908*^-13 I}], {40000}];
Table[testFunc[{0. - 6.94908*^-13 I}], {40000}];

this does not, even if I evaluate it several times

Do[testFunc[{0. - 6.94908*^-13 I}], {40000}];
Do[testFunc[{0. - 6.94908*^-13 I}], {40000}];

the same is true for ConstantArray.

Test Code

MMASrc =     
  "# include <WolframLibrary.h>
   # include <WolframCompileLibrary.h>

   DLLEXPORT mint WolframLibrary_getVersion(){
     return WolframLibraryVersion;
   }

   DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData){
     return 0;
   }

   EXTERN_C DLLEXPORT int test(
     WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res){

     MTensor ta=MArgument_getMTensor(Args[0]);
     MArgument_setMTensor(Res,ta);
     return LIBRARY_NO_ERROR;
   }";

Needs["CCompilerDriver`"];
lib = CreateLibrary[MMASrc, "test", "Debug" -> True, "TargetDirectory" -> "/tmp"];
testFunc = LibraryFunctionLoad[lib, "test", {{Complex, 1}}, {Complex, 1}];
$\endgroup$
7
  • $\begingroup$ I feel your pain, but did you really have unsaved notebooks open when testing this? $\endgroup$ Jul 25, 2013 at 11:16
  • $\begingroup$ @SjoerdC.deVries Fortunately, only the notebook with the toy-code above. Therefore, I only had to edit the OP's code again to get the reduced example. $\endgroup$
    – halirutan
    Jul 25, 2013 at 13:34
  • $\begingroup$ In principle, you don't need to use FileNames to get the full path of the libs as "SystemIncludeDirectories" -> Automatic should handle that. $\endgroup$
    – rcollyer
    Jul 25, 2013 at 13:37
  • $\begingroup$ @rcollyer Yes, thanks. I simplified the post. $\endgroup$
    – halirutan
    Jul 25, 2013 at 13:40
  • 8
    $\begingroup$ The crash in this sample code is clearly a bug. It should work with the default Automatic passing. And it cannot be made to work no matter what tensor-passing convention you specify. I've reported the bug, and if I get any further details I will report back. $\endgroup$ Jul 30, 2013 at 6:09
3
$\begingroup$

Have a look at the memory management write up for tensor. I suspect you are returning a pointer to an automatic tensor that is being cleaned up.

LibrayLink Interaction

Can you elaborate more on your thoughts, because I read the documentation exactly the opposite way: "For automatic passing, the MTensor is owned by the library function only when that call to the library is active. The function can return the MTensor whether it has been modified or not, but whatever happens, the MTensor cannot be used after the function has returned

Yes. I believe the docs are in error. If you clone an input tensor, or create a new one, and return it the kernel will not crash.

It is my belief that on automatic copy in a temporary pointer is created. On an automatic return a copy is not made but returned directly. So if you return an input tensor you are returning a tensor pointing to memory that is going to be destroyed. A crash is inevitable.

This works just fine ...

    MMASrc = 
"#include <WolframLibrary.h>
#include <WolframCompileLibrary.h>

DLLEXPORT mint WolframLibrary_getVersion(){
     return WolframLibraryVersion;
}

DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData){
     return 0;
}
EXTERN_C DLLEXPORT int test(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res){

MTensor T0;
T0=0;
MTensor ta=MArgument_getMTensor(Args[0]);
libData->MTensor_clone( ta, &T0);

MArgument_setMTensor(Res,T0);
     return LIBRARY_NO_ERROR;
}";

Needs["CCompilerDriver`"];
lib=CreateLibrary[MMASrc,"test","Debug"->True, "TargetDirectory"->"/tmp"];
testFunc=LibraryFunctionLoad[lib,"test",{{Complex,1}},{Complex,1}];
Table[testFunc[{0.-6.94908^-13I}],{40000}];
Table[testFunc[{0.-6.94908^-13I}],{40000}];
Table[testFunc[{0.-6.94908^-13I}],{40000}];
Table[testFunc[{0.-6.94908^-13I}],{40000}];
$\endgroup$
6
  • $\begingroup$ Can you elaborate more on your thoughts, because I read the documentation exactly the opposite way: "For automatic passing, the MTensor is owned by the library function only when that call to the library is active. The function can return the MTensor whether it has been modified or not, but whatever happens, the MTensor cannot be used after the function has returned." $\endgroup$
    – halirutan
    Jul 26, 2013 at 1:01
  • $\begingroup$ See my added comments above. $\endgroup$
    – Eric M
    Jul 27, 2013 at 15:56
  • $\begingroup$ OK, +1 for trying this out. So this suggests, that there are two copies needed, because automatic passing already creates a copy of input tensors and then you have to clone it again? And why does this happens with Table and the small numbers only? $\endgroup$
    – halirutan
    Jul 27, 2013 at 21:49
  • $\begingroup$ Thanks for the answer. It works! You mentioned "automatic copy in a temporary pointer is created", what do you mean the temporary pointer, what's its relation to the tensor ta created in the library function? If it is due to the clean process, why it still crash when we use manual pass as testFunc=LibraryFunctionLoad[lib,"test",{{Complex,1,"Manual"}},{Complex,1}];? Since in the manual pass, it will "pass in a copy of the MTensor and do not automatically clean". $\endgroup$ Jul 29, 2013 at 1:58
  • $\begingroup$ And in order to save the time and memory for large matrixes, is it possible to use the disown features or shared passing etc instead of using the cloning process? $\endgroup$ Jul 29, 2013 at 2:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.