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

[GR-2798] Implemented VectorDataReuse nodes.

PullRequest: fastr/1338
parents 05f63277 9b48c144
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