rintelintel-mkl

Integrating a C Subfunction for Optimizing R Code


I have an existing R script that performs various operations, and I'm looking to create a C sub function to optimize a specific part of it. My goal is to integrate this C sub function within R Desktop for improved performance and efficiency.

For example, let's assume that I want to sum the elements obtained by multiplying the vector x and y. In R, I can achieve this with the following code:

R code

x <- c(1, 2, 3)
y <- c(4, 5, 6)
z <- sum(x * y)  

The same operation using oneMKL can be performed like this:

#include <stdio.h>
#include <mkl.h>
int main() {
    double x[] = {1.0, 2.0, 3.0};
    double y[] = {4.0, 5.0, 6.0};
    double z;
    // Perform vector multiplication and summation using Intel MKL
    z = cblas_ddot(3, x, 1, y, 1);
    printf("Result: %lf\n", z);
    return 0;
}

After compiling the .c function using CMD, I get:

C:\Program Files (x86)\Intel\oneAPI>cd C:/Users/Administrator/Desktop
C:\Users\Administrator\Desktop>icx -o example example.c /Qmkl /MD
Intel(R) oneAPI DPC++/C++ Compiler for applications running on Intel(R) 64, Version 2023.1.0 Build 20230320
Copyright (C) 1985-2023 Intel Corporation. All rights reserved.

C:\Users\Administrator\Desktop>example.exe
Result: 32.000000 

What I want to do is replace the 4th line of the Rscript code with a .c function. I'm facing two problems:

1. Convert the C Function for General Inputs:

I don't know if I have defined the function correctly.

#include <stdio.h>
#include <mkl.h>

void multiplyAndSum(double *x, double *y, int length, double *result) {
    *result = cblas_ddot(length, x, 1, y, 1);
}

2. Calling the C Function in R:

I don't know how to call the .c function in step 1 within R. Is there a way to compile the function and run it explicitly within R Desktop, without using the command prompt (cmd)

Please, I understand that my question may be quite basic, but my knowledge is limited. I would greatly appreciate a step-by-step answer, ideally. I have installed Intel oneAPI Base Toolkit on windows platform.

Best regards, Anastasia

PS: My environment variables are displayed in the image below. Perhaps this information could be helpful for you to assist me. enter image description here


Solution

  • Here is a working example with the C function in the question.

    C code, file so_77177870.c

    // file: so_77177870.c
    #include <R.h>
    #include <mkl.h>
    
    void multiplyAndSum(double *x, double *y, int *length, double *result) {
      *result = cblas_ddot(*length, x, 1, y, 1);
    }
    

    Compile the code above with

    R CMD SHLIB so_77177870.c
    

    This will produce a shared library, extension .dll in Windows. Then, in R, load the library and write a wrapper function, dotprod. The C code's return value is its last argument.

    See Writing R Extensions, section 5.2.

    dynLoad <- function(dynlib){
      dynlib <- paste0(dynlib, .Platform$dynlib.ext)
      dyn.load(dynlib)
    }
    dynUnload <- function(dynlib){
      dynlib <- paste0(dynlib, .Platform$dynlib.ext)
      dyn.unload(dynlib)
    }
    
    dotprod <- function(x, y) {
      .C("multiplyAndSum", 
         as.double(x), as.double(y), 
         as.integer(length(x)),
         result = double(1)
      )$result
    }
    
    # load the shared library, in this case so_77177870.dll
    dll <- "so_77177870"
    dynLoad(dll)
    
    x <- c(1, 2, 3)
    y <- c(4, 5, 6)
    
    sum(x * y)  
    #> [1] 32
    dotprod(x, y)
    #> [1] 32
    
    # unload the shared library when done
    dynUnload(dll)
    

    Created on 2023-09-26 with reprex v2.0.2