Skip to main content
replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

A lot depends on how you write your code in Mathematica. In my experience, the rule of thumb is that the generated code will be efficient if the code inside Compile more or less resembles the code I would write in plain C (and it is clear why). Idiomatic (high-level) Mathematica code tends to be immutable. At the same time, Compile can handle a number of higher-level functions, such as Transpose, Partition, Map, MapThread, etc. Most of these functions return expressions, and even though these expressions are probably passed to the calling function, they must be created. For example, a call to ReplacePart which replaces a single part in a large array will necessarily lead to copying of that array. Thus, immutability generally implies creating copies.

So, if you write your code in this style and hand it to Compile, you have to keep in mind that lots of small (or large) memory allocations on the heap, and copying of lists (tensors) will be happening. Since this is not apparent for someone who is used to high-level Mathematica programming, the slowdown this may incur may be surprising. See thisthis and thisthis answers for examples of problems coming from many small memory allocations and copying, as well as a speed-up one can get from switching from copying to in-place modifications.

As noted by @acl, one thing worth doing is to set the SystemOptions -> "CompileOptions" as

SetSystemOptions[ "CompileOptions" -> "CompileReportExternal" -> True]

in which case you will get warnings for calling external functions etc.

A good tool to get a "high-level" but precise view on the generated code is the CompilePrint function in the CompiledFunctionTools` package. It allows you to print the pseudocode version of the byte-code instructions generated by Compile. Things to watch for in the printout of CompilePrint function:

  • Calls to CopyTensor
  • Calls to MainEvaluate (callbacks to Mathematica, meaning that something could not be compiled down to C)

One not very widely known technique of writing even large Compile-d functions and combining them from pieces so that there is no performance penalty, is based on inlining. I consider this answerthis answer very illustrative in this respect - I actually posted it to showcase the technique. You can also see this answerthis answer and a discussion in the comments below, for another example of how this technique may be applied.

In summary - if you want your code to be as fast as possible, think about "critical" places and write those in "low-level" style (loops, assignments, etc) - the more it will resemble C the more chances you have for a speed-up (for an example of a function written in such a style and being consequently very fast, see the seqposC function from this answerthis answer). You will have to go against Mathematica ideology and use a lot of in-place modifications. Then your code can be just as fast as hand-written one. Usually, there are just a few places in the program where this matters (inner loops, etc) - in the rest of it you can use higher-level functions as well.

A lot depends on how you write your code in Mathematica. In my experience, the rule of thumb is that the generated code will be efficient if the code inside Compile more or less resembles the code I would write in plain C (and it is clear why). Idiomatic (high-level) Mathematica code tends to be immutable. At the same time, Compile can handle a number of higher-level functions, such as Transpose, Partition, Map, MapThread, etc. Most of these functions return expressions, and even though these expressions are probably passed to the calling function, they must be created. For example, a call to ReplacePart which replaces a single part in a large array will necessarily lead to copying of that array. Thus, immutability generally implies creating copies.

So, if you write your code in this style and hand it to Compile, you have to keep in mind that lots of small (or large) memory allocations on the heap, and copying of lists (tensors) will be happening. Since this is not apparent for someone who is used to high-level Mathematica programming, the slowdown this may incur may be surprising. See this and this answers for examples of problems coming from many small memory allocations and copying, as well as a speed-up one can get from switching from copying to in-place modifications.

As noted by @acl, one thing worth doing is to set the SystemOptions -> "CompileOptions" as

SetSystemOptions[ "CompileOptions" -> "CompileReportExternal" -> True]

in which case you will get warnings for calling external functions etc.

A good tool to get a "high-level" but precise view on the generated code is the CompilePrint function in the CompiledFunctionTools` package. It allows you to print the pseudocode version of the byte-code instructions generated by Compile. Things to watch for in the printout of CompilePrint function:

  • Calls to CopyTensor
  • Calls to MainEvaluate (callbacks to Mathematica, meaning that something could not be compiled down to C)

One not very widely known technique of writing even large Compile-d functions and combining them from pieces so that there is no performance penalty, is based on inlining. I consider this answer very illustrative in this respect - I actually posted it to showcase the technique. You can also see this answer and a discussion in the comments below, for another example of how this technique may be applied.

