15
$\begingroup$

Consider the following example:

generatef[opt_: "MVM"] := 
 Compile[{}, Module[{j = 0}, Do[j++, {i, 10^8}]; j], CompilationTarget -> opt]

f1 = generatef[];
f2 = generatef["C"];

f1[] // AbsoluteTiming
(* {1.262879, 100000000} *)
f2[] // AbsoluteTiming
(* {0.495352, 100000000} *)

DumpSave["test.mx", f2];

Clear[f2]

<< test.mx

f2[] // AbsoluteTiming
(* {1.295921, 100000000} *)

Tested in v9.0.1, Win8.1 64bit, TDM-GCC 4.9.2, "SystemCompileOptions"->"-Ofast".

Apparently f2 is no longer compiled in C after the save & load, which is undesired. Any solution?

$\endgroup$
  • 1
    $\begingroup$ C compiled is not Mathematica code. There's a function CreateLibrary or something like this to create a dll from mm code. Unfortunately you cannot compile many functions in a single dll. $\endgroup$ – faysou May 9 '15 at 8:58
  • 1
    $\begingroup$ @faysou happily MMA creates a library for us when compiling which we can reload! $\endgroup$ – dr.blochwave May 9 '15 at 9:33
  • 1
    $\begingroup$ Yes, CreateLibrary is practical to know where to export the library. $\endgroup$ – faysou May 9 '15 at 10:02
19
$\begingroup$

Yes, there is! Mathematica creates a LibraryFunction when compiling to C, but puts it in a temporary directory. If you can recover the library, you can load it as often as you like!

First let's define the function as in the question:

generatef[opt_] := 
 Compile[{}, Module[{j = 0}, Do[j++, {i, 10^8}]; j], CompilationTarget -> opt];
f2 = generatef["C"];

Now take the expression f2, and replace the heads of CompiledFunction and LibraryFunction with List. The last bit tells us all the information we need to load function again with LibraryFunctionLoad:

f2List = (f2 /. {CompiledFunction -> List, LibraryFunction -> List})

(* {{10, 10.1, 5468}, {}, {{2, 0, 2}}, {{0, {2, 0, 0}}, 
    {100000000, {2, 0, 1}}, {1, {2, 0, 4}}}, {0, 8, 0, 0, 0}, 
    {{6, 0, 2}, {6, 1, 3}, {6, 0, 5}, {3, 4}, {6, 2, 6}, 
    {12, 6, 4, 7}, {6, 7, 2}, {4, 5, 3, -3}, {1}}, 
    Function[{}, Module[{j = 0}, Do[j++, {i, 100000000}]; j]], Evaluate, 
    {"...\\Mathematica\\ApplicationData\\
      CCompilerDriver\\BuildFolder\\compiledFunction0.dll", 
     "compiledFunction0", {}, Integer}} *)

So now all we need to do is load up the library and run it, with next-to-no-difference in the timing.

f2[] // AbsoluteTiming
(* {0.589635 seconds, 100000000} *)

AbsoluteTiming[
    mynewfunction = LibraryFunctionLoad @@ Last@f2List;
    mynewfunction[]
]
(* {0.584785 seconds, 100000000} *)

Then you need to copy the file out of the temporary directory to a directory of your choice in order to preserve the DLL. Here I've chosen the notebook directory, but you could also put it in one of the directories in $LibraryPath instead and then only have to specify the filename rather than a path.

CopyFile[f2List[[-1, 1]], ToString@NotebookDirectory[] <> "compiledFunction0.dll"]
myf2 = LibraryFunctionLoad[
  ToString@NotebookDirectory[] <> "compiledFunction0.dll", 
      "compiledFunction0", {}, {Integer}];

In this example, the {}, {Integer} refers to the input and output variables as per the documentation, which will obviously be different for different functions.

The final point to note is that trying to overwrite/delete the copied DLL can throw an error if you haven't unloaded the library function via LibraryFunctionUnload first.

I've not tested it on OSX or Linux, but apart from the file extensions (.dll, .dylib, .so) I presume it should all be the same.

$\endgroup$
  • $\begingroup$ Exemplary answer! +1 $\endgroup$ – Sjoerd C. de Vries May 9 '15 at 9:35
  • 1
    $\begingroup$ +1. Perhaps also note that there is a directory that LibraryFunctionLoad automatically searches, so that one can specify a short name of a library, rather than a full path. $\endgroup$ – Jacob Akkerboom May 9 '15 at 10:04
  • $\begingroup$ @JacobAkkerboom yes good point - one could copy the file to that instead. $\endgroup$ – dr.blochwave May 9 '15 at 10:06
  • 1
    $\begingroup$ Actually there's no need to use LibraryFunctionLoad, the only necessary part is to save the DLL to a non-temporary directory. Then one can save & load f2 and recover the C compiled function with something like f2new = ReplacePart[f2, {-1,1} -> (* The file path of the DLL *)]. In this way the RuntimeAttributes of the compiled function will also be recovered so your answer will be fully apply to this question :D $\endgroup$ – xzczd May 9 '15 at 10:59
  • 2
    $\begingroup$ @xzczd not in version 8, which was the current version when I wrote to the MathGroup. I suppose someone might have seen my message or noticed the behavior themselves, because it seems to have been fixed in version 9. $\endgroup$ – Oleksandr R. May 20 '15 at 19:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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