[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, &param)) {
+        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, &param)) {
+            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, &param);
+        if (!result) {
+            param.sched_priority = defaultPriority(policy) + priority;
+            return pthread_setschedparam((pthread_t)thread, policy, &param);
+        } 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.