lwjgl/src/java/org/lwjgl/util/mapped/CacheUtil.java

193 lines
6.0 KiB
Java

/*
* Copyright (c) 2002-2011 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.lwjgl.util.mapped;
import org.lwjgl.LWJGLUtil;
import org.lwjgl.MemoryUtil;
import org.lwjgl.PointerBuffer;
import java.nio.*;
/**
* This class provides utility methods for allocating cache-line-aligned
* NIO buffers. The CPU cache line size is detected using a micro-benchmark
* that exploits the performation degredation that occurs when different
* threads write to different locations of the same cache line. The detection
* should be reasonably robust on both the server and client VM, but there
* are a few system properties that can be used to tune it.
*
* @author Spasi
*/
public final class CacheUtil {
private static final int CACHE_LINE_SIZE;
static {
final Integer size = LWJGLUtil.getPrivilegedInteger("org.lwjgl.util.mapped.CacheLineSize"); // forces a specific cache line size
if ( size != null ) {
if ( size < 1 )
throw new IllegalStateException("Invalid CacheLineSize specified: " + size);
CACHE_LINE_SIZE = size;
} else if ( Runtime.getRuntime().availableProcessors() == 1 ) { // We cannot use false sharing to detect it
/*
Spasi:
I have implemented a single-threaded benchmark for this, but it requires
lots of memory allocations and could not tune it for both the client and
server VM. It's not a big deal anyway, 64 bytes should be ok for any
single-core CPU.
*/
if ( LWJGLUtil.DEBUG )
LWJGLUtil.log("Cannot detect cache line size on single-core CPUs, assuming 64 bytes.");
CACHE_LINE_SIZE = 64;
} else
CACHE_LINE_SIZE = CacheLineSize.getCacheLineSize();
}
private CacheUtil() {
}
/**
* Returns the CPU cache line size, in number of bytes.
*
* @return the cache line size
*/
public static int getCacheLineSize() {
return CACHE_LINE_SIZE;
}
/**
* Construct a direct, native-ordered and cache-line-aligned bytebuffer with the specified size.
*
* @param size The size, in bytes
*
* @return a ByteBuffer
*/
public static ByteBuffer createByteBuffer(int size) {
ByteBuffer buffer = ByteBuffer.allocateDirect(size + CACHE_LINE_SIZE);
// Align to cache line.
if ( MemoryUtil.getAddress(buffer) % CACHE_LINE_SIZE != 0 ) {
// Round up to cache line boundary
buffer.position(CACHE_LINE_SIZE - (int)(MemoryUtil.getAddress(buffer) & (CACHE_LINE_SIZE - 1)));
}
buffer.limit(buffer.position() + size);
return buffer.slice().order(ByteOrder.nativeOrder());
}
/**
* Construct a direct, native-ordered and cache-line-aligned shortbuffer with the specified number
* of elements.
*
* @param size The size, in shorts
*
* @return a ShortBuffer
*/
public static ShortBuffer createShortBuffer(int size) {
return createByteBuffer(size << 1).asShortBuffer();
}
/**
* Construct a direct, native-ordered and cache-line-aligned charbuffer with the specified number
* of elements.
*
* @param size The size, in chars
*
* @return an CharBuffer
*/
public static CharBuffer createCharBuffer(int size) {
return createByteBuffer(size << 1).asCharBuffer();
}
/**
* Construct a direct, native-ordered and cache-line-aligned intbuffer with the specified number
* of elements.
*
* @param size The size, in ints
*
* @return an IntBuffer
*/
public static IntBuffer createIntBuffer(int size) {
return createByteBuffer(size << 2).asIntBuffer();
}
/**
* Construct a direct, native-ordered and cache-line-aligned longbuffer with the specified number
* of elements.
*
* @param size The size, in longs
*
* @return an LongBuffer
*/
public static LongBuffer createLongBuffer(int size) {
return createByteBuffer(size << 3).asLongBuffer();
}
/**
* Construct a direct, native-ordered and cache-line-aligned floatbuffer with the specified number
* of elements.
*
* @param size The size, in floats
*
* @return a FloatBuffer
*/
public static FloatBuffer createFloatBuffer(int size) {
return createByteBuffer(size << 2).asFloatBuffer();
}
/**
* Construct a direct, native-ordered and cache-line-aligned doublebuffer with the specified number
* of elements.
*
* @param size The size, in floats
*
* @return a FloatBuffer
*/
public static DoubleBuffer createDoubleBuffer(int size) {
return createByteBuffer(size << 3).asDoubleBuffer();
}
/**
* Construct a cache-line-aligned PointerBuffer with the specified number
* of elements.
*
* @param size The size, in memory addresses
*
* @return a PointerBuffer
*/
public static PointerBuffer createPointerBuffer(int size) {
return new PointerBuffer(createByteBuffer(size * PointerBuffer.getPointerSize()));
}
}