From 2355d32c9adcc697d36d010f6f7b0d87300a4b92 Mon Sep 17 00:00:00 2001 From: Alex Merritt Date: Sat, 5 Feb 2022 02:56:38 +0900 Subject: [PATCH 1/7] Remove a few lingering allocateDirect calls --- .../com/nec/ve/colvector/VeColVector.scala | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/scala/com/nec/ve/colvector/VeColVector.scala b/src/main/scala/com/nec/ve/colvector/VeColVector.scala index c60042b5c..26ded0b67 100644 --- a/src/main/scala/com/nec/ve/colvector/VeColVector.scala +++ b/src/main/scala/com/nec/ve/colvector/VeColVector.scala @@ -30,7 +30,6 @@ import org.apache.arrow.vector._ import org.apache.spark.sql.vectorized.ColumnVector import org.bytedeco.javacpp.BytePointer import sun.misc.Unsafe -import java.nio.ByteBuffer final case class VeColVector(underlying: GenericColVector[Long]) { def allAllocations = containerLocation :: bufferLocations @@ -143,8 +142,8 @@ final case class VeColVector(underlying: GenericColVector[Long]) { if (numItems > 0) { val dataSize = numItems * 8 float8Vector.setValueCount(numItems) - val vhTarget = new BytePointer(ByteBuffer.allocateDirect(dataSize)) - val validityTarget = new BytePointer(ByteBuffer.allocateDirect(numItems)) + val vhTarget = new BytePointer(dataSize) + val validityTarget = new BytePointer(numItems) veProcess.get(buffers.head, vhTarget, vhTarget.limit()) veProcess.get(buffers(1), validityTarget, validityTarget.limit()) getUnsafe.copyMemory( @@ -164,8 +163,8 @@ final case class VeColVector(underlying: GenericColVector[Long]) { if (numItems > 0) { val dataSize = numItems * 8 bigIntVector.setValueCount(numItems) - val vhTarget = new BytePointer(ByteBuffer.allocateDirect(dataSize)) - val validityTarget = new BytePointer(ByteBuffer.allocateDirect(numItems)) + val vhTarget = new BytePointer(dataSize) + val validityTarget = new BytePointer(numItems) veProcess.get(buffers.head, vhTarget, vhTarget.limit()) veProcess.get(buffers(1), validityTarget, validityTarget.limit()) getUnsafe.copyMemory( @@ -185,8 +184,8 @@ final case class VeColVector(underlying: GenericColVector[Long]) { if (numItems > 0) { val dataSize = numItems * 4 intVector.setValueCount(numItems) - val vhTarget = new BytePointer(ByteBuffer.allocateDirect(dataSize)) - val validityTarget = new BytePointer(ByteBuffer.allocateDirect(numItems)) + val vhTarget = new BytePointer(dataSize) + val validityTarget = new BytePointer(numItems) veProcess.get(buffers.head, vhTarget, vhTarget.limit()) veProcess.get(buffers(1), validityTarget, validityTarget.limit()) getUnsafe.copyMemory( @@ -206,13 +205,13 @@ final case class VeColVector(underlying: GenericColVector[Long]) { if (numItems > 0) { val offsetsSize = (numItems + 1) * 4 val lastOffsetIndex = numItems * 4 - val offTarget = new BytePointer(ByteBuffer.allocateDirect(offsetsSize)) - val validityTarget = new BytePointer(ByteBuffer.allocateDirect(numItems)) + val offTarget = new BytePointer(offsetsSize) + val validityTarget = new BytePointer(numItems) veProcess.get(buffers(1), new BytePointer(offTarget), offTarget.limit()) veProcess.get(buffers(2), validityTarget, validityTarget.limit()) val dataSize = offTarget.getInt(lastOffsetIndex) - val vhTarget = new BytePointer(ByteBuffer.allocateDirect(dataSize)) + val vhTarget = new BytePointer(dataSize) offTarget.position(0) veProcess.get(buffers.head, vhTarget, vhTarget.limit()) From 7bbf6ea6db0fd0d21b84a260d819dc9c935e216e Mon Sep 17 00:00:00 2001 From: Alex Merritt Date: Tue, 8 Feb 2022 06:38:21 +0900 Subject: [PATCH 2/7] Replace JNA usage in ArrowTransferStructures with JavaCPP --- build.sbt | 3 + .../nec/arrow/ArrowTransferStructures.java | 280 ---------- .../com/nec/arrow/TransferDefinitions.java | 488 ++++++++++++++++++ .../nec/arrow/TransferDefinitionsConfig.java | 24 + .../nec/cyclone/cpp/transfer-definitions.hpp | 30 +- .../libjniTransferDefinitions.so | Bin 0 -> 129960 bytes .../scala/com/nec/arrow/ArrowInterfaces.scala | 117 +++-- .../com/nec/arrow/CArrowNativeInterface.scala | 2 +- .../com/nec/arrow/VeArrowTransfers.scala | 155 +++--- .../com/nec/ve/colvector/VeColVector.scala | 83 ++- .../com/nec/arrow/ArrowInterfacesTest.scala | 9 +- 11 files changed, 748 insertions(+), 443 deletions(-) delete mode 100644 src/main/java/com/nec/arrow/ArrowTransferStructures.java create mode 100644 src/main/java/com/nec/arrow/TransferDefinitions.java create mode 100644 src/main/java/com/nec/arrow/TransferDefinitionsConfig.java create mode 100755 src/main/resources/transferdefinitions/libjniTransferDefinitions.so diff --git a/build.sbt b/build.sbt index f096dd2a9..c342babd2 100644 --- a/build.sbt +++ b/build.sbt @@ -146,6 +146,9 @@ libraryDependencies ++= { } } + +Test / javaOptions ++= Seq("-Djava.library.path=" + new File("./src/main/resources/transferdefinitions").getAbsolutePath) +Test / fork := true Test / unmanagedJars ++= sys.env .get("CUDF_PATH") .map(path => new File(path)) diff --git a/src/main/java/com/nec/arrow/ArrowTransferStructures.java b/src/main/java/com/nec/arrow/ArrowTransferStructures.java deleted file mode 100644 index a75748f86..000000000 --- a/src/main/java/com/nec/arrow/ArrowTransferStructures.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (c) 2021 Xpress AI. - * - * This file is part of Spark Cyclone. - * See https://github.com/XpressAI/SparkCyclone for further info. - * - * 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.nec.arrow; - -import com.sun.jna.Library; -import com.sun.jna.Pointer; -import com.sun.jna.Structure; - -public interface ArrowTransferStructures extends Library { - - @Structure.FieldOrder({"data", "count"}) - class non_null_int_vector extends Structure { - public long data; - public Integer count; - - public non_null_int_vector() { - super(); - } - - public non_null_int_vector(Pointer p) { - super(p); - read(); - } - - public static class ByReference extends non_null_int_vector implements Structure.ByReference { - public ByReference() { - } - - public ByReference(Pointer p) { - super(p); - } - } - } - - @Structure.FieldOrder({"data","validityBuffer", "count"}) - class nullable_int_vector extends Structure { - public long data; - public long validityBuffer; - public Integer count; - - public int dataSize() { - return count * 4; - } - - public nullable_int_vector() { - super(); - } - - public nullable_int_vector(Pointer p) { - super(p); - read(); - } - - public static class ByReference extends nullable_int_vector implements Structure.ByReference { - public ByReference() { - } - - public ByReference(Pointer p) { - super(p); - } - } - } - - @Structure.FieldOrder({"data", "count"}) - class non_null_int2_vector extends Structure { - public long data; - public Integer count; - - public non_null_int2_vector() { - super(); - } - - public non_null_int2_vector(Pointer p) { - super(p); - read(); - } - - public static class ByReference extends non_null_int2_vector implements Structure.ByReference { - public ByReference() { - } - - public ByReference(Pointer p) { - super(p); - } - } - } - - @Structure.FieldOrder({"data", "count"}) - class non_null_double_vector extends Structure { - public long data; - public Integer count; - - public int dataSize() { - return count * 8; - } - - public non_null_double_vector() { - super(); - } - - public non_null_double_vector(int count) { - super(); - this.count = count; - } - - public non_null_double_vector(Pointer p) { - super(p); - read(); - } - - public static class ByReference extends non_null_double_vector implements Structure.ByReference { - public ByReference() { - } - - public ByReference(Pointer p) { - super(p); - } - } - } - - @Structure.FieldOrder({"data", "validityBuffer", "count", }) - class nullable_double_vector extends Structure { - public long data; - public long validityBuffer; - public Integer count; - - public int dataSize() { - return count * 8; - } - - public nullable_double_vector() { - super(); - } - - public nullable_double_vector(Pointer p) { - super(p); - read(); - } - - public static class ByReference extends nullable_double_vector implements Structure.ByReference { - public ByReference() { - } - - public ByReference(Pointer p) { - super(p); - } - } - } - - @Structure.FieldOrder({"data", "validityBuffer", "count", }) - class nullable_bigint_vector extends Structure { - public long data; - public long validityBuffer; - public Integer count; - - public int dataSize() { - return count * 8; - } - - public nullable_bigint_vector() { - super(); - } - - public nullable_bigint_vector(Pointer p) { - super(p); - read(); - } - - public static class ByReference extends nullable_bigint_vector implements Structure.ByReference { - public ByReference() { - } - - public ByReference(Pointer p) { - super(p); - } - } - } - - @Structure.FieldOrder({"data", "offsets", "validityBuffer", "dataSize", "count"}) - class nullable_varchar_vector extends Structure { - public long data; - public long offsets; - public long validityBuffer; - public Integer dataSize; - public Integer count; - /* 24 + 8 = 32 bytes in size */ - - public nullable_varchar_vector() { - super(); - } - - public nullable_varchar_vector(Pointer p) { - super(p); - read(); - } - - public static class ByReference extends nullable_varchar_vector implements Structure.ByReference { - public ByReference() { - } - - public ByReference(Pointer p) { - super(p); - } - } - } - - @Structure.FieldOrder({"data", "count"}) - class non_null_bigint_vector extends Structure { - public long data; - public Integer count; - - public int dataSize() { - return count * 8; - } - - public non_null_bigint_vector() { - super(); - } - - public non_null_bigint_vector(int count) { - super(); - this.count = count; - } - - public non_null_bigint_vector(Pointer p) { - super(p); - read(); - } - - public static class ByReference extends non_null_bigint_vector implements Structure.ByReference { - public ByReference() { - } - - public ByReference(Pointer p) { - super(p); - } - } - } - - @Structure.FieldOrder({"data", "length"}) - class non_null_c_bounded_string extends Structure { - public long data; - public Integer length; - - public non_null_c_bounded_string() { - super(); - } - - public non_null_c_bounded_string(Pointer p) { - super(p); - read(); - } - - public static class ByReference extends non_null_c_bounded_string implements Structure.ByReference { - public ByReference() { - } - - public ByReference(Pointer p) { - super(p); - } - } - } -} \ No newline at end of file diff --git a/src/main/java/com/nec/arrow/TransferDefinitions.java b/src/main/java/com/nec/arrow/TransferDefinitions.java new file mode 100644 index 000000000..3e7a9b24f --- /dev/null +++ b/src/main/java/com/nec/arrow/TransferDefinitions.java @@ -0,0 +1,488 @@ +// Targeted by JavaCPP version 1.5.6: DO NOT EDIT THIS FILE + +package com.nec.arrow; + +import java.nio.*; +import org.bytedeco.javacpp.*; +import org.bytedeco.javacpp.annotation.*; + +public class TransferDefinitions extends TransferDefinitionsConfig { + static { Loader.load(); } + +@Name("std::vector") public static class StringVector extends Pointer { + static { Loader.load(); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public StringVector(Pointer p) { super(p); } + public StringVector(BytePointer value) { this(1); put(0, value); } + public StringVector(BytePointer ... array) { this(array.length); put(array); } + public StringVector(String value) { this(1); put(0, value); } + public StringVector(String ... array) { this(array.length); put(array); } + public StringVector() { allocate(); } + public StringVector(long n) { allocate(n); } + private native void allocate(); + private native void allocate(@Cast("size_t") long n); + public native @Name("operator =") @ByRef StringVector put(@ByRef StringVector x); + + public boolean empty() { return size() == 0; } + public native long size(); + public void clear() { resize(0); } + public native void resize(@Cast("size_t") long n); + + @Index(function = "at") public native @StdString BytePointer get(@Cast("size_t") long i); + public native StringVector put(@Cast("size_t") long i, BytePointer value); + @ValueSetter @Index(function = "at") public native StringVector put(@Cast("size_t") long i, @StdString String value); + + public native @ByVal Iterator insert(@ByVal Iterator pos, @StdString BytePointer value); + public native @ByVal Iterator erase(@ByVal Iterator pos); + public native @ByVal Iterator begin(); + public native @ByVal Iterator end(); + @NoOffset @Name("iterator") public static class Iterator extends Pointer { + public Iterator(Pointer p) { super(p); } + public Iterator() { } + + public native @Name("operator ++") @ByRef Iterator increment(); + public native @Name("operator ==") boolean equals(@ByRef Iterator it); + public native @Name("operator *") @StdString BytePointer get(); + } + + public BytePointer[] get() { + BytePointer[] array = new BytePointer[size() < Integer.MAX_VALUE ? (int)size() : Integer.MAX_VALUE]; + for (int i = 0; i < array.length; i++) { + array[i] = get(i); + } + return array; + } + @Override public String toString() { + return java.util.Arrays.toString(get()); + } + + public BytePointer pop_back() { + long size = size(); + BytePointer value = get(size - 1); + resize(size - 1); + return value; + } + public StringVector push_back(BytePointer value) { + long size = size(); + resize(size + 1); + return put(size, value); + } + public StringVector put(BytePointer value) { + if (size() != 1) { resize(1); } + return put(0, value); + } + public StringVector put(BytePointer ... array) { + if (size() != array.length) { resize(array.length); } + for (int i = 0; i < array.length; i++) { + put(i, array[i]); + } + return this; + } + + public StringVector push_back(String value) { + long size = size(); + resize(size + 1); + return put(size, value); + } + public StringVector put(String value) { + if (size() != 1) { resize(1); } + return put(0, value); + } + public StringVector put(String ... array) { + if (size() != array.length) { resize(array.length); } + for (int i = 0; i < array.length; i++) { + put(i, array[i]); + } + return this; + } +} + +@Name("std::vector") public static class SizeTVector extends Pointer { + static { Loader.load(); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public SizeTVector(Pointer p) { super(p); } + public SizeTVector(long ... array) { this(array.length); put(array); } + public SizeTVector() { allocate(); } + public SizeTVector(long n) { allocate(n); } + private native void allocate(); + private native void allocate(@Cast("size_t") long n); + public native @Name("operator =") @ByRef SizeTVector put(@ByRef SizeTVector x); + + public boolean empty() { return size() == 0; } + public native long size(); + public void clear() { resize(0); } + public native void resize(@Cast("size_t") long n); + + @Index(function = "at") public native @Cast("size_t") long get(@Cast("size_t") long i); + public native SizeTVector put(@Cast("size_t") long i, long value); + + public native @ByVal Iterator insert(@ByVal Iterator pos, @Cast("size_t") long value); + public native @ByVal Iterator erase(@ByVal Iterator pos); + public native @ByVal Iterator begin(); + public native @ByVal Iterator end(); + @NoOffset @Name("iterator") public static class Iterator extends Pointer { + public Iterator(Pointer p) { super(p); } + public Iterator() { } + + public native @Name("operator ++") @ByRef Iterator increment(); + public native @Name("operator ==") boolean equals(@ByRef Iterator it); + public native @Name("operator *") @Cast("size_t") long get(); + } + + public long[] get() { + long[] array = new long[size() < Integer.MAX_VALUE ? (int)size() : Integer.MAX_VALUE]; + for (int i = 0; i < array.length; i++) { + array[i] = get(i); + } + return array; + } + @Override public String toString() { + return java.util.Arrays.toString(get()); + } + + public long pop_back() { + long size = size(); + long value = get(size - 1); + resize(size - 1); + return value; + } + public SizeTVector push_back(long value) { + long size = size(); + resize(size + 1); + return put(size, value); + } + public SizeTVector put(long value) { + if (size() != 1) { resize(1); } + return put(0, value); + } + public SizeTVector put(long ... array) { + if (size() != array.length) { resize(array.length); } + for (int i = 0; i < array.length; i++) { + put(i, array[i]); + } + return this; + } +} + +// Parsed from transfer-definitions.hpp + +/* + * Copyright (c) 2021 Xpress AI. + * + * This file is part of Spark Cyclone. + * See https://github.com/XpressAI/SparkCyclone for further info. + * + * 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. + * + */ +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// #ifndef VE_TD_DEFS +public static class data_out extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public data_out() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public data_out(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public data_out(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public data_out position(long position) { + return (data_out)super.position(position); + } + @Override public data_out getPointer(long i) { + return new data_out((Pointer)this).offsetAddress(i); + } + + public native Pointer data(int i); public native data_out data(int i, Pointer setter); + public native @Cast("void**") PointerPointer data(); public native data_out data(PointerPointer setter); + public native @Cast("size_t") long count(); public native data_out count(long setter); + public native @Cast("size_t") long size(); public native data_out size(long setter); +} + +public static class varchar_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public varchar_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public varchar_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public varchar_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public varchar_vector position(long position) { + return (varchar_vector)super.position(position); + } + @Override public varchar_vector getPointer(long i) { + return new varchar_vector((Pointer)this).offsetAddress(i); + } + + public native @Cast("char*") BytePointer data(); public native varchar_vector data(BytePointer setter); + public native IntPointer offsets(); public native varchar_vector offsets(IntPointer setter); + public native int count(); public native varchar_vector count(int setter); +} + +public static class nullable_int_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public nullable_int_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public nullable_int_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public nullable_int_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public nullable_int_vector position(long position) { + return (nullable_int_vector)super.position(position); + } + @Override public nullable_int_vector getPointer(long i) { + return new nullable_int_vector((Pointer)this).offsetAddress(i); + } + + public native IntPointer data(); public native nullable_int_vector data(IntPointer setter); + public native @Cast("uint64_t*") LongPointer validityBuffer(); public native nullable_int_vector validityBuffer(LongPointer setter); + public native int count(); public native nullable_int_vector count(int setter); + public int dataSize() { + return count() * 4; + } +} + +public static class nullable_double_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public nullable_double_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public nullable_double_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public nullable_double_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public nullable_double_vector position(long position) { + return (nullable_double_vector)super.position(position); + } + @Override public nullable_double_vector getPointer(long i) { + return new nullable_double_vector((Pointer)this).offsetAddress(i); + } + + public native DoublePointer data(); public native nullable_double_vector data(DoublePointer setter); + public native @Cast("uint64_t*") LongPointer validityBuffer(); public native nullable_double_vector validityBuffer(LongPointer setter); + public native int count(); public native nullable_double_vector count(int setter); + public int dataSize() { + return count() * 8; + } +} + +public static class non_null_double_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public non_null_double_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public non_null_double_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public non_null_double_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public non_null_double_vector position(long position) { + return (non_null_double_vector)super.position(position); + } + @Override public non_null_double_vector getPointer(long i) { + return new non_null_double_vector((Pointer)this).offsetAddress(i); + } + + public native DoublePointer data(); public native non_null_double_vector data(DoublePointer setter); + public native int count(); public native non_null_double_vector count(int setter); + public int dataSize() { + return count() * 8; + } +} + + +public static class nullable_bigint_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public nullable_bigint_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public nullable_bigint_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public nullable_bigint_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public nullable_bigint_vector position(long position) { + return (nullable_bigint_vector)super.position(position); + } + @Override public nullable_bigint_vector getPointer(long i) { + return new nullable_bigint_vector((Pointer)this).offsetAddress(i); + } + + public native @Cast("int64_t*") LongPointer data(); public native nullable_bigint_vector data(LongPointer setter); + public native @Cast("uint64_t*") LongPointer validityBuffer(); public native nullable_bigint_vector validityBuffer(LongPointer setter); + public native int count(); public native nullable_bigint_vector count(int setter); + public int dataSize() { + return count() * 8; + } +} + +public static class non_null_bigint_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public non_null_bigint_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public non_null_bigint_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public non_null_bigint_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public non_null_bigint_vector position(long position) { + return (non_null_bigint_vector)super.position(position); + } + @Override public non_null_bigint_vector getPointer(long i) { + return new non_null_bigint_vector((Pointer)this).offsetAddress(i); + } + + public native @Cast("int64_t*") LongPointer data(); public native non_null_bigint_vector data(LongPointer setter); + public native int count(); public native non_null_bigint_vector count(int setter); + public int dataSize() { + return count() * 8; + } +} + +public static class non_null_int2_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public non_null_int2_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public non_null_int2_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public non_null_int2_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public non_null_int2_vector position(long position) { + return (non_null_int2_vector)super.position(position); + } + @Override public non_null_int2_vector getPointer(long i) { + return new non_null_int2_vector((Pointer)this).offsetAddress(i); + } + + public native ShortPointer data(); public native non_null_int2_vector data(ShortPointer setter); + public native int count(); public native non_null_int2_vector count(int setter); + public int size() { + return count() * 2; + } +} + +public static class non_null_int_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public non_null_int_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public non_null_int_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public non_null_int_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public non_null_int_vector position(long position) { + return (non_null_int_vector)super.position(position); + } + @Override public non_null_int_vector getPointer(long i) { + return new non_null_int_vector((Pointer)this).offsetAddress(i); + } + + public native IntPointer data(); public native non_null_int_vector data(IntPointer setter); + public native int count(); public native non_null_int_vector count(int setter); +} + +public static class non_null_varchar_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public non_null_varchar_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public non_null_varchar_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public non_null_varchar_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public non_null_varchar_vector position(long position) { + return (non_null_varchar_vector)super.position(position); + } + @Override public non_null_varchar_vector getPointer(long i) { + return new non_null_varchar_vector((Pointer)this).offsetAddress(i); + } + + public native @Cast("char*") BytePointer data(); public native non_null_varchar_vector data(BytePointer setter); + public native IntPointer offsets(); public native non_null_varchar_vector offsets(IntPointer setter); + public native int dataSize(); public native non_null_varchar_vector dataSize(int setter); + public native int count(); public native non_null_varchar_vector count(int setter); +} + +public static class nullable_varchar_vector extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public nullable_varchar_vector() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public nullable_varchar_vector(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public nullable_varchar_vector(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public nullable_varchar_vector position(long position) { + return (nullable_varchar_vector)super.position(position); + } + @Override public nullable_varchar_vector getPointer(long i) { + return new nullable_varchar_vector((Pointer)this).offsetAddress(i); + } + + public native @Cast("char*") BytePointer data(); public native nullable_varchar_vector data(BytePointer setter); + public native IntPointer offsets(); public native nullable_varchar_vector offsets(IntPointer setter); + public native @Cast("uint64_t*") LongPointer validityBuffer(); public native nullable_varchar_vector validityBuffer(LongPointer setter); + public native int dataSize(); public native nullable_varchar_vector dataSize(int setter); + public native int count(); public native nullable_varchar_vector count(int setter); +} + +public static class non_null_c_bounded_string extends Pointer { + static { Loader.load(); } + /** Default native constructor. */ + public non_null_c_bounded_string() { super((Pointer)null); allocate(); } + /** Native array allocator. Access with {@link Pointer#position(long)}. */ + public non_null_c_bounded_string(long size) { super((Pointer)null); allocateArray(size); } + /** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */ + public non_null_c_bounded_string(Pointer p) { super(p); } + private native void allocate(); + private native void allocateArray(long size); + @Override public non_null_c_bounded_string position(long position) { + return (non_null_c_bounded_string)super.position(position); + } + @Override public non_null_c_bounded_string getPointer(long i) { + return new non_null_c_bounded_string((Pointer)this).offsetAddress(i); + } + + public native @Cast("char*") BytePointer data(); public native non_null_c_bounded_string data(BytePointer setter); + public native int length(); public native non_null_c_bounded_string length(int setter); +} + +public static final int VE_TD_DEFS = 1; +// #endif + + + +} diff --git a/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java b/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java new file mode 100644 index 000000000..edc157e39 --- /dev/null +++ b/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java @@ -0,0 +1,24 @@ +package com.nec.arrow; + +import org.bytedeco.javacpp.*; +import org.bytedeco.javacpp.annotation.*; +import org.bytedeco.javacpp.tools.*; + +@Properties( + value = @Platform( + include = { +// "words.hpp", +// "char_int_conv.hpp", +// "parsefloat.hpp", + "transfer-definitions.hpp" + } +// link = "jniTransferDefinitions" + ), + target = "com.nec.arrow.TransferDefinitions" +) +public class TransferDefinitionsConfig implements InfoMapper { + public void map(InfoMap infoMap) { + infoMap.put(new Info("std::vector").pointerTypes("StringVector").define()) + .put(new Info("std::vector").pointerTypes("SizeTVector").define()); + } +} diff --git a/src/main/resources/com/nec/cyclone/cpp/transfer-definitions.hpp b/src/main/resources/com/nec/cyclone/cpp/transfer-definitions.hpp index 4bea6a93f..c8053bde3 100644 --- a/src/main/resources/com/nec/cyclone/cpp/transfer-definitions.hpp +++ b/src/main/resources/com/nec/cyclone/cpp/transfer-definitions.hpp @@ -28,12 +28,6 @@ #include #include #include -#include "frovedis/text/dict.hpp" -#include "frovedis/text/words.hpp" -#include "frovedis/text/char_int_conv.hpp" -#include "frovedis/text/parsefloat.hpp" -#include "frovedis/text/parsedatetime.hpp" -#include "frovedis/text/datetime_utility.hpp" #ifndef VE_TD_DEFS typedef struct @@ -64,6 +58,13 @@ typedef struct int32_t count; } nullable_double_vector; +typedef struct +{ + double *data; + int32_t count; +} non_null_double_vector; + + typedef struct { int64_t *data; @@ -71,6 +72,23 @@ typedef struct int32_t count; } nullable_bigint_vector; +typedef struct +{ + int64_t *data; + int32_t count; +} non_null_bigint_vector; + +typedef struct +{ + int16_t *data; + int32_t count; +} non_null_int2_vector; + +typedef struct +{ + int32_t *data; + int32_t count; +} non_null_int_vector; typedef struct { diff --git a/src/main/resources/transferdefinitions/libjniTransferDefinitions.so b/src/main/resources/transferdefinitions/libjniTransferDefinitions.so new file mode 100755 index 0000000000000000000000000000000000000000..a3425635a111826453a323f22c0955d315534928 GIT binary patch literal 129960 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 N#3Ve~L+`mX{tpDKXafKM literal 0 HcmV?d00001 diff --git a/src/main/scala/com/nec/arrow/ArrowInterfaces.scala b/src/main/scala/com/nec/arrow/ArrowInterfaces.scala index 5cfd3dea8..6fb378a79 100644 --- a/src/main/scala/com/nec/arrow/ArrowInterfaces.scala +++ b/src/main/scala/com/nec/arrow/ArrowInterfaces.scala @@ -19,10 +19,14 @@ */ package com.nec.arrow -import com.nec.arrow.ArrowTransferStructures._ +import com.nec.arrow.TransferDefinitions._ import org.apache.arrow.vector._ import org.apache.spark.sql.util.ArrowUtilsExposed import org.bytedeco.javacpp.BytePointer +import org.bytedeco.javacpp.DoublePointer +import org.bytedeco.javacpp.LongPointer +import org.bytedeco.javacpp.IntPointer +import org.bytedeco.javacpp.ShortPointer import sun.misc.Unsafe object ArrowInterfaces { @@ -40,59 +44,56 @@ object ArrowInterfaces { def c_double_vector(float8Vector: Float8Vector): non_null_double_vector = { val vc = new non_null_double_vector() - vc.data = float8Vector.getDataBufferAddress() - - vc.count = float8Vector.getValueCount + .data(new DoublePointer(float8Vector.getDataBuffer().nioBuffer.asDoubleBuffer)) + .count(float8Vector.getValueCount) vc } def c_nullable_double_vector(float8Vector: Float8Vector): nullable_double_vector = { val vc = new nullable_double_vector() - vc.data = float8Vector.getDataBufferAddress() - vc.validityBuffer = float8Vector.getValidityBufferAddress - vc.count = float8Vector.getValueCount + .data(new DoublePointer(float8Vector.getDataBuffer().nioBuffer.asDoubleBuffer)) + .validityBuffer(new LongPointer(float8Vector.getValidityBuffer().nioBuffer.asLongBuffer)) + .count(float8Vector.getValueCount) vc } def c_nullable_varchar_vector(varCharVector: VarCharVector): nullable_varchar_vector = { val vc = new nullable_varchar_vector() - vc.data = varCharVector.getDataBufferAddress() - vc.offsets = varCharVector.getOffsetBufferAddress() - vc.validityBuffer = - varCharVector.getValidityBufferAddress() - vc.count = varCharVector.getValueCount - vc.dataSize = varCharVector.sizeOfValueBuffer() + .data(new BytePointer(varCharVector.getDataBuffer().nioBuffer)) + .offsets(new IntPointer(varCharVector.getOffsetBuffer().nioBuffer.asIntBuffer)) + .validityBuffer(new LongPointer(varCharVector.getValidityBuffer().nioBuffer.asLongBuffer)) + .count(varCharVector.getValueCount) + .dataSize(varCharVector.sizeOfValueBuffer()) vc } def c_bounded_string(string: String): non_null_c_bounded_string = { val vc = new non_null_c_bounded_string() - vc.data = (new BytePointer(string.length)) - .put(string.getBytes(): _*) - .address() - vc.length = string.length + .data((new BytePointer(string.length)) + .put(string.getBytes(): _*)) + .length(string.length) vc } def c_bounded_data(bytePointer: BytePointer, bufSize: Int): non_null_c_bounded_string = { val vc = new non_null_c_bounded_string() - vc.data = bytePointer.address() - vc.length = bufSize + .data(bytePointer) + .length(bufSize) vc } def c_int2_vector(intVector: IntVector): non_null_int2_vector = { val vc = new non_null_int2_vector() - vc.data = intVector.getDataBufferAddress() - vc.count = intVector.getValueCount + .data(new ShortPointer(intVector.getDataBuffer().nioBuffer.asShortBuffer)) + .count(intVector.getValueCount) vc } def c_nullable_int_vector(intVector: IntVector): nullable_int_vector = { val vc = new nullable_int_vector() - vc.data = intVector.getDataBufferAddress() - vc.validityBuffer = intVector.getValidityBufferAddress() - vc.count = intVector.getValueCount + .data(new IntPointer(intVector.getDataBuffer().nioBuffer.asIntBuffer)) + .validityBuffer(new LongPointer(intVector.getValidityBuffer().nioBuffer.asLongBuffer)) + .count(intVector.getValueCount) vc } @@ -105,10 +106,10 @@ object ArrowInterfaces { case idx if (!bitVector.isNull(idx)) => intVector.set(idx, bitVector.get(idx)) case idx => intVector.setNull(idx) } - vc.data = intVector.getDataBufferAddress() - vc.validityBuffer = bitVector.getValidityBufferAddress() - vc.count = bitVector.getValueCount - vc + val newVc = vc.data(new IntPointer(intVector.getDataBuffer().nioBuffer.asIntBuffer)) + .validityBuffer(new LongPointer(bitVector.getValidityBuffer().nioBuffer.asLongBuffer)) + .count(bitVector.getValueCount) + newVc } def c_nullable_int_vector(smallIntVector: SmallIntVector): nullable_int_vector = { @@ -122,36 +123,34 @@ object ArrowInterfaces { intVector.set(idx, smallIntVector.get(idx).toInt) case idx => intVector.setNull(idx) } - vc.data = intVector.getDataBufferAddress() - vc.validityBuffer = - smallIntVector.getValidityBufferAddress() - vc.count = smallIntVector.getValueCount - vc + val newVc = vc.data(new IntPointer(intVector.getDataBuffer().nioBuffer.asIntBuffer)) + .validityBuffer( + new LongPointer(smallIntVector.getValidityBuffer().nioBuffer.asLongBuffer)) + .count(smallIntVector.getValueCount) + newVc } def c_nullable_bigint_vector(tzVector: TimeStampMicroTZVector): nullable_bigint_vector = { val vc = new nullable_bigint_vector() - vc.data = tzVector.getDataBufferAddress() - vc.validityBuffer = tzVector.getValidityBufferAddress() - vc.count = tzVector.getValueCount + .data(new LongPointer(tzVector.getDataBuffer().nioBuffer.asLongBuffer)) + .validityBuffer(new LongPointer(tzVector.getValidityBuffer().nioBuffer.asLongBuffer)) + .count(tzVector.getValueCount) vc } def c_nullable_bigint_vector(bigIntVector: BigIntVector): nullable_bigint_vector = { val vc = new nullable_bigint_vector() - vc.data = bigIntVector.getDataBufferAddress() - vc.validityBuffer = - bigIntVector.getValidityBufferAddress() - vc.count = bigIntVector.getValueCount + .data(new LongPointer(bigIntVector.getDataBuffer().nioBuffer.asLongBuffer)) + .validityBuffer(new LongPointer(bigIntVector.getValidityBuffer().nioBuffer.asLongBuffer)) + .count(bigIntVector.getValueCount) vc } def c_nullable_date_vector(dateDayVector: DateDayVector): nullable_int_vector = { val vc = new nullable_int_vector() - vc.data = dateDayVector.getDataBufferAddress() - vc.validityBuffer = - dateDayVector.getValidityBufferAddress() - vc.count = dateDayVector.getValueCount + .data(new IntPointer(dateDayVector.getDataBuffer().nioBuffer.asIntBuffer)) + .validityBuffer(new LongPointer(dateDayVector.getValidityBuffer().nioBuffer.asLongBuffer)) + .count(dateDayVector.getValueCount) vc } @@ -167,7 +166,7 @@ object ArrowInterfaces { } intVector.setValueCount(input.count) (0 until input.count).foreach(i => BitVectorHelper.setBit(intVector.getValidityBuffer, i)) - getUnsafe.copyMemory(input.data, intVector.getDataBufferAddress, input.count * 4) + getUnsafe.copyMemory(input.data.address, intVector.getDataBufferAddress, input.count * 4) } def non_null_bigint_vector_to_bigintVector( @@ -179,7 +178,7 @@ object ArrowInterfaces { } bigintVector.setValueCount(input.count) (0 until input.count).foreach(i => BitVectorHelper.setBit(bigintVector.getValidityBuffer, i)) - getUnsafe.copyMemory(input.data, bigintVector.getDataBufferAddress, input.dataSize()) + getUnsafe.copyMemory(input.data.address, bigintVector.getDataBufferAddress, input.dataSize()) } def nullable_bigint_vector_to_BigIntVector( @@ -191,11 +190,11 @@ object ArrowInterfaces { } bigintVector.setValueCount(input.count) getUnsafe.copyMemory( - input.validityBuffer, + input.validityBuffer.address, bigintVector.getValidityBufferAddress, Math.ceil(input.count / 64.0).toInt * 8 ) - getUnsafe.copyMemory(input.data, bigintVector.getDataBufferAddress, input.dataSize()) + getUnsafe.copyMemory(input.data.address, bigintVector.getDataBufferAddress, input.dataSize()) } def non_null_double_vector_to_float8Vector( @@ -210,7 +209,7 @@ object ArrowInterfaces { } float8Vector.setValueCount(input.count) (0 until input.count).foreach(i => BitVectorHelper.setBit(float8Vector.getValidityBuffer, i)) - getUnsafe.copyMemory(input.data, float8Vector.getDataBufferAddress, input.dataSize()) + getUnsafe.copyMemory(input.data.address, float8Vector.getDataBufferAddress, input.dataSize()) } def nullable_double_vector_to_float8Vector( @@ -225,11 +224,11 @@ object ArrowInterfaces { } float8Vector.setValueCount(input.count) getUnsafe.copyMemory( - input.validityBuffer, + input.validityBuffer.address, float8Vector.getValidityBufferAddress, Math.ceil(input.count / 64.0).toInt * 8 ) - getUnsafe.copyMemory(input.data, float8Vector.getDataBufferAddress, input.dataSize()) + getUnsafe.copyMemory(input.data.address, float8Vector.getDataBufferAddress, input.dataSize()) } def non_null_int2_vector_to_IntVector(input: non_null_int2_vector, intVector: IntVector): Unit = { @@ -238,7 +237,7 @@ object ArrowInterfaces { } intVector.setValueCount(input.count) (0 until input.count).foreach(i => BitVectorHelper.setBit(intVector.getValidityBuffer, i)) - getUnsafe.copyMemory(input.data, intVector.getDataBufferAddress, input.size()) + getUnsafe.copyMemory(input.data.address, intVector.getDataBufferAddress, input.size()) } def nullable_int_vector_to_IntVector(input: nullable_int_vector, intVector: IntVector): Unit = { @@ -250,11 +249,11 @@ object ArrowInterfaces { } intVector.setValueCount(input.count) getUnsafe.copyMemory( - input.validityBuffer, + input.validityBuffer.address, intVector.getValidityBufferAddress, Math.ceil(input.count / 64.0).toInt * 8 ) - getUnsafe.copyMemory(input.data, intVector.getDataBufferAddress, input.dataSize()) + getUnsafe.copyMemory(input.data.address, intVector.getDataBufferAddress, input.dataSize()) } def nullable_int_vector_to_SmallIntVector( @@ -285,12 +284,12 @@ object ArrowInterfaces { varCharVector.allocateNew(input.dataSize.toLong, input.count) varCharVector.setValueCount(input.count) getUnsafe.copyMemory( - input.validityBuffer, + input.validityBuffer.address, varCharVector.getValidityBufferAddress, Math.ceil(input.count / 64.0).toInt * 8 ) - getUnsafe.copyMemory(input.data, varCharVector.getDataBufferAddress, input.dataSize.toLong) - getUnsafe.copyMemory(input.offsets, varCharVector.getOffsetBufferAddress, 4 * (input.count + 1)) + getUnsafe.copyMemory(input.data.address, varCharVector.getDataBufferAddress, input.dataSize.toLong) + getUnsafe.copyMemory(input.offsets.address, varCharVector.getOffsetBufferAddress, 4 * (input.count + 1)) } def nullable_int_vector_to_BitVector(input: nullable_int_vector, bitVector: BitVector): Unit = { @@ -319,10 +318,10 @@ object ArrowInterfaces { } timeStampVector.setValueCount(input.count) getUnsafe.copyMemory( - input.validityBuffer, + input.validityBuffer.address, timeStampVector.getValidityBufferAddress, Math.ceil(input.count / 64.0).toInt * 8 ) - getUnsafe.copyMemory(input.data, timeStampVector.getDataBufferAddress, input.dataSize()) + getUnsafe.copyMemory(input.data.address, timeStampVector.getDataBufferAddress, input.dataSize()) } } diff --git a/src/main/scala/com/nec/arrow/CArrowNativeInterface.scala b/src/main/scala/com/nec/arrow/CArrowNativeInterface.scala index 50da3436d..4336d3308 100644 --- a/src/main/scala/com/nec/arrow/CArrowNativeInterface.scala +++ b/src/main/scala/com/nec/arrow/CArrowNativeInterface.scala @@ -20,7 +20,7 @@ package com.nec.arrow import com.nec.arrow.ArrowInterfaces.c_bounded_data -import com.nec.arrow.ArrowTransferStructures._ +import com.nec.arrow.TransferDefinitions._ import com.nec.arrow.ArrowInterfaces._ import com.nec.arrow.ArrowNativeInterface.NativeArgument.VectorInputNativeArgument.InputVectorWrapper.{ BigIntVectorInputWrapper, diff --git a/src/main/scala/com/nec/arrow/VeArrowTransfers.scala b/src/main/scala/com/nec/arrow/VeArrowTransfers.scala index 208c40da4..3c77e8340 100644 --- a/src/main/scala/com/nec/arrow/VeArrowTransfers.scala +++ b/src/main/scala/com/nec/arrow/VeArrowTransfers.scala @@ -42,7 +42,7 @@ import com.nec.arrow.ArrowNativeInterface.NativeArgument.VectorOutputNativeArgum TimeStampVectorOutputWrapper, VarCharVectorOutputWrapper } -import com.nec.arrow.ArrowTransferStructures._ +import com.nec.arrow.TransferDefinitions._ import com.nec.arrow.VeArrowNativeInterface.{copyPointerToVe, requireOk, requirePositive, Cleanup} import com.typesafe.scalalogging.LazyLogging import org.apache.arrow.vector._ @@ -50,6 +50,10 @@ import org.apache.arrow.vector._ import scala.collection.mutable import org.apache.spark.sql.util.ArrowUtilsExposed import org.bytedeco.javacpp.BytePointer +import org.bytedeco.javacpp.DoublePointer +import org.bytedeco.javacpp.LongPointer +import org.bytedeco.javacpp.IntPointer +import org.bytedeco.javacpp.ShortPointer import org.bytedeco.veoffload.global.veo import org.bytedeco.veoffload.veo_args import org.bytedeco.veoffload.veo_proc_handle @@ -245,9 +249,9 @@ object VeArrowTransfers extends LazyLogging { val keyName = "double_" + float8Vector.getName + "_" + float8Vector.getDataBuffer.capacity() logger.debug(s"Copying Buffer to VE for $keyName") val vcvr = new nullable_double_vector() - vcvr.count = float8Vector.getValueCount - vcvr.data = copyPointerToVe(proc, new BytePointer(float8Vector.getDataBuffer.nioBuffer()))(cleanup) - vcvr.validityBuffer = copyPointerToVe(proc, new BytePointer(float8Vector.getValidityBuffer.nioBuffer()))(cleanup) + .count(float8Vector.getValueCount) + .data(new DoublePointer(copyPointerToVe(proc, new BytePointer(float8Vector.getDataBuffer.nioBuffer()))(cleanup))) + .validityBuffer(new LongPointer(copyPointerToVe(proc, new BytePointer(float8Vector.getValidityBuffer.nioBuffer()))(cleanup))) vcvr } @@ -257,10 +261,10 @@ object VeArrowTransfers extends LazyLogging { ): non_null_c_bounded_string = { val vc = new non_null_c_bounded_string() val thePtr = new BytePointer(string.getBytes():_*) - thePtr.position(0) - vc.length = string.length - vc.data = copyPointerToVe(proc, thePtr) + vc + .length(string.length) + .data(new BytePointer(copyPointerToVe(proc, thePtr))) } private def make_veo_string_of_bytePointer( @@ -268,10 +272,10 @@ object VeArrowTransfers extends LazyLogging { bytePointer: BytePointer, size: Int )(implicit cleanup: Cleanup): non_null_c_bounded_string = { - val vc = new non_null_c_bounded_string() - vc.length = size bytePointer.position(0) - vc.data = copyPointerToVe(proc, bytePointer, Some(size)) + val vc = new non_null_c_bounded_string() + .length(size) + .data(new BytePointer(copyPointerToVe(proc, bytePointer, Some(size)))) vc } @@ -283,9 +287,9 @@ object VeArrowTransfers extends LazyLogging { logger.debug(s"Copying Buffer to VE for $keyName") val vcvr = new nullable_int_vector() - vcvr.count = intVector.getValueCount - vcvr.data = copyPointerToVe(proc, new BytePointer(intVector.getDataBuffer.nioBuffer()))(cleanup) - vcvr.validityBuffer = copyPointerToVe(proc, new BytePointer(intVector.getValidityBuffer.nioBuffer()))(cleanup) + .count(intVector.getValueCount) + .data(new IntPointer(copyPointerToVe(proc, new BytePointer(intVector.getDataBuffer.nioBuffer()))(cleanup))) + .validityBuffer(new LongPointer(copyPointerToVe(proc, new BytePointer(intVector.getValidityBuffer.nioBuffer()))(cleanup))) vcvr } @@ -306,9 +310,9 @@ object VeArrowTransfers extends LazyLogging { logger.debug(s"Copying Buffer to VE for $keyName") val vcvr = new nullable_int_vector() - vcvr.count = intVector.getValueCount - vcvr.data = copyPointerToVe(proc, new BytePointer(intVector.getDataBuffer.nioBuffer()))(cleanup) - vcvr.validityBuffer = copyPointerToVe(proc, new BytePointer(intVector.getValidityBuffer.nioBuffer()))(cleanup) + .count(intVector.getValueCount) + .data(new IntPointer(copyPointerToVe(proc, new BytePointer(intVector.getDataBuffer.nioBuffer()))(cleanup))) + .validityBuffer(new LongPointer(copyPointerToVe(proc, new BytePointer(intVector.getValidityBuffer.nioBuffer()))(cleanup))) vcvr } @@ -328,9 +332,9 @@ object VeArrowTransfers extends LazyLogging { logger.debug(s"Copying Buffer to VE for $keyName") val vcvr = new nullable_int_vector() - vcvr.count = intVector.getValueCount - vcvr.data = copyPointerToVe(proc, new BytePointer(intVector.getDataBuffer.nioBuffer()))(cleanup) - vcvr.validityBuffer = copyPointerToVe(proc, new BytePointer(intVector.getValidityBuffer.nioBuffer()))(cleanup) + .count(intVector.getValueCount) + .data(new IntPointer(copyPointerToVe(proc, new BytePointer(intVector.getDataBuffer.nioBuffer()))(cleanup))) + .validityBuffer(new LongPointer(copyPointerToVe(proc, new BytePointer(intVector.getValidityBuffer.nioBuffer()))(cleanup))) vcvr } @@ -343,9 +347,9 @@ object VeArrowTransfers extends LazyLogging { logger.debug(s"Copying Buffer to VE for $keyName") val vcvr = new nullable_int_vector() - vcvr.count = dateDayVector.getValueCount - vcvr.data = copyPointerToVe(proc, new BytePointer(dateDayVector.getDataBuffer.nioBuffer()))(cleanup) - vcvr.validityBuffer = copyPointerToVe(proc, new BytePointer(dateDayVector.getValidityBuffer.nioBuffer()))(cleanup) + .count(dateDayVector.getValueCount) + .data(new IntPointer(copyPointerToVe(proc, new BytePointer(dateDayVector.getDataBuffer.nioBuffer()))(cleanup))) + .validityBuffer(new LongPointer(copyPointerToVe(proc, new BytePointer(dateDayVector.getValidityBuffer.nioBuffer()))(cleanup))) vcvr } @@ -359,18 +363,18 @@ object VeArrowTransfers extends LazyLogging { logger.debug(s"Copying Buffer to VE for $keyName") val vcvr = new nullable_varchar_vector() - vcvr.count = varcharVector.getValueCount - vcvr.dataSize = varcharVector.getDataBuffer.capacity().toInt - vcvr.data = copyPointerToVe( + .count(varcharVector.getValueCount) + .dataSize(varcharVector.getDataBuffer.capacity().toInt) + .data(new BytePointer(copyPointerToVe( proc = proc, bytePointer = new BytePointer(varcharVector.getDataBuffer.nioBuffer()), len = Some(varcharVector.getDataBuffer.capacity()) - )(cleanup) - vcvr.offsets = copyPointerToVe( + )(cleanup))) + .offsets(new IntPointer(copyPointerToVe( proc, new BytePointer(varcharVector.getOffsetBuffer.nioBuffer()), len = Some(varcharVector.getOffsetBuffer.capacity()) - )(cleanup) + )(cleanup))) vcvr } @@ -382,9 +386,9 @@ object VeArrowTransfers extends LazyLogging { logger.debug(s"Copying Buffer to VE for $keyName") val vcvr = new nullable_bigint_vector() - vcvr.count = bigintVector.getValueCount - vcvr.data = copyPointerToVe(proc, new BytePointer(bigintVector.getDataBuffer.nioBuffer()))(cleanup) - vcvr.validityBuffer = copyPointerToVe(proc, new BytePointer(bigintVector.getValidityBuffer.nioBuffer()))(cleanup) + .count(bigintVector.getValueCount) + .data(new LongPointer(copyPointerToVe(proc, new BytePointer(bigintVector.getDataBuffer.nioBuffer()))(cleanup))) + .validityBuffer(new LongPointer(copyPointerToVe(proc, new BytePointer(bigintVector.getValidityBuffer.nioBuffer()))(cleanup))) vcvr } @@ -397,9 +401,9 @@ object VeArrowTransfers extends LazyLogging { logger.debug(s"Copying Buffer to VE for $keyName") val vcvr = new nullable_bigint_vector() - vcvr.count = tsVector.getValueCount - vcvr.data = copyPointerToVe(proc, new BytePointer(tsVector.getDataBuffer.nioBuffer()))(cleanup) - vcvr.validityBuffer = copyPointerToVe(proc, new BytePointer(tsVector.getValidityBuffer.nioBuffer()))(cleanup) + .count(tsVector.getValueCount) + .data(new LongPointer(copyPointerToVe(proc, new BytePointer(tsVector.getDataBuffer.nioBuffer()))(cleanup))) + .validityBuffer(new LongPointer(copyPointerToVe(proc, new BytePointer(tsVector.getValidityBuffer.nioBuffer()))(cleanup))) vcvr } @@ -420,8 +424,8 @@ object VeArrowTransfers extends LazyLogging { val dataSize = dataCount * 8 val vhTargetPointer = (new BytePointer(dataSize)) requireOk(veo.veo_read_mem(proc, vhTargetPointer, veoPtr, dataSize)) - vec.count = dataCount - vec.data = vhTargetPointer.address() + val newVec = vec.count(dataCount) + .data(new DoublePointer(vhTargetPointer)) cleanup.add(veoPtr, dataSize) } @@ -450,9 +454,9 @@ object VeArrowTransfers extends LazyLogging { dataCount ) } - vec.count = dataCount - vec.data = vhTargetPointer.address() - vec.validityBuffer = validityTargetPointer.address() + val newVec = vec.count(dataCount) + .data(new DoublePointer(vhTargetPointer)) + .validityBuffer(new LongPointer(validityTargetPointer)) cleanup.add(veoPtr, dataSize) cleanup.add(validityPtr, dataCount) @@ -483,9 +487,9 @@ object VeArrowTransfers extends LazyLogging { ) } - vec.count = dataCount - vec.data = vhTargetPointer.address() - vec.validityBuffer = vhValidityTargetPointer.address() + val newVec = vec.count(dataCount) + .data(new IntPointer(vhTargetPointer)) + .validityBuffer(new LongPointer(vhValidityTargetPointer)) cleanup.add(veoPtr, dataSize) cleanup.add(validityPtr, dataSize) @@ -505,8 +509,8 @@ object VeArrowTransfers extends LazyLogging { val dataSize = dataCount * 8 val vhTargetPointer = (new BytePointer(dataSize)) requireOk(veo.veo_read_mem(proc, vhTargetPointer, veoPtr, dataSize)) - vec.count = dataCount - vec.data = vhTargetPointer.address() + val newVec = vec.count(dataCount) + .data(new LongPointer(vhTargetPointer)) cleanup.add(veoPtr, dataSize) } @@ -540,9 +544,9 @@ object VeArrowTransfers extends LazyLogging { dataCount ) } - vec.count = dataCount - vec.data = vhTargetPointer.address() - vec.validityBuffer = validityTargetPointer.address() + val newVec = vec.count(dataCount) + .data(new LongPointer(vhTargetPointer)) + .validityBuffer(new LongPointer(validityTargetPointer)) cleanup.add(veoPtr, dataSize) cleanup.add(validityPtr, dataSize) @@ -556,11 +560,10 @@ object VeArrowTransfers extends LazyLogging { /** Get data size */ val dataSize = bytePointer.getInt(24) - vec.dataSize = dataSize - - /** Get data count */ val dataCount = bytePointer.getInt(28) - vec.count = dataCount + + val newVec = vec.dataSize(dataSize) + .count(dataCount) if (dataCount < 1) { // no data, do nothing @@ -575,7 +578,7 @@ object VeArrowTransfers extends LazyLogging { veo .veo_read_mem(proc, vhTargetDataPointer, dataPtr, dataSize) } - vec.data = vhTargetDataPointer.address() + val newVec2 = newVec.data(new BytePointer(vhTargetDataPointer)) cleanup.add(dataPtr, dataSize) /** Transfer the offsets */ @@ -591,7 +594,7 @@ object VeArrowTransfers extends LazyLogging { (dataCount + 1) * 4 ) } - vec.offsets = vhTargetOffsetsPointer.address() + val newVec3 = newVec2.offsets(new IntPointer(vhTargetOffsetsPointer)) cleanup.add(offsetsPtr, (dataCount + 1) * 4) /** Transfer the validity buffer */ @@ -607,58 +610,58 @@ object VeArrowTransfers extends LazyLogging { Math.ceil(vec.count / 64.0).toInt * 8 ) } - vec.validityBuffer = vhValidityPointer.address() + val newVec4 = newVec3.validityBuffer(new LongPointer(vhValidityPointer)) cleanup.add(validityPtr, Math.ceil(vec.count / 64.0).toInt * 8) } def stringToBytePointer(str_buf: non_null_c_bounded_string): BytePointer = { - val v_bb = str_buf.getPointer.getByteBuffer(0, 12) - v_bb.putLong(0, str_buf.data) + val v_bb = str_buf.asByteBuffer + v_bb.putLong(0, str_buf.data.address) v_bb.putInt(8, str_buf.length) new BytePointer(v_bb) } def nullableDoubleVectorToBytePointer(double_vector: nullable_double_vector): BytePointer = { - val v_bb = double_vector.getPointer.getByteBuffer(0, 20) - v_bb.putLong(0, double_vector.data) - v_bb.putLong(8, double_vector.validityBuffer) + val v_bb = double_vector.asByteBuffer + v_bb.putLong(0, double_vector.data.address) + v_bb.putLong(8, double_vector.validityBuffer.address) v_bb.putInt(16, double_vector.count) new BytePointer(v_bb) } def nullableBigintVectorToBytePointer(bigint_vector: nullable_bigint_vector): BytePointer = { - val v_bb = bigint_vector.getPointer.getByteBuffer(0, 20) - v_bb.putLong(0, bigint_vector.data) - v_bb.putLong(8, bigint_vector.validityBuffer) + val v_bb = bigint_vector.asByteBuffer + v_bb.putLong(0, bigint_vector.data.address) + v_bb.putLong(8, bigint_vector.validityBuffer.address) v_bb.putInt(16, bigint_vector.count) new BytePointer(v_bb) } def nullableIntVectorToBytePointer(int_vector: nullable_int_vector): BytePointer = { - val v_bb = int_vector.getPointer.getByteBuffer(0, 20) - v_bb.putLong(0, int_vector.data) - v_bb.putLong(8, int_vector.validityBuffer) + val v_bb = int_vector.asByteBuffer + v_bb.putLong(0, int_vector.data.address) + v_bb.putLong(8, int_vector.validityBuffer.address) v_bb.putInt(16, int_vector.count) new BytePointer(v_bb) } def nonNullDoubleVectorToBytePointer(double_vector: non_null_double_vector): BytePointer = { - val v_bb = double_vector.getPointer.getByteBuffer(0, 12) - v_bb.putLong(0, double_vector.data) + val v_bb = double_vector.asByteBuffer + v_bb.putLong(0, double_vector.data.address) v_bb.putInt(8, double_vector.count) new BytePointer(v_bb) } def nonNullInt2VectorToBytePointer(int_vector: non_null_int2_vector): BytePointer = { - val v_bb = int_vector.getPointer.getByteBuffer(0, 12) - v_bb.putLong(0, int_vector.data) + val v_bb = int_vector.asByteBuffer + v_bb.putLong(0, int_vector.data.address) v_bb.putInt(8, int_vector.count) new BytePointer(v_bb) } def nonNullBigIntVectorToBytePointer(bigint_vector: non_null_bigint_vector): BytePointer = { - val v_bb = bigint_vector.getPointer.getByteBuffer(0, 12) - v_bb.putLong(0, bigint_vector.data) + val v_bb = bigint_vector.asByteBuffer + v_bb.putLong(0, bigint_vector.data.address) v_bb.putInt(8, bigint_vector.count) new BytePointer(v_bb) } @@ -666,12 +669,12 @@ object VeArrowTransfers extends LazyLogging { def nullableVarCharVectorVectorToBytePointer( varchar_vector: nullable_varchar_vector ): BytePointer = { - val v_bb = varchar_vector.getPointer.getByteBuffer(0, 32) - v_bb.putLong(0, varchar_vector.data) - v_bb.putLong(8, varchar_vector.offsets) - v_bb.putLong(16, varchar_vector.validityBuffer) + val v_bb = varchar_vector.asByteBuffer + v_bb.putLong(0, varchar_vector.data.address) + v_bb.putLong(8, varchar_vector.offsets.address) + v_bb.putLong(16, varchar_vector.validityBuffer.address) v_bb.putInt(24, varchar_vector.dataSize) v_bb.putInt(28, varchar_vector.count) new BytePointer(v_bb) - } + } } diff --git a/src/main/scala/com/nec/ve/colvector/VeColVector.scala b/src/main/scala/com/nec/ve/colvector/VeColVector.scala index 26ded0b67..fcc9c8416 100644 --- a/src/main/scala/com/nec/ve/colvector/VeColVector.scala +++ b/src/main/scala/com/nec/ve/colvector/VeColVector.scala @@ -1,6 +1,6 @@ package com.nec.ve.colvector -import com.nec.arrow.ArrowTransferStructures.{ +import com.nec.arrow.TransferDefinitions.{ nullable_bigint_vector, nullable_double_vector, nullable_int_vector, @@ -28,7 +28,11 @@ import com.nec.ve.colvector.VeColVector.getUnsafe import org.apache.arrow.memory.BufferAllocator import org.apache.arrow.vector._ import org.apache.spark.sql.vectorized.ColumnVector +import org.bytedeco.javacpp.Pointer import org.bytedeco.javacpp.BytePointer +import org.bytedeco.javacpp.DoublePointer +import org.bytedeco.javacpp.LongPointer +import org.bytedeco.javacpp.IntPointer import sun.misc.Unsafe final case class VeColVector(underlying: GenericColVector[Long]) { @@ -85,6 +89,34 @@ final case class VeColVector(underlying: GenericColVector[Long]) { ) ) + class UnsafeBytePointer extends BytePointer + { + def setAddress(to: Long): Unit = { + address = to + } + } + + class UnsafeDoublePointer extends DoublePointer + { + def setAddress(to: Long): Unit = { + address = to + } + } + + class UnsafeIntPointer extends IntPointer + { + def setAddress(to: Long): Unit = { + address = to + } + } + + class UnsafeLongPointer extends LongPointer + { + def setAddress(to: Long): Unit = { + address = to + } + } + def newContainer()(implicit veProcess: VeProcess, source: VeColVectorSource, @@ -93,37 +125,56 @@ final case class VeColVector(underlying: GenericColVector[Long]) { copy(underlying = { veType match { case VeScalarType.VeNullableDouble => + val ptr = (new UnsafeDoublePointer()) + ptr.setAddress(buffers(0)) + val validityPtr = (new UnsafeLongPointer()) + validityPtr.setAddress(buffers(1)) val vcvr = new nullable_double_vector() - vcvr.count = numItems - vcvr.data = buffers(0) - vcvr.validityBuffer = buffers(1) + .count(numItems) + .data(ptr) + .validityBuffer(validityPtr) val bytePointer = nullableDoubleVectorToBytePointer(vcvr) underlying.copy(container = veProcess.putPointer(bytePointer)) case VeScalarType.VeNullableInt => + val ptr = (new UnsafeIntPointer()) + ptr.setAddress(buffers(0)) + val validityPtr = (new UnsafeLongPointer()) + validityPtr.setAddress(buffers(1)) val vcvr = new nullable_int_vector() - vcvr.count = numItems - vcvr.data = buffers(0) - vcvr.validityBuffer = buffers(1) + .count(numItems) + .data(ptr) + .validityBuffer(validityPtr) val bytePointer = nullableIntVectorToBytePointer(vcvr) underlying.copy(container = veProcess.putPointer(bytePointer)) case VeScalarType.VeNullableLong => + val ptr = (new UnsafeLongPointer()) + ptr.setAddress(buffers(0)) + val validityPtr = (new UnsafeLongPointer()) + validityPtr.setAddress(buffers(1)) val vcvr = new nullable_bigint_vector() - vcvr.count = numItems - vcvr.data = buffers(0) - vcvr.validityBuffer = buffers(1) + .count(numItems) + .data(ptr) + .validityBuffer(validityPtr) val bytePointer = nullableBigintVectorToBytePointer(vcvr) underlying.copy(container = veProcess.putPointer(bytePointer)) case VeString => + val ptr = (new UnsafeBytePointer()) + ptr.setAddress(buffers(0)) + val offsetsPtr = (new UnsafeIntPointer()) + offsetsPtr.setAddress(buffers(1)) + val validityPtr = (new UnsafeLongPointer()) + validityPtr.setAddress(buffers(2)) + val vcvr = new nullable_varchar_vector() - vcvr.count = numItems - vcvr.data = buffers(0) - vcvr.offsets = buffers(1) - vcvr.validityBuffer = buffers(2) - vcvr.dataSize = - variableSize.getOrElse(sys.error("Invalid state - VeString has no variableSize")) + .count(numItems) + .data(ptr) + .offsets(offsetsPtr) + .validityBuffer(validityPtr) + .dataSize( + variableSize.getOrElse(sys.error("Invalid state - VeString has no variableSize"))) val bytePointer = nullableVarCharVectorVectorToBytePointer(vcvr) underlying.copy(container = veProcess.putPointer(bytePointer)) diff --git a/src/test/scala/com/nec/arrow/ArrowInterfacesTest.scala b/src/test/scala/com/nec/arrow/ArrowInterfacesTest.scala index 027c70616..92189965b 100644 --- a/src/test/scala/com/nec/arrow/ArrowInterfacesTest.scala +++ b/src/test/scala/com/nec/arrow/ArrowInterfacesTest.scala @@ -19,7 +19,7 @@ */ package com.nec.arrow import com.nec.arrow.ArrowInterfaces.non_null_double_vector_to_float8Vector -import com.nec.arrow.ArrowTransferStructures.non_null_double_vector +import com.nec.arrow.TransferDefinitions.non_null_double_vector import com.nec.util.RichVectors._ import org.apache.arrow.memory.RootAllocator import org.apache.arrow.vector.Float8Vector @@ -41,11 +41,10 @@ final class ArrowInterfacesTest extends AnyFreeSpec { try { val vector = new Float8Vector("value", alloc) try { - val ndv = new non_null_double_vector - ndv.count = list.size val bp = new DoublePointer(list.toArray:_*) - - ndv.data = bp.address() + val ndv = new non_null_double_vector() + .count(list.size) + .data(bp) non_null_double_vector_to_float8Vector(ndv, vector) assert(vector.toList == list) } finally vector.close() From 24fd7688d2cd37f6992b71a2791cc66eaa4a94de Mon Sep 17 00:00:00 2001 From: Alex Merritt Date: Fri, 11 Feb 2022 15:08:11 +0900 Subject: [PATCH 3/7] Use sbt-javacpp4s plugin to do JavaCPP generation; Add generated .so path to the VectorEngine ForkOptions --- build.sbt | 20 ++++++++++++++++++- project/plugins.sbt | 1 + .../nec/arrow/TransferDefinitionsConfig.java | 4 ++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index 611a9be69..9cb22bcd8 100644 --- a/build.sbt +++ b/build.sbt @@ -21,6 +21,7 @@ lazy val root = Project(id = "spark-cyclone-sql-plugin", base = file(".")) .configs(VectorEngine) .configs(TPC) .configs(CMake) + .enablePlugins(SbtJavaCPP4S) .settings( version := "0.9.1" ) @@ -44,6 +45,22 @@ lazy val tracing = project reStart / envVars += "LOG_DIR" -> file("tracing-dir").getAbsolutePath ) +gppCompilerPath := "g++" +nativeJavaClassPath := "com.nec.arrow.TransferDefinitions" + +includePath := (baseDirectory in Compile).value / "src/main/resources/com/nec/cyclone/cpp" + +libraryName := "libTransferDefinitions" + +makeLibraryCommands := Seq( + "g++ -std=c++17 -fPIC", + "-I", includePath.value.toString, + currentLibraryMeta.value.option, + "-o", + (libraryDestinationPath.value / s"${libraryName.value}.${currentLibraryMeta.value.extension}").toString, + ((baseDirectory in Compile).value / "src/main/resources/com/nec/cyclone/cpp/cyclone/" / "transfer-definitions.hpp").toString +) + /** * Run with: * @@ -185,7 +202,7 @@ VectorEngine / run / fork := true */ VectorEngine / testGrouping := (VectorEngine / definedTests).value.map { suite => import sbt.Tests._ - Group(suite.name, Seq(suite), SubProcess(ForkOptions())) + Group(suite.name, Seq(suite), SubProcess(ForkOptions(None, None, Vector[java.io.File](), None, Vector("-Djava.library.path=target/libjni"), false, Map[String, String]()))) } /** This generates a file 'java.hprof.txt' in the project root for very simple profiling. * */ @@ -195,6 +212,7 @@ VectorEngine / run / javaOptions ++= { List("-agentlib:hprof=cpu=samples") else Nil } + VectorEngine / sourceDirectory := baseDirectory.value / "src" / "test" VectorEngine / testOptions := Seq(Tests.Filter(veFilter)) diff --git a/project/plugins.sbt b/project/plugins.sbt index 8a1de3d25..696fe46ba 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -5,3 +5,4 @@ addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1") addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.6") addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.0") addSbtPlugin("org.bytedeco" % "sbt-javacpp" % "1.17") +addSbtPlugin("com.github.y-yu" % "sbt-javacpp4s" % "0.1.4") diff --git a/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java b/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java index a9b9e6d0f..bf79cf97e 100644 --- a/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java +++ b/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java @@ -11,9 +11,9 @@ // "words.hpp", // "char_int_conv.hpp", // "parsefloat.hpp", - "transfer-definitions.hpp" + "cyclone/transfer-definitions.hpp" } -// link = "jniTransferDefinitions" +// link = "TransferDefinitions" ), target = "com.nec.arrow.TransferDefinitions" ) From c43a8c4d29bcc603fb040acd5fff5d4dbcf757a4 Mon Sep 17 00:00:00 2001 From: Alex Merritt Date: Wed, 16 Feb 2022 18:54:09 -0500 Subject: [PATCH 4/7] Use named arguments in ForkOptions Can't exclude any because they don't have defaults --- build.sbt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index b1f76494c..27dbe422b 100644 --- a/build.sbt +++ b/build.sbt @@ -203,7 +203,9 @@ VectorEngine / run / fork := true */ VectorEngine / testGrouping := (VectorEngine / definedTests).value.map { suite => import sbt.Tests._ - Group(suite.name, Seq(suite), SubProcess(ForkOptions(None, None, Vector[java.io.File](), None, Vector("-Djava.library.path=target/libjni"), false, Map[String, String]()))) + Group(suite.name, Seq(suite), SubProcess(ForkOptions(runJVMOptions = Vector("-Djava.library.path=target/libjni"), + bootJars=Vector[java.io.File](), javaHome=None, outputStrategy=None, + workingDirectory=None, connectInput=false, envVars = Map[String, String]()))) } /** This generates a file 'java.hprof.txt' in the project root for very simple profiling. * */ From 84497d3d0c7dfc70aab00b63dd51cbab9cdf5ba9 Mon Sep 17 00:00:00 2001 From: Alex Merritt Date: Sun, 20 Feb 2022 14:29:12 -0500 Subject: [PATCH 5/7] Move ArrowInterfacesTest to CMake scope --- .../scala/com/nec/{arrow => cmake}/ArrowInterfacesTest.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/scala/com/nec/{arrow => cmake}/ArrowInterfacesTest.scala (98%) diff --git a/src/test/scala/com/nec/arrow/ArrowInterfacesTest.scala b/src/test/scala/com/nec/cmake/ArrowInterfacesTest.scala similarity index 98% rename from src/test/scala/com/nec/arrow/ArrowInterfacesTest.scala rename to src/test/scala/com/nec/cmake/ArrowInterfacesTest.scala index 92189965b..91c7e6e5a 100644 --- a/src/test/scala/com/nec/arrow/ArrowInterfacesTest.scala +++ b/src/test/scala/com/nec/cmake/ArrowInterfacesTest.scala @@ -17,7 +17,7 @@ * limitations under the License. * */ -package com.nec.arrow +package com.nec.cmake import com.nec.arrow.ArrowInterfaces.non_null_double_vector_to_float8Vector import com.nec.arrow.TransferDefinitions.non_null_double_vector import com.nec.util.RichVectors._ From a33d648bc4463357dd13be42fc0a1a193c0784f6 Mon Sep 17 00:00:00 2001 From: Alex Merritt Date: Sun, 20 Feb 2022 15:03:45 -0500 Subject: [PATCH 6/7] Set ForkOptions for CMake scope --- build.sbt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 27dbe422b..f8557cbec 100644 --- a/build.sbt +++ b/build.sbt @@ -187,7 +187,9 @@ CMake / parallelExecution := true */ CMake / testGrouping := (CMake / definedTests).value.map { suite => import sbt.Tests._ - Group(suite.name, Seq(suite), SubProcess(ForkOptions())) + Group(suite.name, Seq(suite), SubProcess(ForkOptions(runJVMOptions = Vector("-Djava.library.path=target/libjni"), + bootJars=Vector[java.io.File](), javaHome=None, outputStrategy=None, + workingDirectory=None, connectInput=false, envVars = Map[String, String]()))) } /** Vector Engine specific configuration */ From b155e29c206adbe59e77ab266d15469bbae87e9a Mon Sep 17 00:00:00 2001 From: Alex Merritt Date: Sun, 20 Feb 2022 15:10:48 -0500 Subject: [PATCH 7/7] Add template instances via JavaCPP, remove individual struct definitions --- .../nec/arrow/TransferDefinitionsConfig.java | 6 +- .../cpp/cyclone/transfer-definitions.cc | 824 ------------------ .../cpp/cyclone/transfer-definitions.hpp | 149 +--- 3 files changed, 9 insertions(+), 970 deletions(-) delete mode 100644 src/main/resources/com/nec/cyclone/cpp/cyclone/transfer-definitions.cc diff --git a/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java b/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java index bf79cf97e..1cb7dc056 100644 --- a/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java +++ b/src/main/java/com/nec/arrow/TransferDefinitionsConfig.java @@ -20,6 +20,10 @@ public class TransferDefinitionsConfig implements InfoMapper { public void map(InfoMap infoMap) { infoMap.put(new Info("std::vector").pointerTypes("StringVector").define()) - .put(new Info("std::vector").pointerTypes("SizeTVector").define()); + .put(new Info("std::vector").pointerTypes("SizeTVector").define()) + .put(new Info("NullableScalarVec").pointerTypes("NullableScalarVecInt32t")) + .put(new Info("NullableScalarVec").pointerTypes("NullableScalarVecInt64t")) + .put(new Info("NullableScalarVec").pointerTypes("NullableScalarVecFloat")) + .put(new Info("NullableScalarVec").pointerTypes("NullableScalarVecDouble")); } } diff --git a/src/main/resources/com/nec/cyclone/cpp/cyclone/transfer-definitions.cc b/src/main/resources/com/nec/cyclone/cpp/cyclone/transfer-definitions.cc deleted file mode 100644 index 216249de1..000000000 --- a/src/main/resources/com/nec/cyclone/cpp/cyclone/transfer-definitions.cc +++ /dev/null @@ -1,824 +0,0 @@ -/* - * Copyright (c) 2021 Xpress AI. - * - * This file is part of Spark Cyclone. - * See https://github.com/XpressAI/SparkCyclone for further info. - * - * 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. - * - */ -#pragma once - -#include "cyclone/transfer-definitions.hpp" -#include "cyclone/cyclone.hpp" -#include "frovedis/core/utility.hpp" -#include - -inline void nullable_int_vector::set_validity(const size_t idx, - const int32_t validity) { - set_valid_bit(validityBuffer, idx, validity); - } - -inline uint32_t nullable_int_vector::get_validity(const size_t idx) const { - return get_valid_bit(validityBuffer, idx); - } - -nullable_int_vector::nullable_int_vector(const frovedis::words &src) { - // Set count - count = src.lens.size(); - - // Set dataSize - auto total_chars = 0; - for (size_t i = 0; i < src.lens.size(); i++) { - total_chars += src.lens[i]; - } - dataSize = total_chars; - - // Compute last_chars - std::vector last_chars(src.lens.size() + 1); - auto sum = 0; - for (auto i = 0; i < src.lens.size(); i++) { - last_chars[i] = sum; - sum += src.lens[i]; - } - - // Copy chars to data - data = static_cast(malloc(sizeof(int) * total_chars)); - for (auto i = 0; i < count; i++) { - auto pos = last_chars[i]; - auto word_start = src.starts[i]; - auto word_end = word_start + src.lens[i]; - for (int j = word_start; j < word_end; j++) { - data[pos++] = (int)src.chars[j]; - } - } - - // Set the offsets - offsets = static_cast(calloc(sizeof(int32_t) * (src.starts.size() + 1), 1)); - for (auto i = 1; i < src.starts.size() + 1; i++) { - offsets[i] = last_chars[i]; - } - offsets[src.starts.size()] = total_chars; - - // Set the validityBuffer - size_t vcount = frovedis::ceil_div(count, int32_t(64)); - validityBuffer = static_cast(calloc(sizeof(uint64_t) * vcount, 1)); - for (auto i = 0; i < vcount; i++) { - validityBuffer[i] = 0xffffffffffffffff; - } -} - -bool nullable_int_vector::equals(const nullable_int_vector * const other) { - // Compare count - auto output = (count == other->count); - - // Compare data - for (auto i = 0; i < count; i++) { - output = output && (data[i] == other->data[i]); - } - - // Compare validityBuffer - for (auto i = 0; i < count; i++) { - output = output && (check_valid(validityBuffer, i) == check_valid(other->validityBuffer, i)); - } - - return output; -} - -nullable_int_vector * nullable_int_vector::clone() { - // Allocate - auto * output = static_cast(malloc(sizeof(nullable_int_vector))); - - // Copy the count - output->count = count; - - // Copy the data - output->data = static_cast(malloc(output->count*4)); - memcpy(output->data, data, output->count*4); - - // Copy the validity buffer - auto vbytes = frovedis::ceil_div(output->count, int32_t(64)) * sizeof(uint64_t); - output->validityBuffer = static_cast(calloc(vbytes, 1)); - memcpy(output->validityBuffer, validityBuffer, vbytes); - - return output; -} - -nullable_int_vector * nullable_int_vector::from_words(const frovedis::words &src) const { - // Allocate - auto * output = static_cast(malloc(sizeof(nullable_int_vector))); - - // Use placement new to construct nullable_int_vector from frovedis::words - // in the pre-allocated memory - return new (output) nullable_int_vector(src); -} - -frovedis::words nullable_int_vector::to_words() const { - frovedis::words output; - if (count == 0) { - return output; - } - - // Set the lens - output.lens.resize(count); - for (auto i = 0; i < count; i++) { - output.lens[i] = offsets[i + 1] - offsets[i]; - } - - // Set the starts - output.starts.resize(count); - for (int i = 0; i < count; i++) { - output.starts[i] = offsets[i]; - } - - // Set the chars - output.chars.resize(offsets[count]); - //FIXME -// frovedis::char_to_int(data, offsets[count], output.chars.data()); - - return output; -} - -nullable_int_vector * nullable_int_vector::filter(const std::vector &matching_ids) const { - // Get the frovedis::words representation of the input - auto input_words = to_words(); - - // Initialize the starts and lens - std::vector starts(matching_ids.size()); - std::vector lens(matching_ids.size()); - - #pragma _NEC vector - for (int g = 0; g < matching_ids.size(); g++) { - // Fetch the original index - int i = matching_ids[g]; - - // Copy the start and len values - starts[g] = input_words.starts[i]; - lens[g] = input_words.lens[i]; - } - - // Use starts, lens, and frovedis::concat_words to generate the frovedis::words - // version of the filtered nullable_int_vector - std::vector new_starts; - std::vector new_chars = frovedis::concat_words( - input_words.chars, - (const std::vector&)(starts), - (const std::vector&)(lens), - "", - (std::vector&)(new_starts) - ); - input_words.chars = new_chars; - input_words.starts = new_starts; - input_words.lens = lens; - - // Map the data from frovedis::words back to nullable_int_vector - auto * output = nullable_int_vector::from_words(input_words); - - // Preserve the validityBuffer across the filter - #pragma _NEC vector - for (int g = 0; g < matching_ids.size(); g++) { - // Fetch the original index - int i = matching_ids[g]; - - // Copy the validity buffer - output->set_validity(g, get_validity(i)); - } - - return output; -} - -nullable_int_vector ** nullable_int_vector::bucket(const std::vector &bucket_counts, - const std::vector &bucket_assignments) const { - // Allocate array of nullable_int_vector pointers - auto ** output = static_cast(malloc(sizeof(nullable_int_vector *) * bucket_counts.size())); - - // Loop over each bucket - for (int b = 0; b < bucket_counts.size(); b++) { - // Generate the list of indexes where the bucket assignment is b - std::vector matching_ids(bucket_counts[b]); - { - // This loop will be vectorized on the VE as vector compress instruction (`vcp`) - size_t pos = 0; - #pragma _NEC vector - for (int i = 0; i < bucket_assignments.size(); i++) { - if (bucket_assignments[i] == b) { - matching_ids[pos++] = i; - } - } - } - - // Create a filtered copy based on the list of indexes - output[b] = this->filter(matching_ids); - } - - return output; -} - -inline void nullable_bigint_vector::set_validity(const size_t idx, - const int32_t validity) { - set_valid_bit(validityBuffer, idx, validity); - } - -inline uint32_t nullable_bigint_vector::get_validity(const size_t idx) const { - return get_valid_bit(validityBuffer, idx); - } - -nullable_bigint_vector::nullable_bigint_vector(const frovedis::words &src) { - // Set count - count = src.lens.size(); - - // Set dataSize - auto total_chars = 0; - for (size_t i = 0; i < src.lens.size(); i++) { - total_chars += src.lens[i]; - } - dataSize = total_chars; - - // Compute last_chars - std::vector last_chars(src.lens.size() + 1); - auto sum = 0; - for (auto i = 0; i < src.lens.size(); i++) { - last_chars[i] = sum; - sum += src.lens[i]; - } - - // Copy chars to data - data = static_cast(malloc(sizeof(int64_t) * total_chars)); - for (auto i = 0; i < count; i++) { - auto pos = last_chars[i]; - auto word_start = src.starts[i]; - auto word_end = word_start + src.lens[i]; - for (int j = word_start; j < word_end; j++) { - data[pos++] = (int64_t)src.chars[j]; - } - } - - // Set the offsets - offsets = static_cast(calloc(sizeof(int32_t) * (src.starts.size() + 1), 1)); - for (auto i = 1; i < src.starts.size() + 1; i++) { - offsets[i] = last_chars[i]; - } - offsets[src.starts.size()] = total_chars; - - // Set the validityBuffer - size_t vcount = frovedis::ceil_div(count, int32_t(64)); - validityBuffer = static_cast(calloc(sizeof(uint64_t) * vcount, 1)); - for (auto i = 0; i < vcount; i++) { - validityBuffer[i] = 0xffffffffffffffff; - } -} - -bool nullable_bigint_vector::equals(const nullable_bigint_vector * const other) { - // Compare count - auto output = (count == other->count); - - // Compare data - for (auto i = 0; i < count; i++) { - output = output && (data[i] == other->data[i]); - } - - // Compare validityBuffer - for (auto i = 0; i < count; i++) { - output = output && (check_valid(validityBuffer, i) == check_valid(other->validityBuffer, i)); - } - - return output; -} - -nullable_bigint_vector * nullable_bigint_vector::clone() { - // Allocate - auto * output = static_cast(malloc(sizeof(nullable_bigint_vector))); - - // Copy the count - output->count = count; - - // Copy the data - output->data = static_cast(malloc(output->count*8)); - memcpy(output->data, data, output->count*8); - - // Copy the validity buffer - auto vbytes = frovedis::ceil_div(output->count, int32_t(64)) * sizeof(uint64_t); - output->validityBuffer = static_cast(calloc(vbytes, 1)); - memcpy(output->validityBuffer, validityBuffer, vbytes); - - return output; -} - -nullable_bigint_vector * nullable_bigint_vector::from_words(const frovedis::words &src) const { - // Allocate - auto * output = static_cast(malloc(sizeof(nullable_bigint_vector))); - - // Use placement new to construct nullable_bigint_vector from frovedis::words - // in the pre-allocated memory - return new (output) nullable_bigint_vector(src); -} - -frovedis::words nullable_bigint_vector::to_words() const { - frovedis::words output; - if (count == 0) { - return output; - } - - // Set the lens - output.lens.resize(count); - for (auto i = 0; i < count; i++) { - output.lens[i] = offsets[i + 1] - offsets[i]; - } - - // Set the starts - output.starts.resize(count); - for (int i = 0; i < count; i++) { - output.starts[i] = offsets[i]; - } - - // Set the chars - output.chars.resize(offsets[count]); -// frovedis::char_to_int(data, offsets[count], output.chars.data()); - - return output; -} - -nullable_bigint_vector * nullable_bigint_vector::filter(const std::vector &matching_ids) const { - // Get the frovedis::words representation of the input - auto input_words = to_words(); - - // Initialize the starts and lens - std::vector starts(matching_ids.size()); - std::vector lens(matching_ids.size()); - - #pragma _NEC vector - for (int g = 0; g < matching_ids.size(); g++) { - // Fetch the original index - int i = matching_ids[g]; - - // Copy the start and len values - starts[g] = input_words.starts[i]; - lens[g] = input_words.lens[i]; - } - - // Use starts, lens, and frovedis::concat_words to generate the frovedis::words - // version of the filtered nullable_bigint_vector - std::vector new_starts; - std::vector new_chars = frovedis::concat_words( - input_words.chars, - (const std::vector&)(starts), - (const std::vector&)(lens), - "", - (std::vector&)(new_starts) - ); - input_words.chars = new_chars; - input_words.starts = new_starts; - input_words.lens = lens; - - // Map the data from frovedis::words back to nullable_bigint_vector - auto * output = nullable_bigint_vector::from_words(input_words); - - // Preserve the validityBuffer across the filter - #pragma _NEC vector - for (int g = 0; g < matching_ids.size(); g++) { - // Fetch the original index - int i = matching_ids[g]; - - // Copy the validity buffer - output->set_validity(g, get_validity(i)); - } - - return output; -} - -nullable_bigint_vector ** nullable_bigint_vector::bucket(const std::vector &bucket_counts, - const std::vector &bucket_assignments) const { - // Allocate array of nullable_bigint_vector pointers - auto ** output = static_cast(malloc(sizeof(nullable_bigint_vector *) * bucket_counts.size())); - - // Loop over each bucket - for (int b = 0; b < bucket_counts.size(); b++) { - // Generate the list of indexes where the bucket assignment is b - std::vector matching_ids(bucket_counts[b]); - { - // This loop will be vectorized on the VE as vector compress instruction (`vcp`) - size_t pos = 0; - #pragma _NEC vector - for (int i = 0; i < bucket_assignments.size(); i++) { - if (bucket_assignments[i] == b) { - matching_ids[pos++] = i; - } - } - } - - // Create a filtered copy based on the list of indexes - output[b] = this->filter(matching_ids); - } - - return output; -} - -inline void nullable_float_vector::set_validity(const size_t idx, - const int32_t validity) { - set_valid_bit(validityBuffer, idx, validity); - } - -inline uint32_t nullable_float_vector::get_validity(const size_t idx) const { - return get_valid_bit(validityBuffer, idx); - } - -nullable_float_vector::nullable_float_vector(const frovedis::words &src) { - // Set count - count = src.lens.size(); - - // Set dataSize - auto total_chars = 0; - for (size_t i = 0; i < src.lens.size(); i++) { - total_chars += src.lens[i]; - } - dataSize = total_chars; - - // Compute last_chars - std::vector last_chars(src.lens.size() + 1); - auto sum = 0; - for (auto i = 0; i < src.lens.size(); i++) { - last_chars[i] = sum; - sum += src.lens[i]; - } - - // Copy chars to data - data = static_cast(malloc(sizeof(float) * total_chars)); - for (auto i = 0; i < count; i++) { - auto pos = last_chars[i]; - auto word_start = src.starts[i]; - auto word_end = word_start + src.lens[i]; - for (int j = word_start; j < word_end; j++) { - data[pos++] = (float)src.chars[j]; - } - } - - // Set the offsets - offsets = static_cast(calloc(sizeof(int32_t) * (src.starts.size() + 1), 1)); - for (auto i = 1; i < src.starts.size() + 1; i++) { - offsets[i] = last_chars[i]; - } - offsets[src.starts.size()] = total_chars; - - // Set the validityBuffer - size_t vcount = frovedis::ceil_div(count, int32_t(64)); - validityBuffer = static_cast(calloc(sizeof(uint64_t) * vcount, 1)); - for (auto i = 0; i < vcount; i++) { - validityBuffer[i] = 0xffffffffffffffff; - } -} - -bool nullable_float_vector::equals(const nullable_float_vector * const other) { - // Compare count - auto output = (count == other->count); - - // Compare data - for (auto i = 0; i < count; i++) { - output = output && (data[i] == other->data[i]); - } - - // Compare validityBuffer - for (auto i = 0; i < count; i++) { - output = output && (check_valid(validityBuffer, i) == check_valid(other->validityBuffer, i)); - } - - return output; -} - -nullable_float_vector * nullable_float_vector::clone() { - // Allocate - auto * output = static_cast(malloc(sizeof(nullable_float_vector))); - - // Copy the count - output->count = count; - - // Copy the data - output->data = static_cast(malloc(output->count*4)); - memcpy(output->data, data, output->count*4); - - // Copy the validity buffer - auto vbytes = frovedis::ceil_div(output->count, int32_t(64)) * sizeof(uint64_t); - output->validityBuffer = static_cast(calloc(vbytes, 1)); - memcpy(output->validityBuffer, validityBuffer, vbytes); - - return output; -} - -nullable_float_vector * nullable_float_vector::from_words(const frovedis::words &src) const { - // Allocate - auto * output = static_cast(malloc(sizeof(nullable_float_vector))); - - // Use placement new to construct nullable_float_vector from frovedis::words - // in the pre-allocated memory - return new (output) nullable_float_vector(src); -} - -frovedis::words nullable_float_vector::to_words() const { - frovedis::words output; - if (count == 0) { - return output; - } - - // Set the lens - output.lens.resize(count); - for (auto i = 0; i < count; i++) { - output.lens[i] = offsets[i + 1] - offsets[i]; - } - - // Set the starts - output.starts.resize(count); - for (int i = 0; i < count; i++) { - output.starts[i] = offsets[i]; - } - - // Set the chars - output.chars.resize(offsets[count]); - //FIXME -// frovedis::char_to_int(data, offsets[count], output.chars.data()); - - return output; -} - -nullable_float_vector * nullable_float_vector::filter(const std::vector &matching_ids) const { - // Get the frovedis::words representation of the input - auto input_words = to_words(); - - // Initialize the starts and lens - std::vector starts(matching_ids.size()); - std::vector lens(matching_ids.size()); - - #pragma _NEC vector - for (int g = 0; g < matching_ids.size(); g++) { - // Fetch the original index - int i = matching_ids[g]; - - // Copy the start and len values - starts[g] = input_words.starts[i]; - lens[g] = input_words.lens[i]; - } - - // Use starts, lens, and frovedis::concat_words to generate the frovedis::words - // version of the filtered nullable_float_vector - std::vector new_starts; - std::vector new_chars = frovedis::concat_words( - input_words.chars, - (const std::vector&)(starts), - (const std::vector&)(lens), - "", - (std::vector&)(new_starts) - ); - input_words.chars = new_chars; - input_words.starts = new_starts; - input_words.lens = lens; - - // Map the data from frovedis::words back to nullable_float_vector - auto * output = nullable_float_vector::from_words(input_words); - - // Preserve the validityBuffer across the filter - #pragma _NEC vector - for (int g = 0; g < matching_ids.size(); g++) { - // Fetch the original index - int i = matching_ids[g]; - - // Copy the validity buffer - output->set_validity(g, get_validity(i)); - } - - return output; -} - -nullable_float_vector ** nullable_float_vector::bucket(const std::vector &bucket_counts, - const std::vector &bucket_assignments) const { - // Allocate array of nullable_float_vector pointers - auto ** output = static_cast(malloc(sizeof(nullable_float_vector *) * bucket_counts.size())); - - // Loop over each bucket - for (int b = 0; b < bucket_counts.size(); b++) { - // Generate the list of indexes where the bucket assignment is b - std::vector matching_ids(bucket_counts[b]); - { - // This loop will be vectorized on the VE as vector compress instruction (`vcp`) - size_t pos = 0; - #pragma _NEC vector - for (int i = 0; i < bucket_assignments.size(); i++) { - if (bucket_assignments[i] == b) { - matching_ids[pos++] = i; - } - } - } - - // Create a filtered copy based on the list of indexes - output[b] = this->filter(matching_ids); - } - - return output; -} - -inline void nullable_double_vector::set_validity(const size_t idx, - const int32_t validity) { - set_valid_bit(validityBuffer, idx, validity); - } - -inline uint32_t nullable_double_vector::get_validity(const size_t idx) const { - return get_valid_bit(validityBuffer, idx); - } - -nullable_double_vector::nullable_double_vector(const frovedis::words &src) { - // Set count - count = src.lens.size(); - - // Set dataSize - auto total_chars = 0; - for (size_t i = 0; i < src.lens.size(); i++) { - total_chars += src.lens[i]; - } - dataSize = total_chars; - - // Compute last_chars - std::vector last_chars(src.lens.size() + 1); - auto sum = 0; - for (auto i = 0; i < src.lens.size(); i++) { - last_chars[i] = sum; - sum += src.lens[i]; - } - - // Copy chars to data - data = static_cast(malloc(sizeof(double) * total_chars)); - for (auto i = 0; i < count; i++) { - auto pos = last_chars[i]; - auto word_start = src.starts[i]; - auto word_end = word_start + src.lens[i]; - for (int j = word_start; j < word_end; j++) { - data[pos++] = (double)src.chars[j]; - } - } - - // Set the offsets - offsets = static_cast(calloc(sizeof(int32_t) * (src.starts.size() + 1), 1)); - for (auto i = 1; i < src.starts.size() + 1; i++) { - offsets[i] = last_chars[i]; - } - offsets[src.starts.size()] = total_chars; - - // Set the validityBuffer - size_t vcount = frovedis::ceil_div(count, int32_t(64)); - validityBuffer = static_cast(calloc(sizeof(uint64_t) * vcount, 1)); - for (auto i = 0; i < vcount; i++) { - validityBuffer[i] = 0xffffffffffffffff; - } -} - -bool nullable_double_vector::equals(const nullable_double_vector * const other) { - // Compare count - auto output = (count == other->count); - - // Compare data - for (auto i = 0; i < count; i++) { - output = output && (data[i] == other->data[i]); - } - - // Compare validityBuffer - for (auto i = 0; i < count; i++) { - output = output && (check_valid(validityBuffer, i) == check_valid(other->validityBuffer, i)); - } - - return output; -} - -nullable_double_vector * nullable_double_vector::clone() { - // Allocate - auto * output = static_cast(malloc(sizeof(nullable_double_vector))); - - // Copy the count - output->count = count; - - // Copy the data - output->data = static_cast(malloc(output->count*8)); - memcpy(output->data, data, output->count*8); - - // Copy the validity buffer - auto vbytes = frovedis::ceil_div(output->count, int32_t(64)) * sizeof(uint64_t); - output->validityBuffer = static_cast(calloc(vbytes, 1)); - memcpy(output->validityBuffer, validityBuffer, vbytes); - - return output; -} - -nullable_double_vector * nullable_double_vector::from_words(const frovedis::words &src) const { - // Allocate - auto * output = static_cast(malloc(sizeof(nullable_double_vector))); - - // Use placement new to construct nullable_double_vector from frovedis::words - // in the pre-allocated memory - return new (output) nullable_double_vector(src); -} - -frovedis::words nullable_double_vector::to_words() const { - frovedis::words output; - if (count == 0) { - return output; - } - - // Set the lens - output.lens.resize(count); - for (auto i = 0; i < count; i++) { - output.lens[i] = offsets[i + 1] - offsets[i]; - } - - // Set the starts - output.starts.resize(count); - for (int i = 0; i < count; i++) { - output.starts[i] = offsets[i]; - } - - // Set the chars - output.chars.resize(offsets[count]); - //FIXME -// frovedis::char_to_int(data, offsets[count], output.chars.data()); - - return output; -} - -nullable_double_vector * nullable_double_vector::filter(const std::vector &matching_ids) const { - // Get the frovedis::words representation of the input - auto input_words = to_words(); - - // Initialize the starts and lens - std::vector starts(matching_ids.size()); - std::vector lens(matching_ids.size()); - - #pragma _NEC vector - for (int g = 0; g < matching_ids.size(); g++) { - // Fetch the original index - int i = matching_ids[g]; - - // Copy the start and len values - starts[g] = input_words.starts[i]; - lens[g] = input_words.lens[i]; - } - - // Use starts, lens, and frovedis::concat_words to generate the frovedis::words - // version of the filtered nullable_double_vector - std::vector new_starts; - std::vector new_chars = frovedis::concat_words( - input_words.chars, - (const std::vector&)(starts), - (const std::vector&)(lens), - "", - (std::vector&)(new_starts) - ); - input_words.chars = new_chars; - input_words.starts = new_starts; - input_words.lens = lens; - - // Map the data from frovedis::words back to nullable_double_vector - auto * output = nullable_double_vector::from_words(input_words); - - // Preserve the validityBuffer across the filter - #pragma _NEC vector - for (int g = 0; g < matching_ids.size(); g++) { - // Fetch the original index - int i = matching_ids[g]; - - // Copy the validity buffer - output->set_validity(g, get_validity(i)); - } - - return output; -} - -nullable_double_vector ** nullable_double_vector::bucket(const std::vector &bucket_counts, - const std::vector &bucket_assignments) const { - // Allocate array of nullable_double_vector pointers - auto ** output = static_cast(malloc(sizeof(nullable_double_vector *) * bucket_counts.size())); - - // Loop over each bucket - for (int b = 0; b < bucket_counts.size(); b++) { - // Generate the list of indexes where the bucket assignment is b - std::vector matching_ids(bucket_counts[b]); - { - // This loop will be vectorized on the VE as vector compress instruction (`vcp`) - size_t pos = 0; - #pragma _NEC vector - for (int i = 0; i < bucket_assignments.size(); i++) { - if (bucket_assignments[i] == b) { - matching_ids[pos++] = i; - } - } - } - - // Create a filtered copy based on the list of indexes - output[b] = this->filter(matching_ids); - } - - return output; -} diff --git a/src/main/resources/com/nec/cyclone/cpp/cyclone/transfer-definitions.hpp b/src/main/resources/com/nec/cyclone/cpp/cyclone/transfer-definitions.hpp index 2a05ec95e..c86821aca 100644 --- a/src/main/resources/com/nec/cyclone/cpp/cyclone/transfer-definitions.hpp +++ b/src/main/resources/com/nec/cyclone/cpp/cyclone/transfer-definitions.hpp @@ -107,157 +107,16 @@ struct NullableScalarVec { }; // Explicitly instantiate struct template for int32_t -//typedef NullableScalarVec nullable_int_vector; - -struct nullable_int_vector { - // NOTE: Field declaration order must be maintained to match existing JNA bindings - - // Initialize fields with defaults - int32_t *data = nullptr; // The raw data containing all the ints concatenated together - int32_t *offsets = nullptr; // Offsets to denote int start and end positions - uint64_t *validityBuffer = nullptr; // Bit vector to denote null values - int32_t dataSize = 0; // Size of data array - int32_t count = 0; // The row count - - - // Explicitly force the generation of a default constructor - nullable_int_vector() = default; - - // Returns a deep copy of this NullableScalarVec - nullable_int_vector * clone(); - - // Value equality check against another NullableScalarVec - bool equals(const nullable_int_vector * const other); - - inline void set_validity(const size_t idx, - const int32_t validity); - - inline uint32_t get_validity(const size_t idx) const; - - // Construct from a given frovedis::words - nullable_int_vector(const frovedis::words &src); - - nullable_int_vector * filter(const std::vector &matching_ids) const; - - nullable_int_vector ** bucket(const std::vector &bucket_counts, - const std::vector &bucket_assignments) const; - frovedis::words to_words() const; - nullable_int_vector * from_words(const frovedis::words &src) const; -}; +typedef NullableScalarVec nullable_int_vector; // Explicitly instantiate struct template for int64_t -//typedef NullableScalarVec nullable_bigint_vector; - -struct nullable_bigint_vector { - // NOTE: Field declaration order must be maintained to match existing JNA bindings - - // Initialize fields with defaults - int64_t *data = nullptr; // The raw data containing all the bigints concatenated together - int32_t *offsets = nullptr; // Offsets to denote bigint start and end positions - uint64_t *validityBuffer = nullptr; // Bit vector to denote null values - int32_t dataSize = 0; // Size of data array - int32_t count = 0; // The row count - - // Explicitly force the generation of a default constructor - nullable_bigint_vector() = default; - - // Returns a deep copy of this NullableScalarVec - nullable_bigint_vector * clone(); - - // Value equality check against another NullableScalarVec - bool equals(const nullable_bigint_vector * const other); - - inline void set_validity(const size_t idx, - const int32_t validity); - - inline uint32_t get_validity(const size_t idx) const; - - // Construct from a given frovedis::words - nullable_bigint_vector(const frovedis::words &src); - - nullable_bigint_vector * filter(const std::vector &matching_ids) const; - - nullable_bigint_vector ** bucket(const std::vector &bucket_counts, - const std::vector &bucket_assignments) const; - frovedis::words to_words() const; - nullable_bigint_vector * from_words(const frovedis::words &src) const; -}; +typedef NullableScalarVec nullable_bigint_vector; // Explicitly instantiate struct template for float -//typedef NullableScalarVec nullable_float_vector; - -struct nullable_float_vector { - // NOTE: Field declaration order must be maintained to match existing JNA bindings - - // Initialize fields with defaults - float *data = nullptr; // The raw data containing all the floats concatenated together - int32_t *offsets = nullptr; // Offsets to denote float start and end positions - uint64_t *validityBuffer = nullptr; // Bit vector to denote null values - int32_t dataSize = 0; // Size of data array - int32_t count = 0; // The row count - - // Explicitly force the generation of a default constructor - nullable_float_vector() = default; - - // Returns a deep copy of this NullableScalarVec - nullable_float_vector * clone(); - - // Value equality check against another NullableScalarVec - bool equals(const nullable_float_vector * const other); - - inline void set_validity(const size_t idx, - const int32_t validity); - - inline uint32_t get_validity(const size_t idx) const; - - // Construct from a given frovedis::words - nullable_float_vector(const frovedis::words &src); - - nullable_float_vector * filter(const std::vector &matching_ids) const; - - nullable_float_vector ** bucket(const std::vector &bucket_counts, - const std::vector &bucket_assignments) const; - frovedis::words to_words() const; - nullable_float_vector * from_words(const frovedis::words &src) const; -}; +typedef NullableScalarVec nullable_float_vector; // Explicitly instantiate struct template for double -//typedef NullableScalarVec nullable_double_vector; - -struct nullable_double_vector { - // NOTE: Field declaration order must be maintained to match existing JNA bindings - - // Initialize fields with defaults - double *data = nullptr; // The raw data containing all the doubles concatenated together - int32_t *offsets = nullptr; // Offsets to denote double start and end positions - uint64_t *validityBuffer = nullptr; // Bit vector to denote null values - int32_t dataSize = 0; // Size of data array - int32_t count = 0; // The row count - - // Explicitly force the generation of a default constructor - nullable_double_vector() = default; - - // Returns a deep copy of this NullableScalarVec - nullable_double_vector * clone(); - - // Value equality check against another NullableScalarVec - bool equals(const nullable_double_vector * const other); - - inline void set_validity(const size_t idx, - const int32_t validity); - - inline uint32_t get_validity(const size_t idx) const; - - // Construct from a given frovedis::words - nullable_double_vector(const frovedis::words &src); - - nullable_double_vector * filter(const std::vector &matching_ids) const; - - nullable_double_vector ** bucket(const std::vector &bucket_counts, - const std::vector &bucket_assignments) const; - frovedis::words to_words() const; - nullable_double_vector * from_words(const frovedis::words &src) const; -}; +typedef NullableScalarVec nullable_double_vector; struct nullable_varchar_vector { // NOTE: Field declaration order must be maintained to match existing JNA bindings