9

I wrote a Gibbs sampler in R and decided to port it to C to see whether it would be faster. A lot of pages I have looked at claim that C will be up to 50 times faster, but every time I have used it, it's only about five or six times faster than R. My question is: is this to be expected, or are there tricks which I am not using which would make my C code significantly faster than this (like how using vectorization speeds up code in R)? I basically took the code and rewrote it in C, replacing matrix operations with for loops and making all the variables pointers.

Also, does anyone know of good resources for C from the point of view of an R programmer? There's an excellent book called The Art of R Programming by Matloff, but it seems to be written from the perspective of someone who already knows C.

Also, the screen tends to freeze when my C code is running in the standard R GUI for Windows. It doesn't crash; it unfreezes once the code has finished running, but it stops me from doing anything else in the GUI. Does anybody know how I could avoid this? I am calling the function using .C()

Sid
  • 1,255
  • 2
  • 22
  • 45
Flounderer
  • 640
  • 5
  • 17
  • 5
    Unless you **really** know and *understand* C, there will be very little performance enhancements to be had. As to why the freezing occurs, it's all about threading. My guess is that R will auto-execute in the background, wheras C most definitely will not. – Richard J. Ross III Nov 15 '12 at 01:19
  • 1
    It depends. As long as you stick to the primitives, they should be about the same. When you code three nested {i,j,k} loops to implement a matrix multiplication, C will be faster. (not if you would use the matrix/vector primitives) – wildplasser Nov 15 '12 at 01:19
  • 5
    To add to what @RichardJ.RossIII said, always remember that you're never just comparing languages, you're also comparing _your ability to program in each language_ at the same time. It can be hard to disentangle to two. – joran Nov 15 '12 at 01:37
  • What @RichardJ.RossIII said. C allows you to squeeze a lot of performance out of the hardware when you need it, but that doesn't all come for free. You have to know what you're doing and understand *why* your code is running slower than it could be with some low level optimization. – Ed S. Nov 15 '12 at 01:38
  • BTW: My guess is that the .C() function links and calls a shared library function. And for sanity reasons, it will freeze the other threads, giving the .C() thingy exclusive access to all "global" data structures. There is another (fork/exec + wait) calling convention in R, but it had a different name. exec, IIRC. – wildplasser Nov 15 '12 at 01:39
  • 2
    For your second paragraph, see http://stackoverflow.com/questions/4106174/where-can-i-learn-to-how-to-write-c-code-to-speed-up-slow-r-functions – GSee Nov 15 '12 at 01:46
  • 1
    Here's an [example](http://stackoverflow.com/a/11275230/636656) of Rcpp producing huge speed-ups relative to even optimized R code, but in the end they turned out to be due to the primitives as @wildplasser noted. In this case, the speed advantage was because Rcpp was modifying the original object rather than modifying a copied object. *When C(++) code performed the same fundamental operations as the R code, it was similarly fast, but C allowed more control over which operations were performed.* – Ari B. Friedman Nov 15 '12 at 02:08
  • Do a loop benchmark, with SIMD in C, and SIMD in R--but you have to access particular libraries to access SIMD https://stackoverflow.com/questions/37213060/does-r-leverage-simd-when-doing-vectorized-calculations SIMD does indeed offer about 4-6x speed-up, assuming you have done a perfect implementation otherwise. If you can't submerge your R loops into a SIMD compiled library call, it's likely it will never equal C. But if you can, R is a lazy functional coding system -- there isn't much overhead even though it is interpreted -- so you should be identical to C under the interpretation layer – Chris Sep 13 '19 at 21:35

4 Answers4

15

Many of the existing posts have explicit examples you can run, for example Darren Wilkinson has several posts on his blog analyzing this in different languages, and later even on different hardware (eg comparing his high-end laptop to his netbook and to a Raspberry Pi). Some of his posts are

and there are many more on his site -- these often compare C, Java, Python and more.

Now, I also turned this into a version using Rcpp -- see this blog post. We also used the same example in a comparison between Julia, Python and R/C++ at useR this summer so you should find plenty other examples and references. MCMC is widely used, and "easy pickings" for speedups.

Given these examples, allow me to add that I disagree with the two earlier comments your question received. The speed will not be the same, it is easy to do better in an example such as this, and your C/C++ skills will mostly determines how much better.

Finally, an often overlooked aspect is that the speed of the RNG matters a lot. Running down loops and adding things up is cheap -- doing "good" draws is not, and a lot of inter-system variation comes from that too.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • Thanks for linking to those posts with a real-world example! The examples I have seen in the past have mostly been artificial ones, eg. adding up the first million positive integers. – Flounderer Nov 15 '12 at 01:54
  • Re: your last paragraph, I couldn't really see a good way to generate uniform random numbers in C, so I just generated as many random numbers as I needed in R before starting, and then passed a pointer to that array as one of the arguments of the C function. I am not sure whether this is better or worse than generating them in C? – Flounderer Nov 15 '12 at 02:08
  • Please see [Writing R Extension, Section 6.3](http://cran.r-project.org/doc/manuals/R-exts.html#Random-numbers) or the documentation of any good numerical library. Rcpp gives you this for free, even *vectorised* ie one call and a vector of N rngs drawn. At compiled speed. – Dirk Eddelbuettel Nov 15 '12 at 02:19
  • Do you mean that C takes a lot of time to peek and poke? Should this be avoided? – Flounderer Nov 15 '12 at 02:54
  • Function calls have overheads. Fewer total calls, faster execution. – Dirk Eddelbuettel Nov 15 '12 at 02:55
  • The function call overhead in C++ is pretty small (on the order of nanoseconds), it does add up if you're doing millions of calls. – hadley Nov 15 '12 at 04:02
2

About the GUI freezing, you might want to call R_CheckUserInterrupt and perhaps R_ProcessEvents every now and then.

Romain Francois
  • 17,432
  • 3
  • 51
  • 77
2

I would say C, done properly, is much faster than R.

Some easy gains you could try: Set the compiler to optimize for more speed. Compiling with the -march flag. Also if you're using VS, make sure you're compiling with release options, not debug.

TeeraMusic
  • 452
  • 1
  • 5
  • 10
1

Your observed performance difference will depend on a number of things: the type of operations that you are doing, how you write the C code, what type of compiler-level optimizations you use, your target CPU architecture, etc etc.

You can write basic, sloppy C and get something that works and runs with decent efficiency. You can also fine-tune your code for the unique characteristics of your target CPU - perhaps invoking specialized assembly instructions - and squeeze every last drop of performance that you can out of the code. You could even write code that runs significantly slower than the R version. C gives you a lot of flexibility. The limiting factor here is how much time that you want to put into writing and optimizing the C code.

The reverse is also true (duplicate the previous paragraph here, but swap "C" and "R").

I'm not trying to sound facetious, but there's really not a straightforward answer to your question. The only way to tell how much faster your C version would be is to write the code both ways and benchmark them.

bta
  • 43,959
  • 6
  • 69
  • 99