In summary - if you want your code to be as fast as possible, think about "critical" places and write those in "low-level" style (loops, assignments, etc) - the more it will resemble C the more chances you have for a speed-up (for an example of a function written in such a style and being consequently very fast, see the seqposC function from this answer). You will have to go against Mathematica ideology and use a lot of in-place modifications. Then your code can be just as fast as hand-written one. Usually, there are just a few places in the program where this matters (inner loops, etc) - in the rest of it you can use higher-level functions as well.

A lot depends on how you write your code in Mathematica. In my experience, the rule of thumb is that the generated code will be efficient if the code inside Compile more or less resembles the code I would write in plain C (and it is clear why). Idiomatic (high-level) Mathematica code tends to be immutable. At the same time, Compile can handle a number of higher-level functions, such as Transpose, Partition, Map, MapThread, etc. Most of these functions return expressions, and even though these expressions are probably passed to the calling function, they must be created. For example, a call to ReplacePart which replaces a single part in a large array will necessarily lead to copying of that array. Thus, immutability generally implies creating copies.

So, if you write your code in this style and hand it to Compile, you have to keep in mind that lots of small (or large) memory allocations on the heap, and copying of lists (tensors) will be happening. Since this is not apparent for someone who is used to high-level Mathematica programming, the slowdown this may incur may be surprising. See this and this answers for examples of problems coming from many small memory allocations and copying, as well as a speed-up one can get from switching from copying to in-place modifications.

As noted by @acl, one thing worth doing is to set the SystemOptions -> "CompileOptions" as

SetSystemOptions[ "CompileOptions" -> "CompileReportExternal" -> True]

in which case you will get warnings for calling external functions etc.

A good tool to get a "high-level" but precise view on the generated code is the CompilePrint function in the CompiledFunctionTools` package. It allows you to print the pseudocode version of the byte-code instructions generated by Compile. Things to watch for in the printout of CompilePrint function:

  • Calls to CopyTensor
  • Calls to MainEvaluate (callbacks to Mathematica, meaning that something could not be compiled down to C)

One not very widely known technique of writing even large Compile-d functions and combining them from pieces so that there is no performance penalty, is based on inlining. I consider this answer very illustrative in this respect - I actually posted it to showcase the technique. You can also see this answer and a discussion in the comments below, for another example of how this technique may be applied.

In summary - if you want your code to be as fast as possible, think about "critical" places and write those in "low-level" style (loops, assignments, etc) - the more it will resemble C the more chances you have for a speed-up (for an example of a function written in such a style and being consequently very fast, see the seqposC function from this answer). You will have to go against Mathematica ideology and use a lot of in-place modifications. Then your code can be just as fast as hand-written one. Usually, there are just a few places in the program where this matters (inner loops, etc) - in the rest of it you can use higher-level functions as well.

Added some notes on immutability and copying
Source Link
Leonid Shifrin
  • 114.9k
  • 16
  • 333
  • 424

A lot depends on how you write your code in Mathematica. In my experience, the rule of thumb is that the generated code will be efficient if the code inside Compile more or less resembles the code I would write in plain C (and it is clear why). Idiomatic (high-level) Mathematica code tends to be immutable. At the same time, Compile can handle a number of higher-level functions, such as Transpose, Partition, Map, MapThread, etc. Most of these functions return expressions, and even though these expressions are probably passed to the calling function, they must be created. For example, a call to ReplacePart which replaces a single part in a large array will necessarily lead to copying of that array. Thus, immutability generally implies creating copies.

So, if you write your code in this style and hand it to Compile, you have to keep in mind that lots of small (or large) memory allocations on the heap, and copying of lists (tensors) will be happening. Since this is not apparent for someone who is used to high-level Mathematica programming, the slowdown this may incur may be surprising. See this and this answers for examples of problems coming from many small memory allocations and copying, as well as a speed-up one can get from switching from copying to in-place modifications.

As noted by @acl, one thing worth doing is to set the SystemOptions -> "CompileOptions" as

SetSystemOptions[ "CompileOptions" -> "CompileReportExternal" -> True]

in which case you will get warnings for calling external functions etc.

A good tool to get a "high-level" but precise view on the generated code is the CompilePrint function in the CompiledFunctionTools` package. It allows you to print the pseudocode version of the byte-code instructions generated by Compile. Things to watch for in the printout of CompilePrint function:

  • Calls to CopyTensor
  • Calls to MainEvaluate (callbacks to Mathematica, meaning that something could not be compiled down to C)

