Skip to content
Snippets Groups Projects
Commit 9b48c144 authored by Miloslav Metelka's avatar Miloslav Metelka
Browse files

Implemented VectorDataReuse nodes.

parent 05f63277
No related branches found
No related tags found
No related merge requests found
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.oracle.truffle.r.nodes.access.vector;
import static com.oracle.truffle.r.nodes.test.TestUtilities.generateInteger;
import static com.oracle.truffle.r.nodes.test.TestUtilities.generateComplex;
import static org.hamcrest.MatcherAssert.assertThat;
import com.oracle.truffle.r.nodes.test.TestBase;
import static com.oracle.truffle.r.nodes.test.TestUtilities.generateDouble;
import com.oracle.truffle.r.runtime.RType;
import com.oracle.truffle.r.runtime.data.NativeDataAccess;
import com.oracle.truffle.r.runtime.data.RComplex;
import com.oracle.truffle.r.runtime.data.RComplexVector;
import com.oracle.truffle.r.runtime.data.RDoubleVector;
import com.oracle.truffle.r.runtime.data.RIntVector;
import com.oracle.truffle.r.runtime.data.RVector;
import com.oracle.truffle.r.runtime.data.nodes.VectorDataReuse;
import org.junit.Test;
import org.junit.experimental.theories.Theories;
import org.junit.runner.RunWith;
@RunWith(Theories.class)
public class VectorManipulationTest extends TestBase {
@Test
public void dummy() {
// to make sure this file is recognized as a test
}
@Test
public void testVectorDataReuse() {
execInContext(() -> {
// Int
RIntVector intVec = generateInteger(2, true).materialize();
VectorDataReuse.Int intDataReuseNode = VectorDataReuse.Int.create();
assertThat("Not temporary", intVec.isTemporary());
int[] intData = intDataReuseNode.execute(intVec.materialize());
assertThat("Invalid data reuse array", intVec.getInternalManagedData() == intData);
intVec.incRefCount();
intData = intDataReuseNode.execute(intVec.materialize());
assertThat("Invalid data reuse array", intVec.getInternalManagedData() != intData);
assertDataContents(intVec, intData);
NativeDataAccess.asPointer(intVec);
intVec.allocateNativeContents();
intData = intDataReuseNode.execute(intVec.materialize());
assertThat("Invalid data reuse array", intVec.getInternalManagedData() != intData);
assertDataContents(intVec, intData);
intVec = generateInteger(2, true).materialize();
assertThat("Not temporary", intVec.isTemporary());
NativeDataAccess.asPointer(intVec);
intVec.allocateNativeContents();
assertThat("Not a native mirror", intVec.getInternalManagedData() == null);
intData = intDataReuseNode.execute(intVec.materialize());
assertThat("Invalid data reuse array", intVec.getInternalManagedData() != intData);
assertDataContents(intVec, intData);
// Double
RDoubleVector doubleVector = generateDouble(2, true).materialize();
VectorDataReuse.Double doubleDataReuseNode = VectorDataReuse.Double.create();
assertThat("Not temporary", doubleVector.isTemporary());
double[] doubleData = doubleDataReuseNode.execute(doubleVector.materialize());
assertThat("Invalid data reuse array", doubleVector.getInternalManagedData() == doubleData);
doubleVector.incRefCount();
doubleData = doubleDataReuseNode.execute(doubleVector.materialize());
assertThat("Invalid data reuse array", doubleVector.getInternalManagedData() != doubleData);
assertDataContents(doubleVector, doubleData);
NativeDataAccess.asPointer(doubleVector);
doubleVector.allocateNativeContents();
doubleData = doubleDataReuseNode.execute(doubleVector.materialize());
assertThat("Invalid data reuse array", doubleVector.getInternalManagedData() != doubleData);
assertDataContents(doubleVector, doubleData);
doubleVector = generateDouble(2, true).materialize();
assertThat("Not temporary", doubleVector.isTemporary());
NativeDataAccess.asPointer(doubleVector);
doubleVector.allocateNativeContents();
assertThat("Not a native mirror", doubleVector.getInternalManagedData() == null);
doubleData = doubleDataReuseNode.execute(doubleVector.materialize());
assertThat("Invalid data reuse array", doubleVector.getInternalManagedData() != doubleData);
assertDataContents(doubleVector, doubleData);
// Complex
RComplexVector complexVector = generateComplex(2, true).materialize();
VectorDataReuse.Complex complexDataReuseNode = VectorDataReuse.Complex.create();
assertThat("Not temporary", complexVector.isTemporary());
double[] complexData = complexDataReuseNode.execute(complexVector.materialize());
assertThat("Invalid data reuse array", complexVector.getInternalManagedData() == complexData);
complexVector.incRefCount();
complexData = complexDataReuseNode.execute(complexVector.materialize());
assertThat("Invalid data reuse array", complexVector.getInternalManagedData() != complexData);
assertDataContents(complexVector, complexData);
NativeDataAccess.asPointer(complexVector);
complexVector.allocateNativeContents();
complexData = complexDataReuseNode.execute(complexVector.materialize());
assertThat("Invalid data reuse array", complexVector.getInternalManagedData() != complexData);
assertDataContents(complexVector, complexData);
complexVector = generateComplex(2, true).materialize();
assertThat("Not temporary", complexVector.isTemporary());
NativeDataAccess.asPointer(complexVector);
complexVector.allocateNativeContents();
assertThat("Not a native mirror", complexVector.getInternalManagedData() == null);
complexData = complexDataReuseNode.execute(complexVector.materialize());
assertThat("Invalid data reuse array", complexVector.getInternalManagedData() != complexData);
assertDataContents(complexVector, complexData);
return null;
});
}
private <ArrayT> void assertDataContents(RVector<ArrayT> vec, ArrayT arr) {
int len = vec.getLength();
RType type = vec.getRType();
for (int i = 0; i < len; i++) {
Object expected = vec.getDataAtAsObject(i);
Object tested;
switch (type) {
case Integer:
tested = ((int[]) arr)[i];
break;
case Double:
tested = ((double[]) arr)[i];
break;
case Complex:
tested = RComplex.valueOf(((double[]) arr)[2 * i], ((double[]) arr)[2 * i + 1]);
break;
case List:
tested = ((Object[]) arr)[i];
break;
default:
throw new AssertionError("Type check not implemented yet.");
}
assertThat("Values differ at index=" + i + ", expected=" + expected + ", tested=" + tested,
(expected == null && tested == null) || (expected != null && expected.equals(tested)));
}
}
}
......@@ -39,6 +39,7 @@ import com.oracle.truffle.r.runtime.context.TruffleRLanguage;
import com.oracle.truffle.r.runtime.data.RComplex;
import com.oracle.truffle.r.runtime.data.RDataFactory;
import com.oracle.truffle.r.runtime.data.RNull;
import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
......@@ -123,7 +124,7 @@ public class TestUtilities {
return RDataFactory.createDoubleVector(array, complete || !complete && size < 3);
}
public static RAbstractVector generateComplex(int size, boolean complete) {
public static RAbstractComplexVector generateComplex(int size, boolean complete) {
double[] array = new double[size << 1];
for (int i = 0; i < size; i++) {
boolean useNA = !complete && i % (NA_INDEX + 1) == NA_INDEX;
......
......@@ -365,6 +365,15 @@ public final class NativeDataAccess {
return data;
}
public static double[] copyComplexNativeData(Object mirrorObj) {
NativeMirror mirror = (NativeMirror) mirrorObj;
long address = mirror.dataAddress;
assert address != 0;
double[] data = new double[(int) (mirror.length << 1)];
UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_DOUBLE_BASE_OFFSET, data.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
return data;
}
public static int[] copyIntNativeData(Object mirrorObj) {
NativeMirror mirror = (NativeMirror) mirrorObj;
long address = mirror.dataAddress;
......
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.oracle.truffle.r.runtime.data.nodes;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.r.runtime.RInternalError;
import com.oracle.truffle.r.runtime.data.NativeDataAccess;
import com.oracle.truffle.r.runtime.data.RComplexVector;
import com.oracle.truffle.r.runtime.data.RDoubleVector;
import com.oracle.truffle.r.runtime.data.RIntVector;
import com.oracle.truffle.r.runtime.data.RList;
import java.util.Arrays;
/**
* Nodes contained in this class allow to reuse an internal data array of a vector which is
* temporary (has zero refCount) and its data are not natively held. Otherwise a copy of the data
* array is returned.
*/
public class VectorDataReuse {
public abstract static class Int extends Node {
public abstract int[] execute(RIntVector vector);
@Specialization(guards = {"!vec.hasNativeMemoryData()", "vec.isTemporary()"})
protected int[] doManagedTempRVector(RIntVector vec) {
return vec.getInternalManagedData();
}
@Specialization(guards = {"!vec.hasNativeMemoryData()", "!vec.isTemporary()"})
protected int[] doManagedRVector(RIntVector vec) {
int[] data = vec.getInternalManagedData();
return Arrays.copyOf(data, data.length);
}
@Specialization(guards = "vec.hasNativeMemoryData()")
protected int[] doNativeDataRVector(RIntVector vec) {
return NativeDataAccess.copyIntNativeData(vec.getNativeMirror());
}
public static Int create() {
return VectorDataReuseFactory.IntNodeGen.create();
}
}
public abstract static class Double extends Node {
public abstract double[] execute(RDoubleVector vector);
@Specialization(guards = {"!vec.hasNativeMemoryData()", "vec.isTemporary()"})
protected double[] doManagedTempRVector(RDoubleVector vec) {
return vec.getInternalManagedData();
}
@Specialization(guards = {"!vec.hasNativeMemoryData()", "!vec.isTemporary()"})
protected double[] doManagedRVector(RDoubleVector vec) {
double[] data = vec.getInternalManagedData();
return Arrays.copyOf(data, data.length);
}
@Specialization(guards = "vec.hasNativeMemoryData()")
protected double[] doNativeDataRVector(RDoubleVector vec) {
return NativeDataAccess.copyDoubleNativeData(vec.getNativeMirror());
}
public static Double create() {
return VectorDataReuseFactory.DoubleNodeGen.create();
}
}
public abstract static class Complex extends Node {
public abstract double[] execute(RComplexVector vector);
@Specialization(guards = {"!vec.hasNativeMemoryData()", "vec.isTemporary()"})
protected double[] doManagedTempRVector(RComplexVector vec) {
return vec.getInternalManagedData();
}
@Specialization(guards = {"!vec.hasNativeMemoryData()", "!vec.isTemporary()"})
protected double[] doManagedRVector(RComplexVector vec) {
double[] data = vec.getInternalManagedData();
return Arrays.copyOf(data, data.length);
}
@Specialization(guards = "vec.hasNativeMemoryData()")
protected double[] doNativeDataRVector(RComplexVector vec) {
return NativeDataAccess.copyComplexNativeData(vec.getNativeMirror());
}
public static Complex create() {
return VectorDataReuseFactory.ComplexNodeGen.create();
}
}
public abstract static class ListData extends Node {
public abstract Object[] execute(RList vector);
@Specialization(guards = {"!vec.hasNativeMemoryData()", "vec.isTemporary()"})
protected Object[] doManagedTempRVector(RList vec) {
return vec.getInternalManagedData();
}
@Specialization(guards = {"!vec.hasNativeMemoryData()", "!vec.isTemporary()"})
protected Object[] doManagedRVector(RList vec) {
Object[] data = vec.getInternalManagedData();
return Arrays.copyOf(data, data.length);
}
@Specialization(guards = "vec.hasNativeMemoryData()")
protected Object[] doNativeDataRVector(@SuppressWarnings("unused") RList vec) {
throw RInternalError.shouldNotReachHere("list cannot have native memory");
}
public static ListData create() {
return VectorDataReuseFactory.ListDataNodeGen.create();
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment