From 2dfccf5f6c9e6d484487b6d1fb671887a7945cae Mon Sep 17 00:00:00 2001 From: chaokunyang Date: Wed, 3 May 2023 22:39:54 +0800 Subject: [PATCH 1/4] test ci --- java/HEADER | 2 +- .../fury-core/src/main/java/io/fury/Fury.java | 2 +- .../src/test/java/io/fury/FuryTest.java | 3 ++- .../src/main/java/io/fury/format/row/Row.java | 2 +- .../test/java/io/fury/format/row/RowTest.java | 3 ++- .../src/main/java/io/fury/test/bean/Foo.java | 2 +- java/license-format.xml | 13 ++++++++++++ java/pom.xml | 21 +++++++++++++++++-- 8 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 java/license-format.xml diff --git a/java/HEADER b/java/HEADER index 86c5ac4c9f..a0bd93abf8 100644 --- a/java/HEADER +++ b/java/HEADER @@ -1,4 +1,4 @@ -Copyright 2023 FURY. +Copyright ${license.git.copyrightYears} The Fury authors Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. diff --git a/java/fury-core/src/main/java/io/fury/Fury.java b/java/fury-core/src/main/java/io/fury/Fury.java index b65e8f46d1..602b990797 100644 --- a/java/fury-core/src/main/java/io/fury/Fury.java +++ b/java/fury-core/src/main/java/io/fury/Fury.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 FURY. + * Copyright 2023 The Fury authors * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. diff --git a/java/fury-core/src/test/java/io/fury/FuryTest.java b/java/fury-core/src/test/java/io/fury/FuryTest.java index 5ba2cea644..1e18c2b85a 100644 --- a/java/fury-core/src/test/java/io/fury/FuryTest.java +++ b/java/fury-core/src/test/java/io/fury/FuryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 FURY. + * Copyright 2023 The Fury authors * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.fury; public class FuryTest {} diff --git a/java/fury-format/src/main/java/io/fury/format/row/Row.java b/java/fury-format/src/main/java/io/fury/format/row/Row.java index cc906ce76b..bc5aa3a59b 100644 --- a/java/fury-format/src/main/java/io/fury/format/row/Row.java +++ b/java/fury-format/src/main/java/io/fury/format/row/Row.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 FURY. + * Copyright 2023 The Fury authors * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. diff --git a/java/fury-format/src/test/java/io/fury/format/row/RowTest.java b/java/fury-format/src/test/java/io/fury/format/row/RowTest.java index 6bfc625a45..962a71d952 100644 --- a/java/fury-format/src/test/java/io/fury/format/row/RowTest.java +++ b/java/fury-format/src/test/java/io/fury/format/row/RowTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 FURY. + * Copyright 2023 The Fury authors * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.fury.format.row; public class RowTest {} diff --git a/java/fury-test-core/src/main/java/io/fury/test/bean/Foo.java b/java/fury-test-core/src/main/java/io/fury/test/bean/Foo.java index 3aba95695b..d2b450553e 100644 --- a/java/fury-test-core/src/main/java/io/fury/test/bean/Foo.java +++ b/java/fury-test-core/src/main/java/io/fury/test/bean/Foo.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 FURY. + * Copyright 2023 The Fury authors * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. diff --git a/java/license-format.xml b/java/license-format.xml new file mode 100644 index 0000000000..61540bd2f9 --- /dev/null +++ b/java/license-format.xml @@ -0,0 +1,13 @@ + + + + + + + + + false + true + false + + diff --git a/java/pom.xml b/java/pom.xml index fda9367436..7972665fee 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -33,7 +33,7 @@ 5.0.0 2.13.2.20220328 1.13 - 3.0 + 4.2 @@ -233,17 +233,34 @@ + + 2023 + true
HEADER
**/src/main/java/** **/src/test/java/** + + **/util/Platform.java + true + + license-format.xml + - SLASHSTAR_STYLE + SLASHSTART_WITH_BLANKLINE_STYLE
+ + + com.mycila + license-maven-plugin-git + + ${license.maven.plugin} + + From f78321aa0373ebfa06c4f359032eec965896f8ba Mon Sep 17 00:00:00 2001 From: chaokunyang Date: Wed, 3 May 2023 22:53:05 +0800 Subject: [PATCH 2/4] fix ci script --- .github/workflows/java-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/java-ci.yml b/.github/workflows/java-ci.yml index 924a906625..e7d846c3d5 100644 --- a/.github/workflows/java-ci.yml +++ b/.github/workflows/java-ci.yml @@ -21,4 +21,4 @@ jobs: java-version: ${{ matrix.java-version }} distribution: 'temurin' - name: Build with Maven - run: .ci/run_ci.sh java${{ matrix.java-version }} \ No newline at end of file + run: ./ci/run_ci.sh java${{ matrix.java-version }} \ No newline at end of file From 7fda98bb9873ca15230a09eb0e23e636672a3fa8 Mon Sep 17 00:00:00 2001 From: chaokunyang Date: Wed, 3 May 2023 22:56:58 +0800 Subject: [PATCH 3/4] remove fury-benchmark --- ci/run_ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/run_ci.sh b/ci/run_ci.sh index defac9b1fe..610ab9cb2c 100755 --- a/ci/run_ci.sh +++ b/ci/run_ci.sh @@ -46,7 +46,7 @@ case $1 in # check naming and others mvn -T16 checkstyle:check set +e - mvn -T16 test -pl '!fury-format,!fury-testsuite,!fury-benchmark' + mvn -T16 test -pl '!fury-format,!fury-testsuite' testcode=$? if [[ $testcode -ne 0 ]]; then exit $testcode From a521844fd5671e374c87d10e6fd5db3016788a9b Mon Sep 17 00:00:00 2001 From: chaokunyang Date: Wed, 3 May 2023 23:07:57 +0800 Subject: [PATCH 4/4] add unsafe util for fast memory operations --- LICENSE | 7 +- .../src/main/java/io/fury/util/Platform.java | 385 ++++++++++++++++++ .../test/java/io/fury/util/PlatformTest.java | 169 ++++++++ 3 files changed, 560 insertions(+), 1 deletion(-) create mode 100644 java/fury-core/src/main/java/io/fury/util/Platform.java create mode 100644 java/fury-core/src/test/java/io/fury/util/PlatformTest.java diff --git a/LICENSE b/LICENSE index 028803de26..1f3cd813c4 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2023 FURY + Copyright 2023 FURY authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -199,3 +199,8 @@ 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. + + +Apache Software Foundation License 2.0 +-------------------------------------- +java/fury-core/src/main/java/io/fury/util/Platform.java is modified from https://github.com/apache/spark/blob/master/common/unsafe/src/main/java/org/apache/spark/unsafe/Platform.java \ No newline at end of file diff --git a/java/fury-core/src/main/java/io/fury/util/Platform.java b/java/fury-core/src/main/java/io/fury/util/Platform.java new file mode 100644 index 0000000000..7b6c85567c --- /dev/null +++ b/java/fury-core/src/main/java/io/fury/util/Platform.java @@ -0,0 +1,385 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 io.fury.util; + +import com.google.common.base.Preconditions; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import sun.misc.Unsafe; + +/** + * A utility class for unsafe memory operations. Note: This class is based on + * org.apache.spark.unsafe.Platform + */ +@SuppressWarnings("restriction") +public final class Platform { + @SuppressWarnings("restriction") + public static final Unsafe UNSAFE; + + public static final int JAVA_VERSION; + public static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; + + static { + String property = System.getProperty("java.specification.version"); + if (property.startsWith("1.")) { + property = property.substring(2); + } + JAVA_VERSION = Integer.parseInt(property); + } + + public static final int BOOLEAN_ARRAY_OFFSET; + + public static final int BYTE_ARRAY_OFFSET; + + public static final int CHAR_ARRAY_OFFSET; + + public static final int SHORT_ARRAY_OFFSET; + + public static final int INT_ARRAY_OFFSET; + + public static final int LONG_ARRAY_OFFSET; + + public static final int FLOAT_ARRAY_OFFSET; + + public static final int DOUBLE_ARRAY_OFFSET; + + private static final boolean unaligned; + + /** + * Limits the number of bytes to copy per {@link Unsafe#copyMemory(long, long, long)} to allow + * safepoint polling during a large copy. + */ + private static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L; + + static { + Unsafe unsafe; + try { + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + unsafe = (Unsafe) unsafeField.get(null); + } catch (Throwable cause) { + throw new UnsupportedOperationException("Unsafe is not supported in this platform."); + } + UNSAFE = unsafe; + BOOLEAN_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(boolean[].class); + BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); + CHAR_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(char[].class); + SHORT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(short[].class); + INT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class); + LONG_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(long[].class); + FLOAT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(float[].class); + DOUBLE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(double[].class); + } + + // This requires `JAVA_VERSION` and `_UNSAFE`. + static { + boolean unalign; + String arch = System.getProperty("os.arch", ""); + if (arch.equals("ppc64le") || arch.equals("ppc64") || arch.equals("s390x")) { + // Since java.nio.Bits.unaligned() doesn't return true on ppc (See JDK-8165231), but + // ppc64 and ppc64le support it + unalign = true; + } else { + try { + Class bitsClass = + Class.forName("java.nio.Bits", false, ClassLoader.getSystemClassLoader()); + if (JAVA_VERSION >= 9) { + // Java 9/10 and 11/12 have different field names. + Field unalignedField = + bitsClass.getDeclaredField(JAVA_VERSION >= 11 ? "UNALIGNED" : "unaligned"); + unalign = + UNSAFE.getBoolean( + UNSAFE.staticFieldBase(unalignedField), UNSAFE.staticFieldOffset(unalignedField)); + } else { + Method unalignedMethod = bitsClass.getDeclaredMethod("unaligned"); + unalignedMethod.setAccessible(true); + unalign = Boolean.TRUE.equals(unalignedMethod.invoke(null)); + } + } catch (Throwable t) { + // We at least know x86 and x64 support unaligned access. + //noinspection DynamicRegexReplaceableByCompiledPattern + unalign = arch.matches("^(i[3-6]86|x86(_64)?|x64|amd64|aarch64)$"); + } + } + unaligned = unalign; + } + + // Access fields and constructors once and store them, for performance: + + private static final long BUFFER_ADDRESS_FIELD_OFFSET; + private static final long BUFFER_CAPACITY_FIELD_OFFSET; + + static { + try { + Field addressField = Buffer.class.getDeclaredField("address"); + BUFFER_ADDRESS_FIELD_OFFSET = UNSAFE.objectFieldOffset(addressField); + Preconditions.checkArgument(BUFFER_ADDRESS_FIELD_OFFSET != 0); + Field capacityField = Buffer.class.getDeclaredField("capacity"); + BUFFER_CAPACITY_FIELD_OFFSET = UNSAFE.objectFieldOffset(capacityField); + Preconditions.checkArgument(BUFFER_CAPACITY_FIELD_OFFSET != 0); + } catch (NoSuchFieldException e) { + throw new IllegalStateException(e); + } + } + + private static Class getClassByName(@SuppressWarnings("SameParameterValue") String className) { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * Returns true when running JVM is having sun's Unsafe package available in it and underlying + * system having unaligned-access capability. + */ + public static boolean unaligned() { + return unaligned; + } + + public static long objectFieldOffset(Field f) { + return UNSAFE.objectFieldOffset(f); + } + + public static int getInt(Object object, long offset) { + return UNSAFE.getInt(object, offset); + } + + public static void putInt(Object object, long offset, int value) { + UNSAFE.putInt(object, offset, value); + } + + public static boolean getBoolean(Object object, long offset) { + return UNSAFE.getBoolean(object, offset); + } + + public static void putBoolean(Object object, long offset, boolean value) { + UNSAFE.putBoolean(object, offset, value); + } + + public static byte getByte(Object object, long offset) { + return UNSAFE.getByte(object, offset); + } + + public static void putByte(Object object, long offset, byte value) { + UNSAFE.putByte(object, offset, value); + } + + public static short getShort(Object object, long offset) { + return UNSAFE.getShort(object, offset); + } + + public static void putShort(Object object, long offset, short value) { + UNSAFE.putShort(object, offset, value); + } + + public static char getChar(Object obj, long offset) { + return Platform.UNSAFE.getChar(obj, offset); + } + + public static void putChar(Object obj, long offset, char value) { + Platform.UNSAFE.putChar(obj, offset, value); + } + + public static long getLong(Object object, long offset) { + return UNSAFE.getLong(object, offset); + } + + public static void putLong(Object object, long offset, long value) { + UNSAFE.putLong(object, offset, value); + } + + public static float getFloat(Object object, long offset) { + return UNSAFE.getFloat(object, offset); + } + + public static void putFloat(Object object, long offset, float value) { + UNSAFE.putFloat(object, offset, value); + } + + public static double getDouble(Object object, long offset) { + return UNSAFE.getDouble(object, offset); + } + + public static void putDouble(Object object, long offset, double value) { + UNSAFE.putDouble(object, offset, value); + } + + public static Object getObject(Object o, long offset) { + return UNSAFE.getObject(o, offset); + } + + public static void putObject(Object object, long offset, Object value) { + UNSAFE.putObject(object, offset, value); + } + + public static Object getObjectVolatile(Object object, long offset) { + return UNSAFE.getObjectVolatile(object, offset); + } + + public static void putObjectVolatile(Object object, long offset, Object value) { + UNSAFE.putObjectVolatile(object, offset, value); + } + + public static long allocateMemory(long size) { + return UNSAFE.allocateMemory(size); + } + + public static void freeMemory(long address) { + UNSAFE.freeMemory(address); + } + + public static long reallocateMemory(long address, long oldSize, long newSize) { + long newMemory = UNSAFE.allocateMemory(newSize); + copyMemory(null, address, null, newMemory, oldSize); + freeMemory(address); + return newMemory; + } + + public static void setMemory(Object object, long offset, long size, byte value) { + UNSAFE.setMemory(object, offset, size, value); + } + + public static void setMemory(long address, byte value, long size) { + UNSAFE.setMemory(address, size, value); + } + + public static void copyMemory( + Object src, long srcOffset, Object dst, long dstOffset, long length) { + if (length < UNSAFE_COPY_THRESHOLD) { + UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, length); + } else { + while (length > 0) { + long size = Math.min(length, UNSAFE_COPY_THRESHOLD); + UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, size); + length -= size; + srcOffset += size; + dstOffset += size; + } + } + } + + /** + * Optimized byte array equality check for byte arrays. + * + * @return true if the arrays are equal, false otherwise + */ + public static boolean arrayEquals( + Object leftBase, long leftOffset, Object rightBase, long rightOffset, final long length) { + int i = 0; + + // check if stars align and we can get both offsets to be aligned + if ((leftOffset % 8) == (rightOffset % 8)) { + while ((leftOffset + i) % 8 != 0 && i < length) { + if (Platform.getByte(leftBase, leftOffset + i) + != Platform.getByte(rightBase, rightOffset + i)) { + return false; + } + i += 1; + } + } + // for architectures that support unaligned accesses, chew it up 8 bytes at a time + if (unaligned || (((leftOffset + i) % 8 == 0) && ((rightOffset + i) % 8 == 0))) { + while (i <= length - 8) { + if (Platform.getLong(leftBase, leftOffset + i) + != Platform.getLong(rightBase, rightOffset + i)) { + return false; + } + i += 8; + } + } + // this will finish off the unaligned comparisons, or do the entire aligned + // comparison whichever is needed. + while (i < length) { + if (Platform.getByte(leftBase, leftOffset + i) + != Platform.getByte(rightBase, rightOffset + i)) { + return false; + } + i += 1; + } + return true; + } + + /** Raises an exception bypassing compiler checks for checked exceptions. */ + public static void throwException(Throwable t) { + UNSAFE.throwException(t); + } + + /** Create an instance of type. This method don't call constructor. */ + public static T newInstance(Class type) { + try { + return type.cast(UNSAFE.allocateInstance(type)); + } catch (InstantiationException e) { + throwException(e); + } + throw new IllegalStateException("unreachable"); + } + + public static long getAddress(ByteBuffer buffer) { + Preconditions.checkNotNull(buffer, "buffer is null"); + Preconditions.checkArgument(buffer.isDirect(), "Can't get address of a non-direct ByteBuffer."); + long offHeapAddress; + try { + offHeapAddress = UNSAFE.getLong(buffer, BUFFER_ADDRESS_FIELD_OFFSET); + } catch (Throwable t) { + throw new Error("Could not access direct byte buffer address field.", t); + } + return offHeapAddress; + } + + private static final ByteBuffer localBuffer = ByteBuffer.allocateDirect(0); + + /** Create a direct buffer from native memory represented by address [address, address + size). */ + public static ByteBuffer createDirectByteBufferFromNativeAddress(long address, int size) { + try { + // ByteBuffer.allocateDirect(0) is about 30x slower than `localBuffer.duplicate()`. + ByteBuffer buffer = localBuffer.duplicate(); + UNSAFE.putLong(buffer, BUFFER_ADDRESS_FIELD_OFFSET, address); + UNSAFE.putInt(buffer, BUFFER_CAPACITY_FIELD_OFFSET, size); + buffer.clear(); + return buffer; + } catch (Throwable t) { + throw new Error("Failed to wrap unsafe off-heap memory with ByteBuffer", t); + } + } + + /** Wrap a buffer [address, address + size) into provided buffer. */ + public static void wrapDirectByteBufferFromNativeAddress( + ByteBuffer buffer, long address, int size) { + Preconditions.checkArgument( + buffer.isDirect(), "Can't wrap native memory into a non-direct ByteBuffer."); + UNSAFE.putLong(buffer, BUFFER_ADDRESS_FIELD_OFFSET, address); + UNSAFE.putInt(buffer, BUFFER_CAPACITY_FIELD_OFFSET, size); + buffer.clear(); + } + + public static ByteBuffer wrapDirectBuffer(long address, int size) { + return createDirectByteBufferFromNativeAddress(address, size); + } + + /** Wrap a buffer [address, address + size) into provided buffer. */ + public static void wrapDirectBuffer(ByteBuffer buffer, long address, int size) { + UNSAFE.putLong(buffer, BUFFER_ADDRESS_FIELD_OFFSET, address); + UNSAFE.putInt(buffer, BUFFER_CAPACITY_FIELD_OFFSET, size); + buffer.clear(); + } +} diff --git a/java/fury-core/src/test/java/io/fury/util/PlatformTest.java b/java/fury-core/src/test/java/io/fury/util/PlatformTest.java new file mode 100644 index 0000000000..08088270e7 --- /dev/null +++ b/java/fury-core/src/test/java/io/fury/util/PlatformTest.java @@ -0,0 +1,169 @@ +/* + * Copyright 2023 The Fury authors + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 io.fury.util; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +public class PlatformTest { + + private static final Logger LOG = LoggerFactory.getLogger(PlatformTest.class); + + @Test + public void testArrayEquals() { + byte[] bytes = "123456781234567".getBytes(StandardCharsets.UTF_8); + byte[] bytes2 = "123456781234567".getBytes(StandardCharsets.UTF_8); + assert bytes.length == bytes2.length; + assertTrue( + Platform.arrayEquals( + bytes, Platform.BYTE_ARRAY_OFFSET, bytes2, Platform.BYTE_ARRAY_OFFSET, bytes.length)); + } + + @Test(enabled = false) + public void benchmarkArrayEquals() { + byte[] bytes = "123456781234567".getBytes(StandardCharsets.UTF_8); + byte[] bytes2 = "123456781234567".getBytes(StandardCharsets.UTF_8); + arrayEquals(bytes, bytes2); + bytes = "1234567812345678".getBytes(StandardCharsets.UTF_8); + bytes2 = "1234567812345678".getBytes(StandardCharsets.UTF_8); + arrayEquals(bytes, bytes2); + } + + private boolean arrayEquals(byte[] bytes, byte[] bytes2) { + long nums = 200_000_000; + boolean eq = false; + { + // warm + for (int i = 0; i < nums; i++) { + eq = + bytes.length == bytes2.length + && Platform.arrayEquals( + bytes, + Platform.BYTE_ARRAY_OFFSET, + bytes2, + Platform.BYTE_ARRAY_OFFSET, + bytes.length); + } + long t = System.nanoTime(); + for (int i = 0; i < nums; i++) { + eq = + bytes.length == bytes2.length + && Platform.arrayEquals( + bytes, + Platform.BYTE_ARRAY_OFFSET, + bytes2, + Platform.BYTE_ARRAY_OFFSET, + bytes.length); + } + long duration = System.nanoTime() - t; + System.out.format("native cost %sns %sms\n", duration, duration / 1000_000); + } + { + // warm + for (int i = 0; i < nums; i++) { + eq = Arrays.equals(bytes, bytes2); + } + long t = System.nanoTime(); + for (int i = 0; i < nums; i++) { + eq = Arrays.equals(bytes, bytes2); + } + long duration = System.nanoTime() - t; + System.out.format("Arrays.equals cost %sns %sms\n", duration, duration / 1000_000); + } + return eq; + } + + @Test + public void wrapDirectBuffer() { + long address = 0; + try { + int size = 16; + address = Platform.allocateMemory(size); + ByteBuffer buffer = Platform.wrapDirectBuffer(address, size); + buffer.putLong(0, 1); + assertEquals(1, buffer.getLong(0)); + } finally { + Platform.freeMemory(address); + } + } + + @Test(enabled = false) + public void benchmarkWrapDirectBuffer() { + long address = 0; + try { + int size = 16; + address = Platform.allocateMemory(size); + long nums = 100_000_000; + ByteBuffer buffer = null; + { + for (int i = 0; i < nums; i++) { + buffer = Platform.wrapDirectBuffer(address, size); + } + long startTime = System.nanoTime(); + for (int i = 0; i < nums; i++) { + buffer = Platform.wrapDirectBuffer(address, size); + } + long duration = System.nanoTime() - startTime; + buffer.putLong(0, 1); + if (LOG.isInfoEnabled()) { + LOG.info("wrapDirectBuffer costs " + duration + "ns " + duration / 1000_000 + "ms\n"); + } + } + { + for (int i = 0; i < nums; i++) { + Platform.wrapDirectBuffer(buffer, address, size); + } + long startTime = System.nanoTime(); + for (int i = 0; i < nums; i++) { + Platform.wrapDirectBuffer(buffer, address, size); + } + long duration = System.nanoTime() - startTime; + buffer.putLong(0, 1); + if (LOG.isInfoEnabled()) { + LOG.info("wrap into buffer costs " + duration + "ns " + duration / 1000_000 + "ms\n"); + } + } + { + byte[] arr = new byte[32]; + ByteBuffer buf = null; + for (int i = 0; i < nums; i++) { + buf = ByteBuffer.wrap(arr); + } + long startTime = System.nanoTime(); + for (int i = 0; i < nums; i++) { + buf = ByteBuffer.wrap(arr); + } + long duration = System.nanoTime() - startTime; + buf.putLong(0, 1); + if (LOG.isInfoEnabled()) { + LOG.info("ByteBuffer.wrap " + duration + "ns " + duration / 1000_000 + "ms\n"); + } + } + } finally { + Platform.freeMemory(address); + } + } +}