[#2685] Epoll transport should use GetPrimitiveArrayCritical / ReleasePrimitiveArrayCritical
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.
This commit is contained in:
parent
695fbc9140
commit
512d1a11ff
@ -162,9 +162,17 @@ jobject createDatagramSocketAddress(JNIEnv * env, struct sockaddr_storage addr,
|
|||||||
return socketAddr;
|
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);
|
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) {
|
if (socketType == AF_INET6) {
|
||||||
struct sockaddr_in6* ip6addr = (struct sockaddr_in6 *) addr;
|
struct sockaddr_in6* ip6addr = (struct sockaddr_in6 *) addr;
|
||||||
ip6addr->sin6_family = AF_INET6;
|
ip6addr->sin6_family = AF_INET6;
|
||||||
@ -181,7 +189,8 @@ void init_sockaddr(JNIEnv * env, jbyteArray address, jint scopeId, jint jport, s
|
|||||||
memcpy( &(ipaddr->sin_addr.s_addr), addressBytes + 12, 4);
|
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() {
|
static int socket_type() {
|
||||||
@ -197,14 +206,23 @@ static int socket_type() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_in_addr(JNIEnv * env, jbyteArray address, struct in_addr * addr) {
|
int init_in_addr(JNIEnv * env, jbyteArray address, struct in_addr * addr) {
|
||||||
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) {
|
if (socketType == AF_INET6) {
|
||||||
memcpy(addr, addressBytes, 16);
|
memcpy(addr, addressBytes, 16);
|
||||||
} else {
|
} else {
|
||||||
memcpy(addr, addressBytes + 12, 4);
|
memcpy(addr, addressBytes + 12, 4);
|
||||||
}
|
}
|
||||||
(*env)->ReleaseByteArrayElements(env, address, addressBytes, JNI_ABORT);
|
(*env)->ReleasePrimitiveArrayCritical(env, address, addressBytes, JNI_ABORT);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
// util methods end
|
// util methods end
|
||||||
|
|
||||||
@ -496,7 +514,10 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollWait(JNIEnv * env
|
|||||||
}
|
}
|
||||||
|
|
||||||
jboolean isCopy;
|
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) {
|
if (elements == NULL) {
|
||||||
// No memory left ?!?!?
|
// No memory left ?!?!?
|
||||||
throwOutOfMemoryError(env, "Can't allocate memory");
|
throwOutOfMemoryError(env, "Can't allocate memory");
|
||||||
@ -524,7 +545,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.
|
// was just pinned so use JNI_ABORT to eliminate not needed copy.
|
||||||
mode = JNI_ABORT;
|
mode = JNI_ABORT;
|
||||||
}
|
}
|
||||||
(*env)->ReleaseLongArrayElements(env, events, elements, mode);
|
(*env)->ReleasePrimitiveArrayCritical(env, events, elements, mode);
|
||||||
|
|
||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
@ -590,7 +611,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) {
|
jint sendTo0(JNIEnv * env, jint fd, void* buffer, jint pos, jint limit ,jbyteArray address, jint scopeId, jint port) {
|
||||||
struct sockaddr_storage addr;
|
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;
|
ssize_t res;
|
||||||
int err;
|
int err;
|
||||||
@ -847,7 +870,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) {
|
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;
|
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){
|
if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1){
|
||||||
int err = errno;
|
int err = errno;
|
||||||
@ -864,7 +889,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) {
|
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;
|
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 res;
|
||||||
int err;
|
int err;
|
||||||
|
Loading…
Reference in New Issue
Block a user