Last active
August 29, 2015 14:00
-
-
Save frsyuki/ddde844f87ea0aa33e7e to your computer and use it in GitHub Desktop.
unsafe-test-2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <sys/mman.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <sys/time.h> | |
#include <fcntl.h> | |
#include <stdint.h> | |
#include <stdbool.h> | |
#include <arpa/inet.h> | |
#if defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN) | |
# error architecture must be little endian | |
#endif | |
#if defined(_byteswap_uint64) || (defined(_MSC_VER) && _MSC_VER >= 1400) | |
# define _ntohll(x) (_byteswap_uint64(x)) | |
#elif defined(bswap_64) | |
# define _ntohll(x) bswap_64(x) | |
#elif defined(__DARWIN_OSSwapInt64) | |
# define _ntohll(x) __DARWIN_OSSwapInt64(x) | |
#else | |
# warn _ntohll by bitshift | |
# define _ntohll(x) \ | |
( ((((uint64_t)x) << 56) ) | \ | |
((((uint64_t)x) << 40) & 0x00ff000000000000ULL ) | \ | |
((((uint64_t)x) << 24) & 0x0000ff0000000000ULL ) | \ | |
((((uint64_t)x) << 8) & 0x000000ff00000000ULL ) | \ | |
((((uint64_t)x) >> 8) & 0x00000000ff000000ULL ) | \ | |
((((uint64_t)x) >> 24) & 0x0000000000ff0000ULL ) | \ | |
((((uint64_t)x) >> 40) & 0x000000000000ff00ULL ) | \ | |
((((uint64_t)x) >> 56) ) ) | |
#endif | |
#define _load32(dst, src, type) \ | |
do { \ | |
memcpy((type*) (dst), (src), sizeof(type)); \ | |
*(dst) = ntohl(*(dst)); \ | |
} while (0); | |
#define _load64(dst, src, type) \ | |
do { \ | |
memcpy((type*) (dst), (src), sizeof(type)); \ | |
*(dst) = _ntohll(*(dst)); \ | |
} while (0); | |
#define _shift32(dst, src, type) (*(dst) = (type) ( \ | |
(((uint32_t)((uint8_t*)(src))[0]) << 24) | \ | |
(((uint32_t)((uint8_t*)(src))[1]) << 16) | \ | |
(((uint32_t)((uint8_t*)(src))[2]) << 8) | \ | |
(((uint32_t)((uint8_t*)(src))[3]) ) )) | |
#define _shift64(dst, src, type) (*(dst) = (type) ( \ | |
(((uint64_t)((uint8_t*)(src))[0]) << 56) | \ | |
(((uint64_t)((uint8_t*)(src))[1]) << 48) | \ | |
(((uint64_t)((uint8_t*)(src))[2]) << 40) | \ | |
(((uint64_t)((uint8_t*)(src))[3]) << 32) | \ | |
(((uint64_t)((uint8_t*)(src))[4]) << 24) | \ | |
(((uint64_t)((uint8_t*)(src))[5]) << 16) | \ | |
(((uint64_t)((uint8_t*)(src))[6]) << 8) | \ | |
(((uint64_t)((uint8_t*)(src))[7]) ) )) | |
#define FILE_PATH "random.data" | |
static volatile int32_t v32; | |
static volatile int64_t v64; | |
static void run_shift(const char* data, size_t size) | |
{ | |
const size_t last = size - 9; | |
for(size_t i=0; i < last; i++) { | |
char b = data[i]; | |
i++; | |
if(b < 0) { | |
_shift32(&v32, data + i, int32_t); | |
i += 4; | |
} else { | |
_shift64(&v64, data + i, int64_t); | |
i += 8; | |
} | |
} | |
} | |
static void run_load(const char* data, size_t size) | |
{ | |
const size_t last = size - 9; | |
for(size_t i=0; i < last; i++) { | |
char b = data[i]; | |
i++; | |
if(b < 0) { | |
_load32(&v32, data + i, int32_t); | |
i += 4; | |
} else { | |
_load64(&v64, data + i, int64_t); | |
i += 8; | |
} | |
} | |
} | |
static void show_measured(const char* name, | |
size_t size, int loop, | |
const struct timeval* start, const struct timeval* finish) | |
{ | |
double time = | |
(finish->tv_sec - start->tv_sec) * 1000.0 + | |
(finish->tv_usec - start->tv_usec) / 1000.0; | |
double msec = time / loop; | |
double mbs = size * loop / (time / 1000) / 1024 / 1024; | |
printf("-- %s\n", name); | |
printf(" %.2f msec/loop\n", msec); | |
printf(" %.2f MB/s\n", mbs); | |
} | |
int main(void) | |
{ | |
const int loop = LOOP; // compile with -DLOOP=N option | |
int fd = open(FILE_PATH, O_RDONLY); | |
struct stat stbuf; | |
fstat(fd, &stbuf); | |
size_t size = stbuf.st_size; | |
char* map = mmap(NULL, size, PROT_READ, | |
MAP_SHARED, fd, 0); | |
printf("size: %lu\n", size); | |
printf("loop: %u times\n", loop); | |
{ | |
// warm-up | |
for(int i=0; i < loop; i++) { | |
run_load(map, size); | |
} | |
struct timeval start; | |
gettimeofday(&start, NULL); | |
for(int i=0; i < loop; i++) { | |
run_load(map, size); | |
} | |
struct timeval finish; | |
gettimeofday(&finish, NULL); | |
show_measured("C load", size, loop, &start, &finish); | |
} | |
{ | |
// warm-up | |
for(int i=0; i < loop; i++) { | |
run_shift(map, size); | |
} | |
struct timeval start; | |
gettimeofday(&start, NULL); | |
for(int i=0; i < loop; i++) { | |
run_shift(map, size); | |
} | |
struct timeval finish; | |
gettimeofday(&finish, NULL); | |
show_measured("C shift", size, loop, &start, &finish); | |
} | |
munmap(map, size); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Random; | |
import sun.misc.Unsafe; | |
import sun.nio.ch.DirectBuffer; | |
import java.lang.reflect.Field; | |
import java.nio.ByteBuffer; | |
import java.io.File; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
public class DeserBenchmark { | |
public static void main(String[] args) throws Exception { | |
if (args.length != 3) { | |
System.out.println("usage: <seed> <size> <loop>"); | |
System.exit(1); | |
} | |
long seed = Long.parseLong(args[0]); | |
int size = Integer.parseInt(args[1]); | |
int loop = Integer.parseInt(args[2]); | |
new DeserBenchmark().run(seed, size, loop); | |
} | |
public void run(long seed, int size, int loop) { | |
if (seed == 0) { | |
seed = new Random().nextInt(); | |
} | |
System.out.printf("seed: %d%n", seed); | |
System.out.printf("size: %d bytes%n", size); | |
System.out.printf("loop: %d times%n", loop); | |
byte[] bytes = new byte[size]; | |
new Random(seed).nextBytes(bytes); | |
ByteBuffer heap = ByteBuffer.wrap(bytes); | |
ByteBuffer direct = ByteBuffer.allocateDirect(size); | |
direct.put(bytes); | |
for(int n=0; n < 4; n++) { | |
//measure("ByteBuffer heap", size, loop, new ByteBufferRunnable(heap)); | |
//measure("ByteBuffer direct", size, loop, new ByteBufferRunnable(direct)); | |
//measure("Unsafe abstract heap", size, loop, new HeapUnsafeAbstractRunnable(bytes)); | |
//measure("Unsafe abstract direct", size, loop, new DirectUnsafeAbstractRunnable(direct)); | |
measure("Unsafe heap", size, loop, new HeapUnsafeRunnable(bytes)); | |
//measure("Unsafe direct", size, loop, new DirectUnsafeRunnable(direct)); | |
measure("Unsafe special input heap", size, loop, new HeapUnsafeSpecialInputRunnable(bytes)); | |
measure("Unsafe interface input heap", size, loop, new HeapUnsafeInterfaceInputRunnable(bytes)); | |
measure("Unsafe buffer heap", size, loop, new HeapUnsafeBufferRunnable(bytes)); | |
} | |
System.out.println("writing data to random.data file"); | |
try { | |
new FileOutputStream(new File("random.data")).write(bytes); | |
} catch (IOException ex) { | |
ex.printStackTrace(); | |
} | |
} | |
private void measure(String name, int size, int loop, Runnable runnable) { | |
// warm-up | |
for (int i=0; i < loop; i++) { | |
runnable.run(); | |
} | |
long startTime = System.currentTimeMillis(); | |
for (int i=0; i < loop; i++) { | |
runnable.run(); | |
} | |
long time = System.currentTimeMillis() - startTime; | |
double mbs = size * (long) loop / ((double) time / 1000) / 1024 / 1024; | |
double msec = time / (double) loop; | |
System.out.printf("-- %s%n", name); | |
System.out.printf(" %.2f msec/loop%n", msec); | |
System.out.printf(" %.2f MB/s%n", mbs); | |
} | |
private static class ByteBufferRunnable implements Runnable { | |
private ByteBuffer src; | |
public int v32; | |
public long v64; | |
public ByteBufferRunnable(ByteBuffer src) { | |
this.src = src; | |
} | |
public void run() { | |
int last = src.limit() - 9; | |
for(int i=0; i < last; i++) { | |
byte b = src.get(i); | |
i++; | |
if(b < 0) { | |
v32 = src.getInt(i); | |
i += 4; | |
} else { | |
v64 = src.getLong(i); | |
i += 8; | |
} | |
} | |
} | |
} | |
private static class UnsafeRunnable implements Runnable { | |
private static final Unsafe unsafe; | |
static { | |
try { | |
Field field = Unsafe.class.getDeclaredField("theUnsafe"); | |
field.setAccessible(true); | |
unsafe = (Unsafe) field.get(null); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private final Object base; | |
private final long address; | |
private final int length; | |
public int v32; | |
public long v64; | |
public UnsafeRunnable(Object base, long address, int length) { | |
this.base = base; | |
this.address = address; | |
this.length = length; | |
} | |
public void run() { | |
int last = length - 9; | |
for(int i=0; i < last; i++) { | |
byte b = unsafe.getByte(base, address + i); | |
i++; | |
if(b < 0) { | |
v32 = unsafe.getInt(base, address + i); | |
i += 4; | |
} else { | |
v64 = unsafe.getLong(base, address + i); | |
i += 8; | |
} | |
} | |
} | |
} | |
private static class HeapUnsafeRunnable extends UnsafeRunnable { | |
public HeapUnsafeRunnable(byte[] src) { | |
super(src, Unsafe.ARRAY_BYTE_BASE_OFFSET, src.length); | |
} | |
} | |
private static class DirectUnsafeRunnable extends UnsafeRunnable { | |
public DirectUnsafeRunnable(ByteBuffer src) { | |
super(null, ((DirectBuffer) src).address(), src.limit()); | |
} | |
} | |
private static abstract class UnsafeAbstractRunnable implements Runnable { | |
protected static final Unsafe unsafe; | |
public int v32; | |
public long v64; | |
static { | |
try { | |
Field field = Unsafe.class.getDeclaredField("theUnsafe"); | |
field.setAccessible(true); | |
unsafe = (Unsafe) field.get(null); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
protected final Object base; | |
protected final long address; | |
protected final int length; | |
public UnsafeAbstractRunnable(Object base, long address, int length) { | |
this.base = base; | |
this.address = address; | |
this.length = length; | |
} | |
public void run() { | |
int last = length - 9; | |
for(int i=0; i < last; i++) { | |
byte b = getByte(i); | |
i++; | |
if(b < 0) { | |
v32 = getInt(i); | |
i += 4; | |
} else { | |
v64 = getLong(i); | |
i += 8; | |
} | |
} | |
} | |
public abstract byte getByte(int i); | |
public abstract int getInt(int i); | |
public abstract long getLong(int i); | |
} | |
private static class HeapUnsafeAbstractRunnable extends UnsafeAbstractRunnable { | |
public HeapUnsafeAbstractRunnable(byte[] src) { | |
super(src, Unsafe.ARRAY_BYTE_BASE_OFFSET, src.length); | |
} | |
@Override | |
public byte getByte(int i) { | |
return unsafe.getByte(base, address + i); | |
} | |
@Override | |
public int getInt(int i) { | |
return unsafe.getByte(base, address + i); | |
} | |
@Override | |
public long getLong(int i) { | |
return unsafe.getByte(base, address + i); | |
} | |
} | |
private static class DirectUnsafeAbstractRunnable extends UnsafeAbstractRunnable { | |
public DirectUnsafeAbstractRunnable(ByteBuffer src) { | |
super(null, ((DirectBuffer) src).address(), src.limit()); | |
} | |
@Override | |
public byte getByte(int i) { | |
return unsafe.getByte(base, address + i); | |
} | |
@Override | |
public int getInt(int i) { | |
return unsafe.getByte(base, address + i); | |
} | |
@Override | |
public long getLong(int i) { | |
return unsafe.getByte(base, address + i); | |
} | |
} | |
private static class HeapUnsafeSpecialInputRunnable implements Runnable { | |
private final UnsafeBufferSpecialInput input; | |
public int v32; | |
public long v64; | |
public HeapUnsafeSpecialInputRunnable(byte[] src) { | |
this.input = new UnsafeBufferSpecialInput( | |
new UnsafeBuffer(src)); | |
} | |
public void run() { | |
input.reset(); | |
try { | |
while(true) { | |
byte b = input.readByte(); | |
if(b < 0) { | |
v32 = input.readInt(); | |
} else { | |
v64 = input.readLong(); | |
} | |
} | |
} catch (IndexOutOfBoundsException ex) { | |
} | |
} | |
} | |
private static class HeapUnsafeInterfaceInputRunnable implements Runnable { | |
private final PartialDataInput input; | |
public int v32; | |
public long v64; | |
public HeapUnsafeInterfaceInputRunnable(byte[] src) { | |
new NullDataInput(); // load class | |
this.input = new UnsafeBufferDataInput( | |
new UnsafeBuffer(src)); | |
} | |
public void run() { | |
((UnsafeBufferSpecialInput) input).reset(); | |
try { | |
while(true) { | |
byte b = input.readByte(); | |
if(b < 0) { | |
v32 = input.readInt(); | |
} else { | |
v64 = input.readLong(); | |
} | |
} | |
} catch (IndexOutOfBoundsException ex) { | |
} catch (IOException ex) { | |
} | |
} | |
} | |
public class HeapUnsafeBufferRunnable implements Runnable { | |
private UnsafeBuffer buffer; | |
private int position; | |
public int v32; | |
public long v64; | |
public HeapUnsafeBufferRunnable(byte[] src) { | |
this.buffer = new UnsafeBuffer(src); | |
} | |
public void run() { | |
int last = buffer.getSize() - 9; | |
for(int i=0; i < last; i++) { | |
byte b = buffer.getByte(i); | |
i++; | |
if(b < 0) { | |
v32 = buffer.getInt(i); | |
i += 4; | |
} else { | |
v64 = buffer.getLong(i); | |
i += 8; | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: run | |
DeserBenchmark.class: DeserBenchmark.java | |
javac *.java | |
deser_benchmark: deser_benchmark.c | |
gcc -Wall deser_benchmark.c --std=c99 -O2 -DLOOP=1000 -o deser_benchmark | |
run: DeserBenchmark.class deser_benchmark | |
java -cp . DeserBenchmark 1700461846 10000000 1000 | |
./deser_benchmark | |
clean: | |
rm -f *.class | |
rm -f random.data | |
rm -f deser_benchmark | |
.PHONY: clean run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
public class NullDataInput implements PartialDataInput { | |
public byte readByte() throws IOException { | |
return (byte) 0; | |
} | |
public int readInt() throws IOException { | |
return 0; | |
} | |
public long readLong() throws IOException { | |
return 0L; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
public interface PartialDataInput { | |
public byte readByte() throws IOException; | |
public int readInt() throws IOException; | |
public long readLong() throws IOException; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
seed: 1700461846 | |
size: 100000000 bytes | |
loop: 1000 times | |
-- Unsafe heap | |
65.84 msec/loop | |
1448.38 MB/s | |
-- Unsafe special input heap | |
139.71 msec/loop | |
682.63 MB/s | |
-- Unsafe interface input heap | |
130.43 msec/loop | |
731.16 MB/s | |
-- Unsafe buffer heap | |
88.62 msec/loop | |
1076.09 MB/s | |
-- Unsafe heap | |
65.67 msec/loop | |
1452.29 MB/s | |
-- Unsafe special input heap | |
138.48 msec/loop | |
688.67 MB/s | |
-- Unsafe interface input heap | |
129.66 msec/loop | |
735.50 MB/s | |
-- Unsafe buffer heap | |
87.40 msec/loop | |
1091.20 MB/s | |
-- Unsafe heap | |
65.73 msec/loop | |
1450.85 MB/s | |
-- Unsafe special input heap | |
138.49 msec/loop | |
688.62 MB/s | |
-- Unsafe interface input heap | |
129.75 msec/loop | |
735.04 MB/s | |
-- Unsafe buffer heap | |
87.48 msec/loop | |
1090.19 MB/s | |
-- Unsafe heap | |
65.66 msec/loop | |
1452.55 MB/s | |
-- Unsafe special input heap | |
138.41 msec/loop | |
689.05 MB/s | |
-- Unsafe interface input heap | |
129.94 msec/loop | |
733.93 MB/s | |
-- Unsafe buffer heap | |
87.45 msec/loop | |
1090.59 MB/s |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sun.misc.Unsafe; | |
import sun.nio.ch.DirectBuffer; | |
import java.lang.reflect.Field; | |
import java.nio.ByteBuffer; | |
import java.io.File; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
public final class UnsafeBuffer { | |
private static final Unsafe unsafe; | |
static { | |
try { | |
Field field = Unsafe.class.getDeclaredField("theUnsafe"); | |
field.setAccessible(true); | |
unsafe = (Unsafe) field.get(null); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private final Object base; | |
private final long address; | |
private final int size; | |
public UnsafeBuffer(byte[] src) { | |
this(src, Unsafe.ARRAY_BYTE_BASE_OFFSET, src.length); | |
} | |
public UnsafeBuffer(ByteBuffer src) { | |
this(null, ((DirectBuffer) src).address(), src.limit()); | |
} | |
public UnsafeBuffer(Object base, long address, int size) { | |
this.base = base; | |
this.address = address; | |
this.size = size; | |
} | |
public int getSize() { | |
return size; | |
} | |
public byte getByte(int position) { | |
if(size <= position) { | |
throw new IndexOutOfBoundsException(); | |
} | |
return unsafe.getByte(base, address + position); | |
} | |
public int getInt(int position) { | |
if(size <= position - 4) { | |
throw new IndexOutOfBoundsException(); | |
} | |
return unsafe.getInt(base, address + position); | |
} | |
public long getLong(int position) { | |
if(size <= position - 8) { | |
throw new IndexOutOfBoundsException(); | |
} | |
return unsafe.getLong(base, address + position); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UnsafeBufferDataInput extends UnsafeBufferSpecialInput implements PartialDataInput { | |
public UnsafeBufferDataInput(UnsafeBuffer buffer) { | |
super(buffer); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UnsafeBufferSpecialInput { | |
private UnsafeBuffer buffer; | |
private int position; | |
public UnsafeBufferSpecialInput(UnsafeBuffer buffer) { | |
this.buffer = buffer; | |
this.position = 0; | |
} | |
public final void reset() { | |
this.position = 0; | |
} | |
public final byte readByte() { | |
byte v = buffer.getByte(position); | |
position += 1; | |
return v; | |
} | |
public final int readInt() { | |
int v = buffer.getInt(position); | |
position += 4; | |
return v; | |
} | |
public final long readLong() { | |
long v = buffer.getLong(position); | |
position += 8; | |
return v; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment