How do I use Intel® MKL with Java*?

Published: 03/27/2013, Last Updated: 03/27/2013

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.

Attachment Size
dgemm-java-example.zip 2.2 KB
intel-mkl-java-examples.zip 1.2 MB

Product and Performance Information

1

Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for Intel microprocessors. Please refer to the applicable product User and Reference Guides for more information regarding the specific instruction sets covered by this notice.

Notice revision #20110804