One not very widely known technique of writing even large Compile-d functions and combining them from pieces so that there is no performance penalty, is based on inlining. I consider this answer very illustrative in this respect - I actually posted it to showcase the technique. You can also see this answer and a discussion in the comments below, for another example of how this technique may be applied.

In summary - if you want your code to be as fast as possible, think about "critical" places and write those in "low-level" style (loops, assignments, etc) - the more it will resemble C the more chances you have for a speed-up (for an example of a function written in such a style and being consequently very fast, see the seqposC function from this answer). You will have to go against Mathematica ideology and use a lot of in-place modifications. Then your code can be just as fast as hand-written one. Usually, there are just a few places in the program where this matters (inner loops, etc) - in the rest of it you can use higher-level functions as well.

A lot depends on how you write your code in Mathematica. In my experience, the rule of thumb is that the generated code will be efficient if the code inside Compile more or less resembles the code I would write in plain C (and it is clear why). Idiomatic (high-level) Mathematica code tends to be immutable. At the same time, Compile can handle a number of higher-level functions, such as Transpose, Partition, Map, MapThread, etc.

So, if you write your code in this style and hand it to Compile, you have to keep in mind that lots of small (or large) memory allocations on the heap, and copying of lists (tensors) will be happening. Since this is not apparent for someone who is used to high-level Mathematica programming, the slowdown this may incur may be surprising. See this and this answers for examples of problems coming from many small memory allocations and copying, as well as a speed-up one can get from switching from copying to in-place modifications.

As noted by @acl, one thing worth doing is to set the SystemOptions -> "CompileOptions" as

SetSystemOptions[ "CompileOptions" -> "CompileReportExternal" -> True]

in which case you will get warnings for calling external functions etc.

A good tool to get a "high-level" but precise view on the generated code is the CompilePrint function in the CompiledFunctionTools` package. It allows you to print the pseudocode version of the byte-code instructions generated by Compile. Things to watch for in the printout of CompilePrint function:

  • Calls to CopyTensor
  • Calls to MainEvaluate (callbacks to Mathematica, meaning that something could not be compiled down to C)

One not very widely known technique of writing even large Compile-d functions and combining them from pieces so that there is no performance penalty, is based on inlining. I consider this answer very illustrative in this respect - I actually posted it to showcase the technique. You can also see this answer and a discussion in the comments below, for another example of how this technique may be applied.

In summary - if you want your code to be as fast as possible, think about "critical" places and write those in "low-level" style (loops, assignments, etc) - the more it will resemble C the more chances you have for a speed-up (for an example of a function written in such a style and being consequently very fast, see the seqposC function from this answer). You will have to go against Mathematica ideology and use a lot of in-place modifications. Then your code can be just as fast as hand-written one. Usually, there are just a few places in the program where this matters (inner loops, etc) - in the rest of it you can use higher-level functions as well.

A lot depends on how you write your code in Mathematica. In my experience, the rule of thumb is that the generated code will be efficient if the code inside Compile more or less resembles the code I would write in plain C (and it is clear why). Idiomatic (high-level) Mathematica code tends to be immutable. At the same time, Compile can handle a number of higher-level functions, such as Transpose, Partition, Map, MapThread, etc. Most of these functions return expressions, and even though these expressions are probably passed to the calling function, they must be created. For example, a call to ReplacePart which replaces a single part in a large array will necessarily lead to copying of that array. Thus, immutability generally implies creating copies.

So, if you write your code in this style and hand it to Compile, you have to keep in mind that lots of small (or large) memory allocations on the heap, and copying of lists (tensors) will be happening. Since this is not apparent for someone who is used to high-level Mathematica programming, the slowdown this may incur may be surprising. See this and this answers for examples of problems coming from many small memory allocations and copying, as well as a speed-up one can get from switching from copying to in-place modifications.

As noted by @acl, one thing worth doing is to set the SystemOptions -> "CompileOptions" as

SetSystemOptions[ "CompileOptions" -> "CompileReportExternal" -> True]

in which case you will get warnings for calling external functions etc.

A good tool to get a "high-level" but precise view on the generated code is the CompilePrint function in the CompiledFunctionTools` package. It allows you to print the pseudocode version of the byte-code instructions generated by Compile. Things to watch for in the printout of CompilePrint function:

  • Calls to CopyTensor
  • Calls to MainEvaluate (callbacks to Mathematica, meaning that something could not be compiled down to C)

