Skip to content

Instantly share code, notes, and snippets.

@frsyuki
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frsyuki/ddde844f87ea0aa33e7e to your computer and use it in GitHub Desktop.
Save frsyuki/ddde844f87ea0aa33e7e to your computer and use it in GitHub Desktop.
unsafe-test-2
#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);
}
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;
}
}
}
}
}
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
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;
}
}
import java.io.IOException;
public interface PartialDataInput {
public byte readByte() throws IOException;
public int readInt() throws IOException;
public long readLong() throws IOException;
}
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
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);
}
}
public class UnsafeBufferDataInput extends UnsafeBufferSpecialInput implements PartialDataInput {
public UnsafeBufferDataInput(UnsafeBuffer buffer) {
super(buffer);
}
}
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