Replaced HashMap<Long, T> with FastLongMap in the OpenCL package.

Replaced CharsetEncoder with simple ASCII encoding in APIUtil.
Attempt to fix CL native kernels on x64.
This commit is contained in:
Ioannis Tsakpinis 2010-10-12 01:35:33 +00:00
parent 8d37d1bdee
commit 9405dde18a
9 changed files with 300 additions and 177 deletions

View File

@ -34,10 +34,9 @@ package org.lwjgl.opencl;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLUtil;
import org.lwjgl.PointerBuffer;
import org.lwjgl.opencl.FastLongMap.Entry;
import java.nio.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
@ -75,16 +74,10 @@ final class APIUtil {
protected PointerBuffer initialValue() { return BufferUtils.createPointerBuffer(INITIAL_LENGTHS_SIZE); }
};
private static final ThreadLocal<InfiniteCharSequence> infiniteSeqTL = new ThreadLocal<InfiniteCharSequence>() {
protected InfiniteCharSequence initialValue() { return new InfiniteCharSequence(); }
};
private static final ThreadLocal<Buffers> buffersTL = new ThreadLocal<Buffers>() {
protected Buffers initialValue() { return new Buffers(); }
};
private static final CharsetEncoder encoder = Charset.forName("US-ASCII").newEncoder();
private APIUtil() {
}
@ -188,15 +181,22 @@ final class APIUtil {
return lengths;
}
private static InfiniteCharSequence getInfiniteSeq() {
return infiniteSeqTL.get();
}
/**
* Simple ASCII encoding.
*
* @param buffer The target buffer
* @param string The source string
*/
private static ByteBuffer encode(final ByteBuffer buffer, final CharSequence string) {
for ( int i = 0; i < string.length(); i++ ) {
final char c = string.charAt(i);
if ( LWJGLUtil.DEBUG && 0x80 <= c ) // Silently ignore and map to 0x1A.
buffer.put((byte)0x1A);
else
buffer.put((byte)c);
}
private static void encode(final ByteBuffer buffer, final CharSequence string) {
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
infiniteSeq.setString(string);
encoder.encode(infiniteSeq.buffer, buffer, true);
infiniteSeq.clear();
return buffer;
}
/**
@ -224,10 +224,7 @@ final class APIUtil {
* @return the String as a ByteBuffer
*/
static ByteBuffer getBuffer(final CharSequence string) {
final ByteBuffer buffer = getBufferByte(string.length());
encode(buffer, string);
final ByteBuffer buffer = encode(getBufferByte(string.length()), string);
buffer.flip();
return buffer;
}
@ -240,10 +237,7 @@ final class APIUtil {
* @return the String as a ByteBuffer
*/
static ByteBuffer getBuffer(final CharSequence string, final int offset) {
final ByteBuffer buffer = getBufferByteOffset(offset + string.length());
encode(buffer, string);
final ByteBuffer buffer = encode(getBufferByteOffset(offset + string.length()), string);
buffer.flip();
return buffer;
}
@ -256,10 +250,7 @@ final class APIUtil {
* @return the String as a ByteBuffer
*/
static ByteBuffer getBufferNT(final CharSequence string) {
final ByteBuffer buffer = getBufferByte(string.length() + 1);
encode(buffer, string);
final ByteBuffer buffer = encode(getBufferByte(string.length() + 1), string);
buffer.put((byte)0);
buffer.flip();
return buffer;
@ -283,12 +274,8 @@ final class APIUtil {
static ByteBuffer getBuffer(final CharSequence[] strings) {
final ByteBuffer buffer = getBufferByte(getTotalLength(strings));
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
for ( CharSequence string : strings ) {
infiniteSeq.setString(string);
encoder.encode(infiniteSeq.buffer, buffer, true);
}
infiniteSeq.clear();
for ( CharSequence string : strings )
encode(buffer, string);
buffer.flip();
return buffer;
@ -304,13 +291,10 @@ final class APIUtil {
static ByteBuffer getBufferNT(final CharSequence[] strings) {
final ByteBuffer buffer = getBufferByte(getTotalLength(strings) + strings.length);
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
for ( CharSequence string : strings ) {
infiniteSeq.setString(string);
encoder.encode(infiniteSeq.buffer, buffer, true);
encode(buffer, string);
buffer.put((byte)0);
}
infiniteSeq.clear();
buffer.flip();
return buffer;
@ -358,43 +342,6 @@ final class APIUtil {
return (int)size;
}
/**
* A mutable CharSequence with very large initial length. We can wrap this in a re-usable CharBuffer for decoding.
* We cannot subclass CharBuffer because of {@link java.nio.CharBuffer#toString(int,int)}.
*/
private static class InfiniteCharSequence implements CharSequence {
final CharBuffer buffer;
CharSequence string;
InfiniteCharSequence() {
buffer = CharBuffer.wrap(this);
}
void setString(final CharSequence string) {
this.string = string;
this.buffer.position(0);
this.buffer.limit(string.length());
}
void clear() {
this.string = null;
}
public int length() {
return Integer.MAX_VALUE;
}
public char charAt(final int index) {
return string.charAt(index);
}
public CharSequence subSequence(final int start, final int end) {
return string.subSequence(start, end);
}
}
private static class Buffers {
final ShortBuffer shorts;
@ -559,7 +506,8 @@ final class APIUtil {
if ( registry.isEmpty() )
return;
for ( final T object : registry.getAll() ) {
for ( Entry<T> entry : registry.getAll() ) {
final T object = entry.value;
while ( object.isValid() )
destructor.release(object);
}

View File

@ -37,9 +37,7 @@ import org.lwjgl.opencl.api.Filter;
import org.lwjgl.opengl.Drawable;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This class is a wrapper around a cl_context pointer.
@ -57,10 +55,10 @@ public final class CLContext extends CLObjectChild<CLPlatform> {
private final CLObjectRegistry<CLEvent> clEvents;
/** Global registry for build callbacks. */
static final Map<Long, CLProgram> clProgramsGlobal = new HashMap<Long, CLProgram>();
static final FastLongMap<CLProgram> clProgramsGlobal = new FastLongMap<CLProgram>();
/** Global registry for event callbacks. */
static final Map<Long, CLEvent> clEventsGlobal = new HashMap<Long, CLEvent>();
static final FastLongMap<CLEvent> clEventsGlobal = new FastLongMap<CLEvent>();
CLContext(final long pointer, final CLPlatform platform) {
super(pointer, platform);

View File

@ -2,11 +2,6 @@ package org.lwjgl.opencl;
import org.lwjgl.LWJGLUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A CLObjectChild container.
*
@ -14,7 +9,7 @@ import java.util.Map;
*/
class CLObjectRegistry<T extends CLObjectChild> {
private Map<Long, T> registry;
private FastLongMap<T> registry;
CLObjectRegistry() {
}
@ -31,12 +26,12 @@ class CLObjectRegistry<T extends CLObjectChild> {
return registry != null && registry.containsKey(id);
}
final List<T> getAll() {
return registry == null ? null : new ArrayList<T>(registry.values());
final Iterable<FastLongMap.Entry<T>> getAll() {
return registry;
}
void registerObject(final T object) {
final Map<Long, T> map = getMap();
final FastLongMap<T> map = getMap();
final Long key = object.getPointer();
if ( LWJGLUtil.DEBUG && map.containsKey(key) )
@ -49,9 +44,9 @@ class CLObjectRegistry<T extends CLObjectChild> {
getMap().remove(object.getPointerUnsafe());
}
private Map<Long, T> getMap() {
private FastLongMap<T> getMap() {
if ( registry == null )
registry = new HashMap<Long, T>();
registry = new FastLongMap<T>();
return registry;
}

View File

@ -31,8 +31,6 @@
*/
package org.lwjgl.opencl;
import java.util.Map;
/**
* A CLObject registry that also registers/unregisters objects to/from a global registry.
*
@ -40,9 +38,9 @@ import java.util.Map;
*/
final class CLObjectRegistryGlobal<T extends CLObjectChild> extends CLObjectRegistry<T> {
private final Map<Long, T> globalRegistry;
private final FastLongMap<T> globalRegistry;
CLObjectRegistryGlobal(final Map<Long, T> globalRegistry) {
CLObjectRegistryGlobal(final FastLongMap<T> globalRegistry) {
this.globalRegistry = globalRegistry;
}

View File

@ -36,9 +36,7 @@ import org.lwjgl.opencl.api.Filter;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.lang.Math.*;
@ -51,12 +49,12 @@ public final class CLPlatform extends CLObject {
private static final CLPlatformUtil util = (CLPlatformUtil)getInfoUtilInstance(CLPlatform.class, "CL_PLATFORM_UTIL");
private static final Map<Long, CLPlatform> clPlatforms = new HashMap<Long, CLPlatform>();
private static final FastLongMap<CLPlatform> clPlatforms = new FastLongMap<CLPlatform>();
private final CLObjectRegistry<CLDevice> clDevices;
/** Global registry for build callbacks. */
static final Map<Long, CLDevice> clDevicesGlobal = new HashMap<Long, CLDevice>();
static final FastLongMap<CLDevice> clDevicesGlobal = new FastLongMap<CLDevice>();
private Object caps;

View File

@ -0,0 +1,239 @@
/*
* Copyright 2002-2004 The Apache Software Foundation.
*
* 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 org.lwjgl.opencl;
import java.util.Iterator;
/**
* A hash map using primitive longs as keys rather than objects.
*
* @author Justin Couch
* @author Alex Chaffee (alex@apache.org)
* @author Stephen Colebourne
* @author Nathan Sweet
*/
final class FastLongMap<V> implements Iterable<FastLongMap.Entry<V>> {
private Entry[] table;
private int size, mask, capacity, threshold;
/** Same as: FastLongMap(16, 0.75f); */
FastLongMap() {
this(16, 0.75f);
}
/** Same as: FastLongMap(initialCapacity, 0.75f); */
FastLongMap(int initialCapacity) {
this(initialCapacity, 0.75f);
}
FastLongMap(int initialCapacity, float loadFactor) {
if ( initialCapacity > 1 << 30 ) throw new IllegalArgumentException("initialCapacity is too large.");
if ( initialCapacity < 0 ) throw new IllegalArgumentException("initialCapacity must be greater than zero.");
if ( loadFactor <= 0 ) throw new IllegalArgumentException("initialCapacity must be greater than zero.");
capacity = 1;
while ( capacity < initialCapacity )
capacity <<= 1;
this.threshold = (int)(capacity * loadFactor);
this.table = new Entry[capacity];
this.mask = capacity - 1;
}
private int index(final long key) {
return index(key, mask);
}
private static int index(final long key, final int mask) {
final int hash = (int)(key ^ (key >>> 32));
return hash & mask;
}
public V put(long key, V value) {
final Entry<V>[] table = this.table;
int index = index(key);
// Check if key already exists.
for ( Entry<V> e = table[index]; e != null; e = e.next ) {
if ( e.key != key ) continue;
V oldValue = e.value;
e.value = value;
return oldValue;
}
table[index] = new Entry<V>(key, value, table[index]);
if ( size++ >= threshold )
rehash(table);
return null;
}
private void rehash(final Entry<V>[] table) {
final int newCapacity = 2 * capacity;
final int newMask = newCapacity - 1;
final Entry<V>[] newTable = new Entry[newCapacity];
for ( int i = 0, index; i < table.length; i++ ) {
Entry<V> e = table[i];
if ( e == null ) continue;
do {
final Entry<V> next = e.next;
index = index(e.key, newMask);
e.next = newTable[index];
newTable[index] = e;
e = next;
} while ( e != null );
}
this.table = newTable;
capacity = newCapacity;
mask = newMask;
threshold *= 2;
}
public V get(long key) {
final int index = index(key);
for ( Entry<V> e = table[index]; e != null; e = e.next )
if ( e.key == key ) return e.value;
return null;
}
public boolean containsValue(Object value) {
final Entry<V>[] table = this.table;
for ( int i = table.length - 1; i >= 0; i-- )
for ( Entry<V> e = table[i]; e != null; e = e.next )
if ( e.value.equals(value) ) return true;
return false;
}
public boolean containsKey(long key) {
final int index = index(key);
for ( Entry<V> e = table[index]; e != null; e = e.next )
if ( e.key == key ) return true;
return false;
}
public V remove(long key) {
final int index = index(key);
Entry<V> prev = table[index];
Entry<V> e = prev;
while ( e != null ) {
Entry<V> next = e.next;
if ( e.key == key ) {
size--;
if ( prev == e )
table[index] = next;
else
prev.next = next;
return e.value;
}
prev = e;
e = next;
}
return null;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void clear() {
final Entry<V>[] table = this.table;
for ( int index = table.length - 1; index >= 0; index-- )
table[index] = null;
size = 0;
}
public EntryIterator iterator() {
return new EntryIterator();
}
public class EntryIterator implements Iterator<Entry<V>> {
private int nextIndex;
private Entry<V> current;
EntryIterator() {
reset();
}
public void reset() {
current = null;
// Find first bucket.
final Entry<V>[] table = FastLongMap.this.table;
int i;
for ( i = table.length - 1; i >= 0; i-- )
if ( table[i] != null ) break;
nextIndex = i;
}
public boolean hasNext() {
if ( nextIndex >= 0 ) return true;
Entry e = current;
return e != null && e.next != null;
}
public Entry<V> next() {
// Next entry in current bucket.
Entry<V> e = current;
if ( e != null ) {
e = e.next;
if ( e != null ) {
current = e;
return e;
}
}
// Use the bucket at nextIndex and find the next nextIndex.
final Entry<V>[] table = FastLongMap.this.table;
int i = nextIndex;
e = current = table[i];
while ( --i >= 0 )
if ( table[i] != null ) break;
nextIndex = i;
return e;
}
public void remove() {
FastLongMap.this.remove(current.key);
}
}
static final class Entry<T> {
final long key;
T value;
Entry<T> next;
Entry(long key, T value, Entry<T> next) {
this.key = key;
this.value = value;
this.next = next;
}
public long getKey() {
return key;
}
public T getValue() {
return value;
}
}
}

View File

@ -32,10 +32,9 @@
package org.lwjgl.opengl;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLUtil;
import java.nio.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
/** @author spasi */
final class APIUtil {
@ -57,16 +56,10 @@ final class APIUtil {
protected IntBuffer initialValue() { return BufferUtils.createIntBuffer(INITIAL_LENGTHS_SIZE); }
};
private static final ThreadLocal<InfiniteCharSequence> infiniteSeqTL = new ThreadLocal<InfiniteCharSequence>() {
protected InfiniteCharSequence initialValue() { return new InfiniteCharSequence(); }
};
private static final ThreadLocal<Buffers> buffersTL = new ThreadLocal<Buffers>() {
protected Buffers initialValue() { return new Buffers(); }
};
private static CharsetEncoder encoder = Charset.forName("US-ASCII").newEncoder();
private APIUtil() {
}
@ -150,15 +143,22 @@ final class APIUtil {
return lengths;
}
private static InfiniteCharSequence getInfiniteSeq() {
return infiniteSeqTL.get();
}
/**
* Simple ASCII encoding.
*
* @param buffer The target buffer
* @param string The source string
*/
private static ByteBuffer encode(final ByteBuffer buffer, final CharSequence string) {
for ( int i = 0; i < string.length(); i++ ) {
final char c = string.charAt(i);
if ( LWJGLUtil.DEBUG && 0x80 <= c ) // Silently ignore and map to 0x1A.
buffer.put((byte)0x1A);
else
buffer.put((byte)c);
}
private static void encode(final ByteBuffer buffer, final CharSequence string) {
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
infiniteSeq.setString(string);
encoder.encode(infiniteSeq.buffer, buffer, true);
infiniteSeq.clear();
return buffer;
}
/**
@ -186,10 +186,7 @@ final class APIUtil {
* @return the String as a ByteBuffer
*/
static ByteBuffer getBuffer(final CharSequence string) {
final ByteBuffer buffer = getBufferByte(string.length());
encode(buffer, string);
final ByteBuffer buffer = encode(getBufferByte(string.length()), string);
buffer.flip();
return buffer;
}
@ -202,10 +199,7 @@ final class APIUtil {
* @return the String as a ByteBuffer
*/
static ByteBuffer getBuffer(final CharSequence string, final int offset) {
final ByteBuffer buffer = getBufferByteOffset(offset + string.length());
encode(buffer, string);
final ByteBuffer buffer = encode(getBufferByteOffset(offset + string.length()), string);
buffer.flip();
return buffer;
}
@ -218,10 +212,7 @@ final class APIUtil {
* @return the String as a ByteBuffer
*/
static ByteBuffer getBufferNT(final CharSequence string) {
final ByteBuffer buffer = getBufferByte(string.length() + 1);
encode(buffer, string);
final ByteBuffer buffer = encode(getBufferByte(string.length() + 1), string);
buffer.put((byte)0);
buffer.flip();
return buffer;
@ -245,12 +236,8 @@ final class APIUtil {
static ByteBuffer getBuffer(final CharSequence[] strings) {
final ByteBuffer buffer = getBufferByte(getTotalLength(strings));
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
for ( CharSequence string : strings ) {
infiniteSeq.setString(string);
encoder.encode(infiniteSeq.buffer, buffer, true);
}
infiniteSeq.clear();
for ( CharSequence string : strings )
encode(buffer, string);
buffer.flip();
return buffer;
@ -266,13 +253,10 @@ final class APIUtil {
static ByteBuffer getBufferNT(final CharSequence[] strings) {
final ByteBuffer buffer = getBufferByte(getTotalLength(strings) + strings.length);
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
for ( CharSequence string : strings ) {
infiniteSeq.setString(string);
encoder.encode(infiniteSeq.buffer, buffer, true);
encode(buffer, string);
buffer.put((byte)0);
}
infiniteSeq.clear();
buffer.flip();
return buffer;
@ -295,43 +279,6 @@ final class APIUtil {
return buffer;
}
/**
* A mutable CharSequence with very large initial length. We can wrap this in a re-usable CharBuffer for decoding.
* We cannot subclass CharBuffer because of {@link CharBuffer#toString(int,int)}.
*/
private static class InfiniteCharSequence implements CharSequence {
final CharBuffer buffer;
CharSequence string;
InfiniteCharSequence() {
buffer = CharBuffer.wrap(this);
}
void setString(final CharSequence string) {
this.string = string;
this.buffer.position(0);
this.buffer.limit(string.length());
}
void clear() {
this.string = null;
}
public int length() {
return Integer.MAX_VALUE;
}
public char charAt(final int index) {
return string.charAt(index);
}
public CharSequence subSequence(final int start, final int end) {
return string.subSequence(start, end);
}
}
private static class Buffers {
final ShortBuffer shorts;

View File

@ -156,9 +156,9 @@ static void CL_USER_FUNC_CALLBACK nativeKernelCallback(void *args) {
for ( i = 0; i < num_mem_objects; i++ ) {
buffer = (*env)->NewDirectByteBuffer(env,
// Pointer to cl_mem buffer
(void *)((char *)args + (12 + 4 + (i * (4 + sizeof(size_t))))),
(void *)((char *)args + (12 + 4 + (i * (4 + sizeof(void *))))),
// cl_mem buffer size
*((jint *)((char *)args + (12 + (i * (4 + sizeof(size_t))))))
*((jint *)((char *)args + (12 + (i * (4 + sizeof(void *))))))
);
(*env)->SetObjectArrayElement(env, memobjs, i, buffer);
}

View File

@ -1061,7 +1061,7 @@ public interface CL10 {
nativeAfterVars = "\tvoid **args_mem_loc = num_mem_objects == 0 ? NULL : (void **)malloc(num_mem_objects * sizeof(void *));",
nativeBeforeCall = "\t_ptr_i = 0;\n" +
"\twhile ( _ptr_i < num_mem_objects ) {\n" +
"\t\targs_mem_loc[_ptr_i] = (cl_void *)((char *)args_address + (4 + _ptr_i * (4 + sizeof(size_t))));\n" +
"\t\targs_mem_loc[_ptr_i] = (cl_void *)((char *)args_address + (4 + _ptr_i * (4 + sizeof(void *))));\n" +
"\t\t_ptr_i++;\n" +
"\t}",
nativeAfterCall = "\tfree(args_mem_loc);"