One not very widely known technique of writing even large Compile-d functions and combining them from pieces so that there is no performance penalty, is based on inlining. I consider this answer very illustrative in this respect - I actually posted it to showcase the technique. You can also see this answer and a discussion in the comments below, for another example of how this technique may be applied.

In summary - if you want your code to be as fast as possible, think about "critical" places and write those in "low-level" style (loops, assignments, etc) - the more it will resemble C the more chances you have for a speed-up (for an example of a function written in such a style and being consequently very fast, see the seqposC function from this answer). You will have to go against Mathematica ideology and use a lot of in-place modifications. Then your code can be just as fast as hand-written one. Usually, there are just a few places in the program where this matters (inner loops, etc) - in the rest of it you can use higher-level functions as well.

Restructured a bit
Source Link
Leonid Shifrin
  • 114.9k
  • 16
  • 333
  • 424

A lot depends on how you write your code in Mathematica. In my experience, the rule of thumb is that the generated code will be efficient if the code inside Compile more or less resembles the code I would write in plain C (and it is clear why). Idiomatic (high-level) Mathematica code tends to be immutable. At the same time, Compile can handle a number of higher-level functions, such as Transpose, Partition, Map, MapThread, etc. 

So, if you write your code in this style and hand it to Compile, you have to keep in mind that lots of small (or large) memory allocations on the heap, and copying of lists (tensors) will be happening.

Since Since this is not apparent for someone who is used to high-level Mathematica programming, the slowdown this may incur may be surprising. See (one examplethis and this answers for examples of problems coming from many small memory allocations and copying, as well as a speed-up one can get from switching from copying to in-place modifications, can be found in this answer. Another example of the speed-up gains from replacing copying with in-place modifications can be found in my answer to this question)

As noted by @acl, one thing worth doing is to set the SystemOptions -> "CompileOptions" as

SetSystemOptions[ "CompileOptions" -> "CompileReportExternal" -> True]

in which case you will get warnings for calling external functions etc.

A good tool to get a "high-level" but precise view on the generated code is the CompilePrint function in the CompiledFunctionTools` package. It allows you to print the pseudocode version of the byte-code instructions generated by Compile. Things to watch for in the printout of CompilePrint function:

  • Calls to CopyTensor
  • Calls to MainEvaluate (callbacks to Mathematica, meaning that something could not be compiled down to C)

One not very widely known technique of writing even large Compile-d functions and combining them from pieces so that there is no performance penalty, is based on inlining. I consider this answer very illustrative in this respect - I actually posted it to showcase the technique. You can also see this answer and a discussion in the comments below, for another example of how this technique may be applied.

So, inIn summary - if you want your code to be as fast as possible, think about "critical" places and write those in "low-level" style (loops, assignments, etc) - the more it will resemble C the more chances you have for a speed-up (for an example of a function written in such a style and being consequently very fast, see the seqposC function from this answer). You will have to go against Mathematica ideology and use a lot of in-place modifications. Then your code can be just as fast as hand-written one. Usually, there are just a few places in the program where this matters (inner loops, etc) - in the rest of it you can use higher-level functions as well.

In my experience, the rule of thumb is that the generated code will be efficient if the code inside Compile more or less resembles the code I would write in plain C (and it is clear why). Idiomatic (high-level) Mathematica code tends to be immutable. At the same time, Compile can handle a number of higher-level functions, such as Transpose, Partition, Map, MapThread, etc. So, if you write your code in this style and hand it to Compile, you have to keep in mind that lots of small (or large) memory allocations on the heap, and copying of lists (tensors) will be happening.

Since this is not apparent for someone who is used to high-level Mathematica programming, the slowdown this may incur may be surprising (one example of problems coming from many small memory allocations and copying, as well as a speed-up one can get from switching from copying to in-place modifications, can be found in this answer. Another example of the speed-up gains from replacing copying with in-place modifications can be found in my answer to this question)

As noted by @acl, one thing worth doing is to set the SystemOptions -> "CompileOptions" as

SetSystemOptions[ "CompileOptions" -> "CompileReportExternal" -> True]

in which case you will get warnings for calling external functions etc.

A good tool to get a "high-level" but precise view on the generated code is the CompilePrint function in the CompiledFunctionTools` package. It allows you to print the pseudocode version of the byte-code instructions generated by Compile. Things to watch for in the printout of CompilePrint function:

  • Calls to CopyTensor
  • Calls to MainEvaluate (callbacks to Mathematica, meaning that something could not be compiled down to C)

