Monday, April 28, 2008

Java's Thread Priorities in Linux

As I told yesterday, Sun Java 5/6 has a "broken" priority policy for linux. There is a related bug in java's bugtracking system. So if to mention it briefly, there are two thread priority policies for linux. The first one, with code 0, specifies to ignore all thread priorities at all making all threads equal for linux scheduler. The second policy model, with code 1, maps java priorities to calls to the system setpriority function. By default java uses thread priority policy 0. You can say java to use policy 1 by invoking it with -XX:ThreadPriorityPolicy=1 command line argument. Unfortunately, this will work only if you start java with root privileges because the setpriority function sets nice level for processes and a process can't lower a nice level. This is a bad news. The good news is that Sun's java has another bug (I hope this bug will not be fixed). Look at the following code from the java 6 update 3 (build 105) sources (os_linux.cpp):
  if (ThreadPriorityPolicy == 1) {
// Only root can raise thread priority. Don't allow ThreadPriorityPolicy=1
// if effective uid is not root. Perhaps, a more elegant way of doing
// this is to test CAP_SYS_NICE capability, but that will require libcap.so
if (geteuid() != 0) {
if (!FLAG_IS_DEFAULT(ThreadPriorityPolicy)) {
warning("-XX:ThreadPriorityPolicy requires root privilege on Linux");
}
ThreadPriorityPolicy = 0;
}
}

It is meant to reset command line argument from 1 to 0 if the effective user is not root.

Look here:
OSReturn os::set_native_priority(Thread* thread, int newpri) {
if ( !UseThreadPriorities || ThreadPriorityPolicy == 0 ) return OS_OK;

int ret = setpriority(PRIO_PROCESS, thread->osthread()->thread_id(), newpri);
return (ret == 0) ? OS_OK : OS_ERR;
}

OSReturn os::get_native_priority(const Thread* const thread, int *priority_ptr) {
if ( !UseThreadPriorities || ThreadPriorityPolicy == 0 ) {
*priority_ptr = java_to_os_priority[NormPriority];
return OS_OK;
}
...
}

I've highlighted the interesting code. Do you see how it checks for policy? It means that if we set ThreadPriorityPolicy to ... say to 666, java will still work like the policy is set to 1. And the check that resets ThreadPriorityPolicy from 1 to 0 for non-root users will not be triggered. Whee! So in fact we can use the policy 1 for non-root users running java with the command line argument -XX:ThreadPriorityPolicy=666. But stop would say you, what will it give us if the system's setpriority function fails for non-root user? It gives us enough if we can run our lovely java initially with nice level -5. A level -5 is the nice level used for HIGHEST priority threads in java as you can see from the following code snippet:
int os::java_to_os_priority[MaxPriority + 1] = {
19, // 0 Entry should never be used

4, // 1 MinPriority
3, // 2
2, // 3

1, // 4
0, // 5 NormPriority
-1, // 6

-2, // 7
-3, // 8
-4, // 9 NearMaxPriority

-5 // 10 MaxPriority
};

Though this looks not fair and totally unholy, I think it is still better then running java with priorities ignored or under root. Thus you can run your java safely and well-scheduled with the command like this:
nice -n -5 su -c 'java -XX:ThreadPriorityPolicy=666 ThreadTester' akshaal

There is other way if you have no access to root user.
java -XX:ThreadPriorityPolicy=666 \
-XX:JavaPriority10_To_OSPriority=0 \
-XX:JavaPriority9_To_OSPriority=1 \
-XX:JavaPriority8_To_OSPriority=2 \
-XX:JavaPriority7_To_OSPriority=3 \
-XX:JavaPriority6_To_OSPriority=4 \
-XX:JavaPriority5_To_OSPriority=5 \
-XX:JavaPriority4_To_OSPriority=6 \
-XX:JavaPriority3_To_OSPriority=7 \
-XX:JavaPriority2_To_OSPriority=8 \
-XX:JavaPriority1_To_OSPriority=9 \
ThreadTester
The drawbacks of this method is that your normal priority threads will run with nice level 5 (although threads with the highest level will run with nice level 0 and lowest priority thread with nice level 9). That is it. Enjoy while these bugs (or features) are not fixed yet :).

1 comment:

  1. Hi. I am developing a real-time system using regular JVM (no RTJS please) and I would like to give my thread the highest possible priority. Can I do that as root and using the new -XX:ThreadPriorityPolicy=666 ? Thanks!

    ReplyDelete