Skip to content

Commit

Permalink
[netty#2685] Epoll transport should use GetPrimitiveArrayCritical / R…
Browse files Browse the repository at this point in the history
…eleasePrimitiveArrayCritical

Motivation:

At the moment we use Get*ArrayElement all the time in the epoll transport which may be wasteful as the JVM may do a memory copy for this. For code-path that will get executed fast (without blocking) we should better make use of GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical as this signal the JVM that we not want to do any memory copy if not really needed. It is important to only do this on non-blocking code-path as this may even suspend the GC to disallow the JVM to move the arrays around.

See also http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#GetPrimitiveArrayCritical

Modification:

Make use of GetPrimitiveArrayCritical / ReleasePrimitiveArrayCritical as replacement for Get*ArrayElement / Release*ArrayElement where possible.

Result:

Better performance due less memory copies.
  • Loading branch information
Norman Maurer committed Jul 21, 2014
1 parent 0281289 commit eb34cbb
Showing 1 changed file with 38 additions and 11 deletions.
49 changes: 38 additions & 11 deletions transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,17 @@ jobject createDatagramSocketAddress(JNIEnv * env, struct sockaddr_storage addr,
return socketAddr;
}

void init_sockaddr(JNIEnv * env, jbyteArray address, jint scopeId, jint jport, struct sockaddr_storage * addr) {
int init_sockaddr(JNIEnv * env, jbyteArray address, jint scopeId, jint jport, struct sockaddr_storage * addr) {
uint16_t port = htons((uint16_t) jport);
jbyte* addressBytes = (*env)->GetByteArrayElements(env, address, 0);
// Use GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical to signal the VM that we really would like
// to not do a memory copy here. This is ok as we not do any blocking action here anyway.
// This is important as the VM may suspend GC for the time!
jbyte* addressBytes = (*env)->GetPrimitiveArrayCritical(env, address, 0);
if (addressBytes == NULL) {
// No memory left ?!?!?
throwOutOfMemoryError(env, "Can't allocate memory");
return -1;
}
if (socketType == AF_INET6) {
struct sockaddr_in6* ip6addr = (struct sockaddr_in6 *) addr;
ip6addr->sin6_family = AF_INET6;
Expand All @@ -178,7 +186,8 @@ void init_sockaddr(JNIEnv * env, jbyteArray address, jint scopeId, jint jport, s
memcpy( &(ipaddr->sin_addr.s_addr), addressBytes + 12, 4);
}

(*env)->ReleaseByteArrayElements(env, address, addressBytes, JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, address, addressBytes, JNI_ABORT);
return 0;
}

static int socket_type() {
Expand All @@ -194,14 +203,23 @@ static int socket_type() {
}
}

void init_in_addr(JNIEnv * env, jbyteArray address, struct in_addr * addr) {
jbyte* addressBytes = (*env)->GetByteArrayElements(env, address, 0);
int init_in_addr(JNIEnv * env, jbyteArray address, struct in_addr * addr) {
// Use GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical to signal the VM that we really would like
// to not do a memory copy here. This is ok as we not do any blocking action here anyway.
// This is important as the VM may suspend GC for the time!
jbyte* addressBytes = (*env)->GetPrimitiveArrayCritical(env, address, 0);
if (addressBytes == NULL) {
// No memory left ?!?!?
throwOutOfMemoryError(env, "Can't allocate memory");
return -1;
}
if (socketType == AF_INET6) {
memcpy(addr, addressBytes, 16);
} else {
memcpy(addr, addressBytes + 12, 4);
}
(*env)->ReleaseByteArrayElements(env, address, addressBytes, JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, address, addressBytes, JNI_ABORT);
return 0;
}
// util methods end

Expand Down Expand Up @@ -471,7 +489,10 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollWait(JNIEnv * env
}

jboolean isCopy;
jlong *elements = (*env)->GetLongArrayElements(env, events, &isCopy);
// Use GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical to signal the VM that we really would like
// to not do a memory copy here. This is ok as we not do any blocking action here anyway.
// This is important as the VM may suspend GC for the time!
jlong *elements = (*env)->GetPrimitiveArrayCritical(env, events, &isCopy);
if (elements == NULL) {
// No memory left ?!?!?
throwOutOfMemoryError(env, "Can't allocate memory");
Expand Down Expand Up @@ -499,7 +520,7 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollWait(JNIEnv * env
// was just pinned so use JNI_ABORT to eliminate not needed copy.
mode = JNI_ABORT;
}
(*env)->ReleaseLongArrayElements(env, events, elements, mode);
(*env)->ReleasePrimitiveArrayCritical(env, events, elements, mode);

return ready;
}
Expand Down Expand Up @@ -565,7 +586,9 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_writeAddress(JNIEnv *

jint sendTo0(JNIEnv * env, jint fd, void* buffer, jint pos, jint limit ,jbyteArray address, jint scopeId, jint port) {
struct sockaddr_storage addr;
init_sockaddr(env, address, scopeId, port, &addr);
if (init_sockaddr(env, address, scopeId, port, &addr) == -1) {
return -1;
}

ssize_t res;
int err;
Expand Down Expand Up @@ -793,7 +816,9 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_socketStream(JNIEnv *

JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_bind(JNIEnv * env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port) {
struct sockaddr_storage addr;
init_sockaddr(env, address, scopeId, port, &addr);
if (init_sockaddr(env, address, scopeId, port, &addr) == -1) {
return -1;
}

if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1){
int err = errno;
Expand All @@ -810,7 +835,9 @@ JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_listen(JNIEnv * env, j

JNIEXPORT jboolean JNICALL Java_io_netty_channel_epoll_Native_connect(JNIEnv * env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port) {
struct sockaddr_storage addr;
init_sockaddr(env, address, scopeId, port, &addr);
if (init_sockaddr(env, address, scopeId, port, &addr) == -1) {
return -1;
}

int res;
int err;
Expand Down

0 comments on commit eb34cbb

Please sign in to comment.