One not very widely known technique of writing even large Compile-d functions and combining them from pieces so that there is no performance penalty, is based on inlining. I consider this answer very illustrative in this respect - I actually posted it to showcase the technique. You can also see this answer and a discussion in the comments below, for another example of how this technique may be applied.

So, in summary - if you want your code to be as fast as possible, think about "critical" places and write those in "low-level" style (loops, assignments, etc) - the more it will resemble C the more chances you have for a speed-up (for an example of a function written in such a style and being consequently very fast, see the seqposC function from this answer). You will have to go against Mathematica ideology and use a lot of in-place modifications. Then your code can be just as fast as hand-written one. Usually, there are just a few places in the program where this matters (inner loops, etc) - in the rest of it you can use higher-level functions as well.

A lot depends on how you write your code in Mathematica. In my experience, the rule of thumb is that the generated code will be efficient if the code inside Compile more or less resembles the code I would write in plain C (and it is clear why). Idiomatic (high-level) Mathematica code tends to be immutable. At the same time, Compile can handle a number of higher-level functions, such as Transpose, Partition, Map, MapThread, etc. 

So, if you write your code in this style and hand it to Compile, you have to keep in mind that lots of small (or large) memory allocations on the heap, and copying of lists (tensors) will be happening. Since this is not apparent for someone who is used to high-level Mathematica programming, the slowdown this may incur may be surprising. See this and this answers for examples of problems coming from many small memory allocations and copying, as well as a speed-up one can get from switching from copying to in-place modifications.

As noted by @acl, one thing worth doing is to set the SystemOptions -> "CompileOptions" as

SetSystemOptions[ "CompileOptions" -> "CompileReportExternal" -> True]

in which case you will get warnings for calling external functions etc.

A good tool to get a "high-level" but precise view on the generated code is the CompilePrint function in the CompiledFunctionTools` package. It allows you to print the pseudocode version of the byte-code instructions generated by Compile. Things to watch for in the printout of CompilePrint function:

  • Calls to CopyTensor
  • Calls to MainEvaluate (callbacks to Mathematica, meaning that something could not be compiled down to C)

One not very widely known technique of writing even large Compile-d functions and combining them from pieces so that there is no performance penalty, is based on inlining. I consider this answer very illustrative in this respect - I actually posted it to showcase the technique. You can also see this answer and a discussion in the comments below, for another example of how this technique may be applied.

In summary - if you want your code to be as fast as possible, think about "critical" places and write those in "low-level" style (loops, assignments, etc) - the more it will resemble C the more chances you have for a speed-up (for an example of a function written in such a style and being consequently very fast, see the seqposC function from this answer). You will have to go against Mathematica ideology and use a lot of in-place modifications. Then your code can be just as fast as hand-written one. Usually, there are just a few places in the program where this matters (inner loops, etc) - in the rest of it you can use higher-level functions as well.

Added a note of @acl and a few more links
Source Link
Leonid Shifrin
  • 114.9k
  • 16
  • 333
  • 424
Loading
Added some links
Source Link
Leonid Shifrin
  • 114.9k
  • 16
  • 333
  • 424
Loading
Source Link
Leonid Shifrin
  • 114.9k
  • 16
  • 333
  • 424
Loading