From dda96891f1542e76b371a6b68ec7bbb876432933 Mon Sep 17 00:00:00 2001 From: Dmitriy Shabanov Date: Mon, 23 Oct 2017 10:30:42 +0300 Subject: [PATCH 1/2] vector feature prototype --- src/main/java/com/aparapi/Config.java | 2 + src/main/java/com/aparapi/Kernel.java | 42 ++++++++++- .../aparapi/internal/model/Entrypoint.java | 10 ++- .../aparapi/internal/writer/KernelWriter.java | 55 ++++++++++++--- .../com/aparapi/opencl/vector/Float2.java | 54 +++++++++++++++ .../java/com/aparapi/runtime/VectorTest.java | 69 +++++++++++++++++++ 6 files changed, 219 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/aparapi/opencl/vector/Float2.java create mode 100644 src/test/java/com/aparapi/runtime/VectorTest.java diff --git a/src/main/java/com/aparapi/Config.java b/src/main/java/com/aparapi/Config.java index 0986dcfd..75f7b530 100644 --- a/src/main/java/com/aparapi/Config.java +++ b/src/main/java/com/aparapi/Config.java @@ -159,6 +159,8 @@ public class Config extends ConfigJNI{ public static final boolean enableARRAY = !Boolean.getBoolean(propPkgName + ".disable.ARRAY"); + public static final boolean enableVECTOR = !Boolean.getBoolean(propPkgName + ".disable.VECTOR"); + public static final boolean enableNEW = Boolean.getBoolean(propPkgName + ".enable.NEW"); public static final boolean enableATHROW = Boolean.getBoolean(propPkgName + ".enable.ATHROW"); diff --git a/src/main/java/com/aparapi/Kernel.java b/src/main/java/com/aparapi/Kernel.java index f697ff4a..ab5fc2db 100644 --- a/src/main/java/com/aparapi/Kernel.java +++ b/src/main/java/com/aparapi/Kernel.java @@ -329,6 +329,14 @@ public abstract class Kernel implements Cloneable { boolean atomic64() default false; } + /** + * This annotation is for internal use only + */ + @Retention(RetentionPolicy.RUNTIME) + public @interface OpenCLMappingPattern { + String mapTo() default ""; + } + public abstract class Entry { public abstract void run(); @@ -2612,7 +2620,7 @@ private static String toClassShortNameIfAny(final Class retClass) { final String mapping = typeToLetterMap.get(strRetClass); // System.out.println("strRetClass = <" + strRetClass + ">, mapping = " + mapping); if (mapping == null) - return "[" + retClass.getName() + ";"; + return "L" + retClass.getName() + ";"; return mapping; } @@ -2688,6 +2696,38 @@ public static boolean isOpenCLDelegateMethod(MethodReferenceEntry methodReferenc return (isMapped); } + public static String getMethodMappedPattern(MethodReferenceEntry _methodReferenceEntry) { + final String name = _methodReferenceEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace("/","."); + + final Class currentClass; + try { + currentClass = Class.forName(name); + } catch (ClassNotFoundException e) { + return null; + } + + String methodSignature = toSignature(_methodReferenceEntry).replace("/", "."); + + //System.out.println("? - "+methodSignature); + + for (final Method method : currentClass.getMethods()) { + if (method.isAnnotationPresent(OpenCLMappingPattern.class)) { + + //System.out.println(toSignature(method)); + + if (methodSignature.equals(toSignature(method))) { + final OpenCLMappingPattern annotation = method.getAnnotation(OpenCLMappingPattern.class); + final String mapTo = annotation.mapTo(); + if (!mapTo.equals("")) { + return mapTo; + } + } + } + } + + return null; + } + public static boolean usesAtomic32(MethodReferenceEntry methodReferenceEntry) { if (CacheEnabler.areCachesEnabled()) return getProperty(atomic32Cache, methodReferenceEntry, false); diff --git a/src/main/java/com/aparapi/internal/model/Entrypoint.java b/src/main/java/com/aparapi/internal/model/Entrypoint.java index 3a291b24..0e11e65e 100644 --- a/src/main/java/com/aparapi/internal/model/Entrypoint.java +++ b/src/main/java/com/aparapi/internal/model/Entrypoint.java @@ -477,7 +477,7 @@ public Entrypoint(ClassModel _classModel, MethodModel _methodModel, Object _k) t for (final MethodCall methodCall : methodModel.getMethodCalls()) { ClassModelMethod m = resolveCalledMethod(methodCall, classModel); - if ((m != null) && !methodMap.keySet().contains(m) && !noCL(m)) { + if ((m != null) && !methodMap.keySet().contains(m) && !noCL(m) && !isInternal(m)) { final MethodModel target = new MethodModel(m, this); methodMap.put(m, target); methodModel.getCalledMethods().add(target); @@ -805,10 +805,14 @@ else if (instruction instanceof I_INVOKEVIRTUAL) { } private boolean noCL(ClassModelMethod m) { - boolean found = m.getClassModel().getNoCLMethods().contains(m.getName()); - return found; + return m.getClassModel().getNoCLMethods().contains(m.getName()); } + private boolean isInternal(ClassModelMethod m) { + //TODO: use mapped cache + return m.getOwnerClassModel().getClassWeAreModelling().getName().startsWith("com.aparapi.opencl.vector"); + } + private FieldEntry getSimpleGetterField(MethodModel method) { return method.getAccessorVariableFieldEntry(); } diff --git a/src/main/java/com/aparapi/internal/writer/KernelWriter.java b/src/main/java/com/aparapi/internal/writer/KernelWriter.java index 8099c591..70fa5d4b 100644 --- a/src/main/java/com/aparapi/internal/writer/KernelWriter.java +++ b/src/main/java/com/aparapi/internal/writer/KernelWriter.java @@ -64,6 +64,7 @@ to national security controls as identified on the Commerce Control List (curren import com.aparapi.internal.model.ClassModel.*; import com.aparapi.internal.model.ClassModel.ConstantPool.*; +import com.aparapi.internal.tool.InstructionHelper.StringWriter; import java.util.*; public abstract class KernelWriter extends BlockWriter{ @@ -160,7 +161,13 @@ public abstract class KernelWriter extends BlockWriter{ javaToCLIdentifierMap.put("globalBarrier()V", "barrier(CLK_GLOBAL_MEM_FENCE)"); } - /** + private final static Map mapping = new HashMap<>(); + static { + mapping.put("Lcom/aparapi/opencl/vector/Float2;", "float2"); + } + + + /** * These three convert functions are here to perform * any type conversion that may be required between * Java and OpenCL. @@ -170,6 +177,11 @@ public abstract class KernelWriter extends BlockWriter{ * @return Suitably converted string, "char*", etc */ @Override public String convertType(String _typeDesc, boolean useClassModel, boolean isLocal) { + String mapTo = mapping.get(_typeDesc); + if (mapTo != null) { + return mapTo + " "; + } + if (_typeDesc.equals("Z") || _typeDesc.equals("boolean")) { return (cvtBooleanToChar); } else if (_typeDesc.equals("[Z") || _typeDesc.equals("boolean[]")) { @@ -226,6 +238,26 @@ public abstract class KernelWriter extends BlockWriter{ write(barrierAndGetterMappings); } } else { + final String pattern = Kernel.getMethodMappedPattern(_methodEntry); + if (pattern != null) { + //System.out.println(pattern); + + String[] params = new String[argc]; + + for (int arg = 0; arg < argc; arg++) { + + StringWriter sw = new StringWriter(); + + sw.writeInstruction(_methodCall.getArg(arg)); + + params[arg] = sw.toString(); + } + + write(String.format(pattern, params)); + + return; + } + final boolean isSpecial = _methodCall instanceof I_INVOKESPECIAL; MethodModel m = entryPoint.getCallTarget(_methodEntry, isSpecial); @@ -381,15 +413,20 @@ public void writePragma(String _name, boolean _enable) { } // If it is a converted array of objects, emit the struct param - String className = null; if (signature.startsWith("L")) { - // Turn Lcom/codegen/javalabs/opencl/demo/DummyOOA; into com_amd_javalabs_opencl_demo_DummyOOA for example - className = (signature.substring(1, signature.length() - 1)).replace('/', '_'); - // if (logger.isLoggable(Level.FINE)) { - // logger.fine("Examining object parameter: " + signature + " new: " + className); - // } - argLine.append(className); - thisStructLine.append(className); + String mapTo = mapping.get(signature); + if (mapTo != null) { + argLine.append(mapTo); + thisStructLine.append(mapTo); + } else { + // Turn Lcom/codegen/javalabs/opencl/demo/DummyOOA; into com_amd_javalabs_opencl_demo_DummyOOA for example + String className = (signature.substring(1, signature.length() - 1)).replace('/', '_'); + // if (logger.isLoggable(Level.FINE)) { + // logger.fine("Examining object parameter: " + signature + " new: " + className); + // } + argLine.append(className); + thisStructLine.append(className); + } } else { argLine.append(convertType(ClassModel.typeName(signature.charAt(0)), false, false)); thisStructLine.append(convertType(ClassModel.typeName(signature.charAt(0)), false, false)); diff --git a/src/main/java/com/aparapi/opencl/vector/Float2.java b/src/main/java/com/aparapi/opencl/vector/Float2.java new file mode 100644 index 00000000..62b7c92d --- /dev/null +++ b/src/main/java/com/aparapi/opencl/vector/Float2.java @@ -0,0 +1,54 @@ +package com.aparapi.opencl.vector; + +import com.aparapi.Kernel.OpenCLMappingPattern; + +public final class Float2 { + + @OpenCLMappingPattern(mapTo = "(float2)( 0, 0 )") + public static Float2 create() { + return create(0f); + } + + @OpenCLMappingPattern(mapTo = "(float2)( %1$s, %1$s )") + public static Float2 create(float n) { + return new Float2(n, n); + } + + @OpenCLMappingPattern(mapTo = "(float2)( %s, %s )") + public static Float2 create(float x, float y) { + return new Float2(x, y); + } + + public final float x; + public final float y; + + private Float2(float x, float y) { + this.x = x; + this.y = y; + } + + @OpenCLMappingPattern(mapTo = "+") + public Float2 add(Float2 v1) { + return Float2.create(this.x + v1.x, this.y + v1.y); + } + + @OpenCLMappingPattern(mapTo = "-") + public Float2 subtract(Float2 v1) { + return Float2.create(this.x - v1.x, this.y - v1.y); + } + + @OpenCLMappingPattern(mapTo = "*") + public Float2 multiply(Float2 v1) { + return Float2.create(this.x * v1.x, this.y * v1.y); + } + + @OpenCLMappingPattern(mapTo = "/") + public Float2 divide(Float2 v1) { + return Float2.create(this.x / v1.x, this.y / v1.y); + } + + @OpenCLMappingPattern(mapTo = "%") + public Float2 remainder(Float2 v1) { + return Float2.create(this.x % v1.x, this.y % v1.y); + } +} diff --git a/src/test/java/com/aparapi/runtime/VectorTest.java b/src/test/java/com/aparapi/runtime/VectorTest.java new file mode 100644 index 00000000..39af0d21 --- /dev/null +++ b/src/test/java/com/aparapi/runtime/VectorTest.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2016 - 2017 Syncleus, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.aparapi.runtime; + +import static org.junit.Assert.assertEquals; + +import com.aparapi.Kernel; +import com.aparapi.opencl.vector.Float2; +import org.junit.Test; + + +public class VectorTest { + @Test + public void test() { + VectorKernel b = new VectorKernel(); + b.test(); + } + + public static class VectorKernel extends Kernel { + private static final int SIZE = 32; + + final Float2[] target = new Float2[SIZE]; + + VectorKernel() { + for (int i = 0; i < SIZE; ++i) { + target[i] = Float2.create(); + } + } + + @Override + public void run() { + int id = getGlobalId(); + + // float2 v = (float2)( 0, 0 ); +// final Float2 v = Float2.create(id); + + final Float2 v = Float2.create(id, id * 2); + target[id] = v; + } + + void validate() { + for (int i = 0; i < SIZE; i++) { + + Float2 v = target[i]; + + assertEquals(i, v.x, 0.01f); + assertEquals(i * 2, v.y, 0.01f); + } + } + + public void test() { + execute(SIZE); + validate(); + } + } +} From 1379e1dfafc913d4d9e249d784ae45dceeb0509d Mon Sep 17 00:00:00 2001 From: Dmitriy Shabanov Date: Tue, 24 Oct 2017 12:03:54 +0300 Subject: [PATCH 2/2] vector feature prototype --- .../aparapi/internal/jni/KernelArgJNI.java | 5 ++ .../aparapi/internal/jni/KernelRunnerJNI.java | 56 +++++++++++++- .../aparapi/internal/kernel/KernelRunner.java | 74 +++++++++++++++---- .../java/com/aparapi/runtime/VectorTest.java | 4 +- 4 files changed, 120 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/aparapi/internal/jni/KernelArgJNI.java b/src/main/java/com/aparapi/internal/jni/KernelArgJNI.java index 23543349..dd5e01bb 100644 --- a/src/main/java/com/aparapi/internal/jni/KernelArgJNI.java +++ b/src/main/java/com/aparapi/internal/jni/KernelArgJNI.java @@ -46,6 +46,11 @@ public abstract class KernelArgJNI{ * @see KernelRunnerJNI#ARG_EXPLICIT * @see KernelRunnerJNI#ARG_EXPLICIT_WRITE * @see KernelRunnerJNI#ARG_OBJ_ARRAY_STRUCT + * @see KernelRunnerJNI#ARG_VECTOR_2 + * @see KernelRunnerJNI#ARG_VECTOR_3 + * @see KernelRunnerJNI#ARG_VECTOR_4 + * @see KernelRunnerJNI#ARG_VECTOR_8 + * @see KernelRunnerJNI#ARG_VECTOR_16 */ @UsedByJNICode protected int type; diff --git a/src/main/java/com/aparapi/internal/jni/KernelRunnerJNI.java b/src/main/java/com/aparapi/internal/jni/KernelRunnerJNI.java index 2ef6a54f..7c92040c 100644 --- a/src/main/java/com/aparapi/internal/jni/KernelRunnerJNI.java +++ b/src/main/java/com/aparapi/internal/jni/KernelRunnerJNI.java @@ -236,14 +236,64 @@ public abstract class KernelRunnerJNI{ /** * This 'bit' indicates that a particular KernelArg represents a static field (array or primitive). - * - * + * + * * @see com.aparapi.internal.annotation.UsedByJNICode - * + * * @author gfrost */ @UsedByJNICode protected static final int ARG_STATIC = 1 << 22; + /** + * This 'bit' indicates that a particular KernelArg represents a vector2 field (array or primitive). + * + * + * @see com.aparapi.internal.annotation.UsedByJNICode + * + * @author gfrost + */ + @UsedByJNICode protected static final int ARG_VECTOR_2 = 1 << 25; + + /** + * This 'bit' indicates that a particular KernelArg represents a vector3 field (array or primitive). + * + * + * @see com.aparapi.internal.annotation.UsedByJNICode + * + * @author gfrost + */ + @UsedByJNICode protected static final int ARG_VECTOR_3 = 1 << 26; + + /** + * This 'bit' indicates that a particular KernelArg represents a vector4 field (array or primitive). + * + * + * @see com.aparapi.internal.annotation.UsedByJNICode + * + * @author gfrost + */ + @UsedByJNICode protected static final int ARG_VECTOR_4 = 1 << 27; + + /** + * This 'bit' indicates that a particular KernelArg represents a vector8 field (array or primitive). + * + * + * @see com.aparapi.internal.annotation.UsedByJNICode + * + * @author gfrost + */ + @UsedByJNICode protected static final int ARG_VECTOR_8 = 1 << 28; + + /** + * This 'bit' indicates that a particular KernelArg represents a vector16 field (array or primitive). + * + * + * @see com.aparapi.internal.annotation.UsedByJNICode + * + * @author gfrost + */ + @UsedByJNICode protected static final int ARG_VECTOR_16 = 1 << 29; + /** * This 'bit' indicates that we wish to enable profiling from the JNI code. * diff --git a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java index 66f8e72b..d7679369 100644 --- a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java +++ b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java @@ -65,6 +65,7 @@ to national security controls as identified on the Commerce Control List (curren import com.aparapi.internal.writer.*; import com.aparapi.opencl.*; +import com.aparapi.opencl.vector.Float2; import java.lang.reflect.*; import java.nio.*; import java.util.*; @@ -943,7 +944,24 @@ private void extractOopConversionBuffer(KernelArg arg) throws AparapiException { private void restoreObjects() throws AparapiException { for (int i = 0; i < argc; i++) { final KernelArg arg = args[i]; - if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) { + + //TODO: code it properly + if ((arg.getType() & ARG_VECTOR_2) != 0) { + Object obj = arg.getArray(); + + float[] array = (float[])obj; + + try { + Float2[] ref = (Float2[])arg.getField().get(kernel); + + for (int j = 0; j < ref.length; j++) { + ref[j] = Float2.create(array[j * 2 + 0], array[j * 2 + 1]); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + } else if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) { extractOopConversionBuffer(arg); } } @@ -979,6 +997,11 @@ private boolean updateKernelArrayRefs() throws AparapiException { if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) { prepareOopConversionBuffer(arg); } else { + //TODO: handle vectors + if ((arg.getType() & ARG_VECTOR_2) != 0) { + usesOopConversion = true; + newArrayRef = new float[arrayLength * 2]; + } // set up JNI fields for normal arrays arg.setJavaArray(newArrayRef); arg.setNumElements(arrayLength); @@ -1415,9 +1438,19 @@ else if (Config.enableShowGeneratedOpenCL) { // args[i].type |= ARG_GLOBAL; if (type.getName().startsWith("[L")) { - args[i].setArray(null); // will get updated in updateKernelArrayRefs - args[i].setType(args[i].getType() - | (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)); + //TODO: get flags from annotation + if ("[Lcom.aparapi.opencl.vector.Float2;".equals(type.getName())) { + args[i].setArray(null); + args[i].setType( + args[i].getType() | (ARG_ARRAY | ARG_FLOAT | ARG_VECTOR_2 | ARG_WRITE | ARG_READ) + ); + } else { + // will get updated in updateKernelArrayRefs + args[i].setArray(null); + args[i].setType( + args[i].getType() | (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ) + ); + } if (logger.isLoggable(Level.FINE)) { logger.fine("tagging " + args[i].getName() + " as (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)"); @@ -1633,24 +1666,39 @@ private int getCurrentPassLocal() { } private int getPrimitiveSize(int type) { + int size = 0; if ((type & ARG_FLOAT) != 0) { - return 4; + size = 4; } else if ((type & ARG_INT) != 0) { - return 4; + size = 4; } else if ((type & ARG_BYTE) != 0) { - return 1; + size = 1; } else if ((type & ARG_CHAR) != 0) { - return 2; + size = 2; } else if ((type & ARG_BOOLEAN) != 0) { - return 1; + size = 1; } else if ((type & ARG_SHORT) != 0) { - return 2; + size = 2; } else if ((type & ARG_LONG) != 0) { - return 8; + size = 8; } else if ((type & ARG_DOUBLE) != 0) { - return 8; + size = 8; } - return 0; + + int vectorFactor = 1; + if ((type & ARG_VECTOR_2) != 0) { + vectorFactor = 2; + } else if ((type & ARG_VECTOR_3) != 0) { + vectorFactor = 3; + } else if ((type & ARG_VECTOR_4) != 0) { + vectorFactor = 4; + } else if ((type & ARG_VECTOR_8) != 0) { + vectorFactor = 8; + } else if ((type & ARG_VECTOR_16) != 0) { + vectorFactor = 16; + } + + return size * vectorFactor; } private void setMultiArrayType(KernelArg arg, Class type) throws AparapiException { diff --git a/src/test/java/com/aparapi/runtime/VectorTest.java b/src/test/java/com/aparapi/runtime/VectorTest.java index 39af0d21..ce6e76dd 100644 --- a/src/test/java/com/aparapi/runtime/VectorTest.java +++ b/src/test/java/com/aparapi/runtime/VectorTest.java @@ -19,6 +19,7 @@ import com.aparapi.Kernel; import com.aparapi.opencl.vector.Float2; +import java.util.Arrays; import org.junit.Test; @@ -44,9 +45,6 @@ public static class VectorKernel extends Kernel { public void run() { int id = getGlobalId(); - // float2 v = (float2)( 0, 0 ); -// final Float2 v = Float2.create(id); - final Float2 v = Float2.create(id, id * 2); target[id] = v; }