Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
#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);
measure("ByteBuffer heap", size, loop, new ByteBufferRunnable(heap));
measure("ByteBuffer direct", size, loop, new ByteBufferRunnable(direct));
measure("Unsafe heap", size, loop, new HeapUnsafeRunnable(bytes));
measure("Unsafe direct", size, loop, new DirectUnsafeRunnable(direct));
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;
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);
}
}
private Object base;
private long address;
private int length;
public UnsafeRunnable(Object base, long address, int length) {
this.base = base;
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(src, ((DirectBuffer) src).address(), src.limit());
}
}
}
all: run
DeserBenchmark.class: DeserBenchmark.java
javac DeserBenchmark.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
seed: 1700461846
size: 10000000 bytes
loop: 1000 times
-- ByteBuffer heap
12.81 msec/loop
744.59 MB/s
-- ByteBuffer direct
8.99 msec/loop
1061.29 MB/s
-- Unsafe heap
6.41 msec/loop
1488.95 MB/s
-- Unsafe direct
6.44 msec/loop
1481.55 MB/s
-- C load
5.91 msec/loop
1614.67 MB/s
-- C shift
6.95 msec/loop
1371.69 MB/s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment