How do I use Intel® MKL with Java*?

Intel® MKL C functions can be accessed from Java through Java Native Interface (JNI). The following example shows how to call cblas_dgemm from java on Linux. For more examples see the attachment located at the bottom of this article.

CAUTION: This article demonstrates usage model for arrays of size less than 2 billion and is aimed at proficient Java users capable of creating native arrays, verify input and do Java optimizations.

To call cblas_dgemm from java application following steps should be performed:

Step 1. Create a java file with cblas dgemm description (CBLAS.java):

/*CBLAS.java*/
public final class CBLAS {
 private CBLAS() {}
 static {
 System.loadLibrary("mkl_java_stubs"); /*load library (which will contain wrapper for cblas function. See step 3)*/
 }
 public final static class ORDER {
   private ORDER() {}
  /** row-major arrays */
   public final static int RowMajor=101;
   /** column-major arrays */
   public final static int ColMajor=102;
 }
public final static class TRANSPOSE {
  private TRANSPOSE() {}
    /** trans='N' */
   public final static int NoTrans =111;
   /** trans='T' */
   public final static int Trans=112;
   /** trans='C' */
   public final static int ConjTrans=113;
 }
public static native void dgemm(int Order, int TransA, int TransB, int M, int N, int K, double alpha, double[] A, int lda, double[] B, int ldb, double beta, double[] C, int ldc); /*inform java virtual machine that function is defined externally*/
}

 

Compile the CBLAS.java using the java compiler as below:

javac CBLAS.java

Step 2. Generate headers files from the java class file which was created in the previous step.

These headers should be used in C file in the next step.

javah CBLAS

Three header files will be generated: CBLAS.h, CBLAS_ORDER.h CBLAS_TRANSPOSE.h

Step 3. Use definition of Java_CBLAS_dgemm in header CBLAS.h that was generated in step 2 to write C file CBLAS.c.

Here’s generated header CBLAS.h – do not edit it!

 

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class CBLAS */
#ifndef _Included_CBLAS
#define _Included_CBLAS
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     CBLAS
 * Method:    dgemm
 * Signature: (IIIIIID[DI[DID[DI)V
 */
 JNIEXPORT void JNICALL Java_CBLAS_dgemm
   (JNIEnv *, jclass, jint, jint, jint, jint, jint, jint, jdouble, jdoubleArray, jint, jdoubleArray, jint, jdouble, jdoubleArray, jint);
 
#ifdef __cplusplus
}
#endif
#endif

 

Definition of function Java_CBLAS_dgemm should be used in wrapper for MKL. Create C file CBLAS.c:

/*CBLAS.c*/
#include <jni.h>
#include <assert.h>
#include "mkl_cblas.h"

JNIEXPORT void Java_CBLAS_dgemm (JNIEnv *env, jclass klass,    jint Order, jint TransA, jint TransB, jint M, jint N, jint K,   jdouble alpha, jdoubleArray  A, int lda, jdoubleArray B, jint ldb,  jdouble beta,  jdoubleArray C, jint ldc){
    jdouble *aElems, *bElems, *cElems;
 
    aElems = (*env)-> GetDoubleArrayElements (env,A,NULL);
    bElems = (*env)-> GetDoubleArrayElements (env,B,NULL);
    cElems = (*env)-> GetDoubleArrayElements (env,C,NULL);
    assert(aElems && bElems && cElems);
 
cblas_dgemm ((CBLAS_ORDER)Order,(CBLAS_TRANSPOSE)TransA,(CBLAS_TRANSPOSE)TransB,
        (int)M,(int)N,(int)K,alpha,aElems,(int)lda,bElems,(int)ldb,beta,cElems,(int)ldc);
 
    (*env)-> ReleaseDoubleArrayElements (env,C,cElems,0);
    (*env)-> ReleaseDoubleArrayElements (env,B,bElems,JNI_ABORT);
    (*env)-> ReleaseDoubleArrayElements (env,A,aElems,JNI_ABORT);
}

 

This file should be compiled to create native library libmkl_java_stubs.so (Loading of this library in java is described in step 1)

icc -shared -fPIC -o libmkl_java_stubs.so CBLAS.c -I. -I$MKLROOT/include -Wl,--start-group $MKLROOT/lib/intel64/libmkl_intel_lp64.a $MKLROOT/lib/intel64/libmkl_intel_thread.a $MKLROOT/lib/intel64/libmkl_core.a -Wl,--end-group -openmp -lpthread -lm -ldl

Step 4. Create main dgemm.java

/*dgemm.java*/
public final class dgemm {
    /** Incarnation prohibited. */
    private dgemm() {}
    /** No command-line options. */
    public static void main(String[] args) {

        //
        // Prepare the matrices and other parameters
        //
        int Order = CBLAS.ORDER.RowMajor;
        int TransA = CBLAS.TRANSPOSE.NoTrans;
        int TransB = CBLAS.TRANSPOSE.NoTrans;
        int M=2, N=4, K=3;
        int lda=K, ldb=N, ldc=N;
        double[] A = new double[] {1,2,3, 4,5,6};
        double[] B = new double[] {0,1,0,1, 1,0,0,1, 1,0,1,0};
        double[] C = new double[] {5,1,3,3, 11,4,6,9};
        double alpha=1, beta=-1;
        //
        // Print the parameters
        //
        System.out.println("alpha=" + string(alpha));
        System.out.println("beta=" + string(beta));
        printMatrix("Matrix A",A,M,K);
        printMatrix("Matrix B",B,K,N);
        printMatrix("Initial C",C,M,N);
        //
        // Compute the function
        //
        CBLAS.dgemm(Order,TransA,TransB,M,N,K,alpha,A,lda,B,ldb,beta,C,ldc);
        //
        // Print the result
        //
        printMatrix("Resulting C",C,M,N);
        //
        // Check the result:
        //
        boolean error=false;
        for (int m=0; m<M; m++)
            for (int n=0; n<N; n++)
                if (C[m*N+n] != 0)
                    error=true;
        if (error)
            System.out.println("ERROR: resulting C must be zero!");
        //
        // Print summary and exit
        //
        if (error) {
            System.out.println("TEST FAILED");
            System.exit(1);
        }
        System.out.println("TEST PASSED");
    }
 
    /** Print the matrix X assuming raw-major order of elements. */
    private static void printMatrix(String prompt, double[] X, int I, int J) {
        System.out.println(prompt);
        for (int i=0; i<I; i++) {
            for (int j=0; j<J; j++)
                System.out.print("\t" + string(X[i*J+j]));
            System.out.println();
        }
    }

    /** Shorter string for real number. */
    private static String string(double re) {
        String s="";
        if (re == (long)re)
            s += (long)re;
        else
            s += re;
        return s;
    }
}
 

Compile the application                                                                                                                                                                                     

javac dgemm.java

Step 5. Execute the application.

java.library.path should point to directory where library libmkl_java_stubs.so is placed. This example assumes that stubs shared library is located next to the created Java executable.

java -Djava.library.path=. dgemm

 

The output should be:

alpha=1
beta=-1
Matrix A
        1       2       3
        4       5       6
Matrix B
        0       1       0       1
        1       0       0       1
        1       0       1       0
Initial C
        5       1       3       3
        11      4       6       9
Resulting C
        0       0       0       0
        0       0       0       0
TEST PASSED

The source code for the above dgemm mkl example is attached below.

For more complete information about compiler optimizations, see our Optimization Notice.