Last active
May 20, 2021 09:21
-
-
Save frsyuki/9502028 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 hidden or 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); | |
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()); | |
} | |
} | |
} |
This file contains hidden or 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 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 |
This file contains hidden or 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: 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