Skip to content

Commit

Permalink
Merge pull request #199 from ate47/gh-198-remove-jlargearrays
Browse files Browse the repository at this point in the history
GH-198 Replace JLargeArrays to custom implementation
  • Loading branch information
D063520 authored Sep 12, 2023
2 parents 912276e + 0ee97a3 commit a97af4e
Show file tree
Hide file tree
Showing 13 changed files with 597 additions and 129 deletions.
5 changes: 0 additions & 5 deletions hdt-java-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,6 @@
<groupId>org.apache.jena</groupId>
<artifactId>jena-arq</artifactId>
</dependency>
<dependency>
<groupId>org.visnow</groupId>
<artifactId>JLargeArrays</artifactId>
<version>1.7-20220624.150242-7</version>
</dependency>
<dependency>
<groupId>pl.pragmatists</groupId>
<artifactId>JUnitParams</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import org.rdfhdt.hdt.util.disk.LongArrayDisk;
import org.rdfhdt.hdt.util.io.Closer;
import org.rdfhdt.hdt.util.io.IOUtil;
import org.visnow.jlargearrays.LongLargeArray;

import java.io.Closeable;
import java.io.IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,20 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;

import org.rdfhdt.hdt.compact.integer.VByte;
import org.rdfhdt.hdt.exceptions.CRCException;
import org.rdfhdt.hdt.exceptions.IllegalFormatException;
import org.rdfhdt.hdt.hdt.HDTVocabulary;
import org.rdfhdt.hdt.listener.ProgressListener;
import org.rdfhdt.hdt.unsafe.UnsafeLongArray;
import org.rdfhdt.hdt.util.BitUtil;
import org.rdfhdt.hdt.util.crc.CRC32;
import org.rdfhdt.hdt.util.crc.CRC8;
import org.rdfhdt.hdt.util.crc.CRCInputStream;
import org.rdfhdt.hdt.util.crc.CRCOutputStream;
import org.rdfhdt.hdt.util.io.IOUtil;
import org.visnow.jlargearrays.LargeArrayUtils;
import org.visnow.jlargearrays.LongLargeArray;

