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.

3 comments

Top
yuvraj v.'s picture

Does WindRiver provide inbuilt java library for MQTT communication?

The program listing in numbered item 3. should have ended before line 21. The subsequent instructions and source listings need to be separated properly.

 

Add a Comment

Have a technical question? Visit our forums. Have site or software product issues? Contact support.