[rvm-research] Implementation of setPriority/getPriority for RVMThread (RVM-750)
Carl Ritson <[email protected]>
| Newsgroups | gmane.comp.java.jikes.rvm.devel |
|---|---|
| Message-ID | <CAKDym5POGG3DK+DTVw2_oVpsnHDrn9+_G=w4dY+0jQA3acpXig@mail.gmail.com> |
Hi, Please find attached a patch which implements thread priority on RVMThreads at the OS level. This addresses RVM-750. Where possible this uses pthread_setschedparam() to set the thread priority via the POSIX threads API. On Linux it is necessary to use setpriority() to manipulate the nice level of the thread instead, at least for threads running in the default SCHED_OTHER policy. In order to support this the thread ID (thread's process id) must be obtained using the gettid() syscall. The attached patch does this during the usual thread start up code and adds a field to RVMThread instances to store this. One side effect of this method is that it is not possible to achieve priorities higher than NORM_PRIORITY on Linux without root access (or changing the scheduling policy). This method is similar to OpenJDK, although OpenJDK does not attempt to fallback to setpriority() on Linux unless the appropriate flags are passed to the JVM and it is run as root (even to access lower priorities). I've tested this patch on Ubuntu 12.04LTS and OS X 10.8. Kind regards, Carl ------------------------------------------------------------------------------ See everything from the browser to the database with AppDynamics Get end-to-end visibility with application monitoring from AppDynamics Isolate bottlenecks and diagnose root cause in seconds. Start your free trial of AppDynamics Pro today! http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk _______________________________________________ Jikesrvm-researchers mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/jikesrvm-researchers
thread-priority.r10655.diff
(application/octet-stream, 7.6 KB)
diff -r 6ea4feda95a5 rvm/src/org/jikesrvm/VM.java
--- a/rvm/src/org/jikesrvm/VM.java Mon Jul 22 19:47:09 2013 +0200
+++ b/rvm/src/org/jikesrvm/VM.java Wed Jul 24 14:14:44 2013 +0100
@@ -160,6 +160,7 @@
//
sysCall.sysSetupHardwareTrapHandler();
RVMThread.getCurrentThread().pthread_id = sysCall.sysGetThreadId();
+ RVMThread.getCurrentThread().priority_handle = sysCall.sysGetThreadPriorityHandle();
RVMThread.availableProcessors = SysCall.sysCall.sysNumProcessors();
// Set up buffer locks used by Thread for logging and status dumping.
diff -r 6ea4feda95a5 rvm/src/org/jikesrvm/runtime/BootRecord.java
--- a/rvm/src/org/jikesrvm/runtime/BootRecord.java Mon Jul 22 19:47:09 2013 +0200
+++ b/rvm/src/org/jikesrvm/runtime/BootRecord.java Wed Jul 24 14:14:44 2013 +0100
@@ -262,6 +262,9 @@
public Address sysSetupHardwareTrapHandlerIP;
public Address sysStashVMThreadIP;
public Address sysThreadTerminateIP;
+ public Address sysGetThreadPriorityHandleIP;
+ public Address sysGetThreadPriorityIP;
+ public Address sysSetThreadPriorityIP;
// monitors
public Address sysMonitorCreateIP;
diff -r 6ea4feda95a5 rvm/src/org/jikesrvm/runtime/SysCall.java
--- a/rvm/src/org/jikesrvm/runtime/SysCall.java Mon Jul 22 19:47:09 2013 +0200
+++ b/rvm/src/org/jikesrvm/runtime/SysCall.java Wed Jul 24 14:14:44 2013 +0100
@@ -190,6 +190,15 @@
public abstract Word sysGetThreadId();
@SysCallTemplate
+ public abstract Word sysGetThreadPriorityHandle();
+
+ @SysCallTemplate
+ public abstract int sysGetThreadPriority(Word thread, Word handle);
+
+ @SysCallTemplate
+ public abstract int sysSetThreadPriority(Word thread, Word handle, int priority);
+
+ @SysCallTemplate
public abstract void sysSetupHardwareTrapHandler();
// This implies that the RVMThread is somehow pinned, or else the
diff -r 6ea4feda95a5 rvm/src/org/jikesrvm/scheduler/RVMThread.java
--- a/rvm/src/org/jikesrvm/scheduler/RVMThread.java Mon Jul 22 19:47:09 2013 +0200
+++ b/rvm/src/org/jikesrvm/scheduler/RVMThread.java Wed Jul 24 14:14:44 2013 +0100
@@ -1025,6 +1025,12 @@
public Word pthread_id;
/**
+ * Thread priority handle. Used when manipulating the threads priority.
+ * This may be different from pthread_id.
+ */
+ public Word priority_handle;
+
+ /**
* Scratch area for use for gpr <=> fpr transfers by PPC baseline compiler.
* Used to transfer x87 to SSE registers on IA32
*/
@@ -2590,6 +2596,14 @@
* get pthread_id from the operating system and store into RVMThread field
*/
currentThread.pthread_id = sysCall.sysGetThreadId();
+ currentThread.priority_handle = sysCall.sysGetThreadPriorityHandle();
+
+ /*
+ * set thread priority to match stored value
+ */
+ sysCall.sysSetThreadPriority(currentThread.pthread_id,
+ currentThread.priority_handle, currentThread.priority - Thread.NORM_PRIORITY);
+
currentThread.enableYieldpoints();
sysCall.sysStashVMThread(currentThread);
if (traceAcct) {
@@ -4471,6 +4485,10 @@
* @see java.lang.Thread#getPriority()
*/
public int getPriority() {
+ if (isAlive()) {
+ // compute current priority
+ priority = sysCall.sysGetThreadPriority(pthread_id, priority_handle) + Thread.NORM_PRIORITY;
+ }
return priority;
}
@@ -4481,8 +4499,15 @@
* @see java.lang.Thread#getPriority()
*/
public void setPriority(int priority) {
- this.priority = priority;
- // @TODO this should be calling a syscall
+ if (isAlive()) {
+ if (sysCall.sysSetThreadPriority(pthread_id, priority_handle, priority - Thread.NORM_PRIORITY) == 0) {
+ this.priority = priority;
+ } else {
+ // setting priority failed
+ }
+ } else {
+ this.priority = priority;
+ }
}
/**
diff -r 6ea4feda95a5 tools/bootImageRunner/sys.C
--- a/tools/bootImageRunner/sys.C Mon Jul 22 19:47:09 2013 +0200
+++ b/tools/bootImageRunner/sys.C Wed Jul 24 14:14:44 2013 +0100
@@ -34,6 +34,11 @@
extern "C" int sched_yield(void);
#endif
+// Enable syscall on Linux / glibc
+#ifdef RVM_FOR_LINUX
+#define _GNU_SOURCE
+#endif
+
#include <stdio.h>
#include <stdlib.h> // getenv() and others
#include <unistd.h>
@@ -71,6 +76,7 @@
#include <sys/ioctl.h>
#ifdef RVM_FOR_LINUX
#include <asm/ioctls.h>
+#include <sys/syscall.h>
#endif
# include <sched.h>
@@ -1248,6 +1254,104 @@
#endif
}
+// Determine if a given thread can use pthread_setschedparam to
+// configure its priority, this is based on the current priority
+// of the thread.
+//
+// The result will be true on all systems other than Linux where
+// pthread_setschedparam cannot be used with SCHED_OTHER policy.
+//
+static int hasPthreadPriority(Word thread_id)
+{
+ struct sched_param param;
+ int policy;
+ if (!pthread_getschedparam((pthread_t)thread_id, &policy, ¶m)) {
+ int min = sched_get_priority_min(policy);
+ int max = sched_get_priority_max(policy);
+ if (min || max) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// Return a handle which can be used to manipulate a threads priority
+// on Linux this will be the kernel thread_id, on other systems the
+// standard thread id.
+extern "C" Word
+sysGetThreadPriorityHandle()
+{
+ // gettid() syscall is Linux specific, detect its syscall number macro
+ #ifdef SYS_gettid
+ pid_t tid = (pid_t) syscall(SYS_gettid);
+ if (tid != -1)
+ return (Word) tid;
+ #endif /* SYS_gettid */
+ return (Word) getThreadId();
+}
+
+// Compute the default (or middle) priority for a given policy.
+static int defaultPriority(int policy)
+{
+ int min = sched_get_priority_min(policy);
+ int max = sched_get_priority_max(policy);
+ return min + ((max - min) / 2);
+}
+
+// Get the thread priority as an offset from the default.
+extern "C" int
+sysGetThreadPriority(Word thread, Word handle)
+{
+ // use pthread priority mechanisms where possible
+ if (hasPthreadPriority(thread)) {
+ struct sched_param param;
+ int policy;
+ if (!pthread_getschedparam((pthread_t)thread, &policy, ¶m)) {
+ return param.sched_priority - defaultPriority(policy);
+ }
+ } else if (thread != handle) {
+ // fallback to setpriority if handle is valid
+ // i.e. handle is tid from gettid()
+ int result;
+ errno = 0; // as result can be legally be -1
+ result = getpriority(PRIO_PROCESS, (int) handle);
+ if (errno == 0) {
+ // default priority is 0, low number -> high priority
+ return -result;
+ }
+
+ }
+ return 0;
+}
+
+// Set the thread priority as an offset from the default.
+extern "C" int
+sysSetThreadPriority(Word thread, Word handle, int priority)
+{
+ // fast path
+ if (sysGetThreadPriority(thread, handle) == priority)
+ return 0;
+
+ // use pthread priority mechanisms where possible
+ if (hasPthreadPriority(thread)) {
+ struct sched_param param;
+ int policy;
+ int result = pthread_getschedparam((pthread_t)thread, &policy, ¶m);
+ if (!result) {
+ param.sched_priority = defaultPriority(policy) + priority;
+ return pthread_setschedparam((pthread_t)thread, policy, ¶m);
+ } else {
+ return result;
+ }
+ } else if (thread != handle) {
+ // fallback to setpriority if handle is valid
+ // i.e. handle is tid from gettid()
+ // default priority is 0, low number -> high priority
+ return setpriority(PRIO_PROCESS, (int) handle, -priority);
+ }
+ return -1;
+}
+
////////////// Pthread mutex and condition functions /////////////
#ifndef RVM_FOR_HARMONY