/**
* @author mario.arias,Lyudmila Balakireva
Expand All @@ -55,7 +53,7 @@ public class SequenceLog64Big implements DynamicSequence {
private static final byte W = 64;
private static final int INDEX = 1073741824;

LongLargeArray data;
UnsafeLongArray data;
private int numbits;
private long numentries;
private long maxvalue;
Expand All @@ -74,8 +72,7 @@ public SequenceLog64Big(int numbits, long capacity) {
this.maxvalue = BitUtil.maxVal(numbits);

long size = numWordsFor(numbits, capacity);
LongLargeArray.setMaxSizeOf32bitArray(SequenceLog64Big.INDEX);


data = IOUtil.createLargeArray(Math.max(size,1));
}

Expand Down Expand Up @@ -115,7 +112,7 @@ public static long numBytesFor(int bitsField, long total) {
* @param bitsField Length in bits of each field
* @param index Position to be retrieved
*/
private static long getField(LongLargeArray data, int bitsField, long index) {
private static long getField(UnsafeLongArray data, int bitsField, long index) {
if(bitsField==0) return 0;

long bitPos = index*bitsField;
Expand All @@ -137,15 +134,15 @@ private static long getField(LongLargeArray data, int bitsField, long index) {
* @param index Position to store in
* @param value Value to be stored
*/
private static void setField(LongLargeArray data, int bitsField, long index, long value) {
private static void setField(UnsafeLongArray data, int bitsField, long index, long value) {
if(bitsField==0) return;

long bitPos = index*bitsField;
long i= bitPos/W;
long j= bitPos%W;

long mask = ~(~0L << bitsField) << j;
data.set(i, (data.getLong(i) & ~mask) | (value << j));
data.set(i, (data.get(i) & ~mask) | (value << j));

if((j+bitsField>W)) {
mask = ~0L << (bitsField+j-W);
Expand All @@ -157,8 +154,8 @@ private void resizeArray(long size) {
//data = Arrays.copyOf(data, size);
if(size > 0) {
if (data.length() != size) {
LongLargeArray a = IOUtil.createLargeArray(size, false);
LargeArrayUtils.arraycopy(data, 0, a, 0, Math.min(size, data.length()));
UnsafeLongArray a = IOUtil.createLargeArray(size, false);
UnsafeLongArray.arraycopy(data, 0, a, 0, Math.min(size, data.length()));
data = a;
}
}else{
Expand Down Expand Up @@ -287,7 +284,7 @@ public void resize(long numentries) {

@Override
public void clear() {
IOUtil.fillLargeArray(data, 0);
data.clear();
}

/* (non-Javadoc)
Expand Down Expand Up @@ -316,7 +313,7 @@ public void save(OutputStream output, ProgressListener listener) throws IOExcept

long numwords = numWordsFor(numbits, numentries);
for(long i=0;i<numwords-1;i++) {
IOUtil.writeLong(out, data.getLong(i));
IOUtil.writeLong(out, data.get(i));
}

if(numwords>0) {
Expand Down
250 changes: 250 additions & 0 deletions hdt-java-core/src/main/java/org/rdfhdt/hdt/unsafe/MemoryUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
package org.rdfhdt.hdt.unsafe;

import org.rdfhdt.hdt.util.concurrent.ExceptionThread;

import java.lang.ref.Cleaner;
import java.lang.reflect.Field;
import java.util.stream.IntStream;

/**
* Unsafe memory utilities
*
* @author Antoine Willerval
*/
public class MemoryUtils {
/**
* Unsafe object
*/
private static final sun.misc.Unsafe UNSAFE;
/**
* Cleaner
*/
private static final Cleaner CLEANER = Cleaner.create();
/**
* pointer to a zero buffer of size {@link #BUFFER_SIZE}
*/
private static final long ZERO_BUFFER;
/**
* pointer to a minus one buffer of size {@link #BUFFER_SIZE}
*/
private static final long MINUS_ONE_BUFFER;
/**
* Object to clean the ZERO/MINUS buffers
*/
private static final Object BUFFER_PARENT = new Object() {
};
/**
* number of bits in the buffer size
*/
private static final int BUFFER_SIZE_BITS = 12; // 2**12 = 4096
/**
* number of bytes in the buffer for {@link #MINUS_ONE_BUFFER} and
* {@link #ZERO_BUFFER}, is equal to 2 to the power of
* {@link #BUFFER_SIZE_BITS}.
*/
private static final int BUFFER_SIZE;
/**
* max size of a Java array before switching to unsafe array, non-final for
* debug
*/
static int maxArraySize = Integer.MAX_VALUE >> 1;
/**
* threshold before switching to parallel set in memset, non-final for debug
*/
static long thresholdParallelSizeSet = (long) maxArraySize * 10;

static {
try {
Field f = Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe");
f.setAccessible(true);
UNSAFE = (sun.misc.Unsafe) f.get(null);
if (UNSAFE == null) {
throw new NullPointerException("Unsafe value is null!");
}
} catch (NullPointerException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException
| NoSuchFieldException | SecurityException e) {
throw new Error("Can't get field value sun.misc.Unsafe", e);
}

if (BUFFER_SIZE_BITS < 3) {
throw new Error("BUFFER_SIZE_BITS can't be lower than 3!");
}
BUFFER_SIZE = 1 << BUFFER_SIZE_BITS;

// allocate the buffers and directly bind them to their parents

ZERO_BUFFER = UNSAFE.allocateMemory(BUFFER_SIZE);
bindPointerTo(ZERO_BUFFER, BUFFER_PARENT);

MINUS_ONE_BUFFER = UNSAFE.allocateMemory(BUFFER_SIZE);
bindPointerTo(MINUS_ONE_BUFFER, BUFFER_PARENT);

// now we can set the values
for (long i = 0; i < (BUFFER_SIZE >> 3); i++) {
UNSAFE.putLong(ZERO_BUFFER + i * 8, 0);
// we can use -1 because -1L = 0xFFFF_FFFF_FFFF_FFFF, so full of
// 0xFF bytes
UNSAFE.putLong(MINUS_ONE_BUFFER + i * 8, -1L);
}
}

/**
* @return unsafe object, be careful and gentle with it
*/
public static sun.misc.Unsafe getUnsafe() {
return UNSAFE;
}

/**
* @return cleaner object
*/
public static Cleaner getCleaner() {
return CLEANER;
}

/**
* @return max size of an array
*/
public static int getMaxArraySize() {
return maxArraySize;
}

/**
* allocate memory
*
* @param size number of elements
* @param sizeOf size of an element
* @return pointer
*/
public static long malloc(long size, int sizeOf) {
return malloc(size * sizeOf);
}

/**
* allocate memory
*
* @param size size to allocate
* @return pointer
*/
public static long malloc(long size) {
return UNSAFE.allocateMemory(size);
}

/**
* free a pointer from the memory
*
* @param ptr pointer
*/
public static void free(long ptr) {
UNSAFE.freeMemory(ptr);
}

/**
* bind this pointer to an object
*
* @param pointer pointer
* @param parent parent object
*/
public static void bindPointerTo(long pointer, Object parent) {
CLEANER.register(parent, new CleanerObject(pointer));
}

private static void memorySet0(long ptr, long size, byte value) {
// fast version using buffer
if (value == -1) {
memorySetBuffer(ptr, size, MINUS_ONE_BUFFER);
return;
}
if (value == 0) {
memorySetBuffer(ptr, size, ZERO_BUFFER);
return;
}
int uv = value & 0xFF;
long lvalue = uv | (uv << 8L) | (uv << 16L) | ((long) uv << 24L) | ((long) uv << 32) | ((long) uv << 40)
| ((long) uv << 48) | ((long) uv << 56);
long addr = ptr;
long lend = ptr + (size & ~7) - 1;
while (addr < lend) {
// use put long to reduce call to putByte
UNSAFE.putLong(addr, lvalue);
addr += 8;
}
// end padding
while (addr < ptr + size) {
UNSAFE.putByte(addr, value);
addr++;
}
}

private static void memorySetBuffer(long ptr, long size, long buffer) {
long addr = ptr;
long tow = size;
while (tow > 0) {
long len;
if (tow > BUFFER_SIZE) {
len = BUFFER_SIZE;
} else {
len = tow;
}
UNSAFE.copyMemory(buffer, addr, len);
tow -= len;
addr += len;
}
}

/**
* copy a memory block from one part of the memory to another one
*
* @param dst destination block start
* @param src source block start
* @param size size to copy
*/
public static void memcpy(long dst, long src, long size) {
UNSAFE.copyMemory(src, dst, size);
}

/**
* set all the bytes at an address
*
* @param ptr pointer
* @param size bytes to allocate
* @param value value
*/
public static void memset(long ptr, long size, byte value) {
if (size > thresholdParallelSizeSet) {
int processors = Runtime.getRuntime().availableProcessors();
long blockSize = size / processors + 1;
try {
ExceptionThread.async("memorySetThread", IntStream.range(0, processors).mapToObj(processor -> {
long start = blockSize * processor;
long end = Math.min(size, blockSize * (processor + 1));
return (ExceptionThread.ExceptionRunnable) () -> memorySet0(ptr + start, end - start, value);
}).toArray(ExceptionThread.ExceptionRunnable[]::new)).startAll().joinAndCrashIfRequired();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
memorySet0(ptr, size, value);
}
}

private MemoryUtils() {
throw new IllegalArgumentException("Can't init utils class");
}

private static class CleanerObject implements Runnable {
private long ptr;

private CleanerObject(long ptr) {
this.ptr = ptr;
}

@Override
public void run() {
if (ptr != 0) {
free(ptr);
ptr = 0;
}
}
}
}
Loading

0 comments on commit a97af4e

Please sign in to comment.