Quantcast
Channel: Intel Developer Zone Articles
Viewing all articles
Browse latest Browse all 3384

Using Intel® MKL in math intensive Java applications on Intel® Xeon Phi

$
0
0

This article is an extension of the existing How do I use Intel® MKL with Java*? article from Intel® MKL Knowledge Base, and we will be reusing the code samples mentioned there.

Here we will explore how we can make use of Intel® Xeon Phi coprocessor available in the system to speed up the mathematical computations by using Automatic Offload enabled functions in Intel® MKL.  The Compiler Assisted Offload (CAO) model is not supported to offload computations using JNI and MKL.

Follow the steps 1,2 and 3 as explained in How do I use Intel® MKL with Java*?. 

This article explains how to build and run on a Linux platform. Before, proceeding, you should have the Intel compilers, Intel MKL and Java paths to be set.

For easy reference, these are detailed here too.

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 DgemmComputation.java

/*DgemmComputation.java*/
import java.util.Random;
import java.util.Scanner;

public final class DgemmComputation {
    /** Incarnation prohibited. */
    private DgemmComputation() {
 
    }

    /** No command-line options. */
    public static void main(String[] args) {

        double [] A; double [] B; double [] C;
        int M, N, K, lda, ldb, ldc;

        int[] matrixSize = new int[] {1024, 2048, 4096, 8192, 12288, 16384, 20480,24576};
 
        int Order = CBLAS.ORDER.RowMajor;
        int TransA = CBLAS.TRANSPOSE.NoTrans;
        int TransB = CBLAS.TRANSPOSE.NoTrans;

        for (int i = 0; i < matrixSize.length; i++ ) {
          System.out.println("Matrix size is: " + matrixSize[i]);
          M=matrixSize[i]; N=matrixSize[i]; K=matrixSize[i];

          lda=K; ldb=N; ldc=N;

          A = new double[matrixSize[i] * matrixSize[i]];
          B = new double[matrixSize[i] * matrixSize[i]];
          C = new double[matrixSize[i] * matrixSize[i]];
       
          double alpha=1, beta=-1;

          DgemmComputation compute_dgemm  = new DgemmComputation();
 
          //Initializing A with random values
	  A = compute_dgemm.initMatrix(matrixSize[i], A);

 	  //Initializing B with random values
	  B = compute_dgemm.initMatrix(matrixSize[i], B);

	  // Compute the function
          final long startTime = System.currentTimeMillis();

          CBLAS.dgemm(Order,TransA,TransB,M,N,K,alpha,A,lda,B,ldb,beta,C,ldc);
       
	  final long endTime = System.currentTimeMillis();

 	  System.out.println("Matrix Size and Total Execution Time:"+ matrixSize[i]+ "," + (endTime - startTime));
          System.out.println("Computation of dgemm over...");
 	}
    }

    // Matrix Initialization function
    private double[] initMatrix(int size, double [] mat) {
	int i;
 	double value;
 	mat = new double[size*size];
	Random rand = new Random();

	for (i=0; i<size*size; i++) {
	  value = rand.nextDouble()*i;
	  mat[i] = Math.round(value*100.0)/100.0;
 	}
 	return mat;
    }  

    /** Print the matrix X assuming raw-major order of elements. */
    private 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("i: " + i + ", j: " + j + " and the value is");
                System.out.print("\t" + X[i*J+j]);
                System.out.println();
	     } 
        }
    }
}

Compile the application                                                                                                                                                                                     

javac DgemmComputation.java

Step 5. Execute the application.

Before executing this application, we have to set a couple of environment variables.

To enable Intel MKL to automatically offload computation, use the following command

export MKL_MIC_ENABLE=1

You can check how the dgemm computation is split across the host CPU and the Intel Xeon Phi coprocessor by using

export OFFLOAD_REPORT=2

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=. DgemmComputation

Here is the screenshot of the output from the result run on a Haswell E5-2695 V3 server with 2 Intel Xeon Phi coprocessors.   You can see that MKL has divided the work among the host cpu, and 2 Xeon Phi coprocessors dynamically by itself and this work division is done depends on the input matrix sizes.  Users can also set this by using MKL_MIC_WORKDIVISION env variables. For more details, please refer How to control the work division article.  

Java MKL Xeon Phi

 

 


Viewing all articles
Browse latest Browse all 3384

Latest Images

Trending Articles



Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>