Threading and Yieldpoints

Note: The first paragraph is outdated. Jikes RVM uses native threading since 3.1.0: For every Java thread, an instance of RVMThread is created which maps directly to a pthread (see start()in RVMThread). The current implementation of yieldpoints is similar to the one described here.

For each physical processor on the system, the system creates a pthread. Each pthread is associated with a virtual processor object that  executes one or more Java threads in a quasi-preemptive manner, as follows. Each compiler generates yield points, which are program points where the running thread checks a dedicated bit in the virtual processor object to determine if it should yield to another thread. The compilers insert yield points in method prologues, method epilogues, and on loop backedges. Currently, the system sets the thread-switch bit approximately every 10ms.

The adaptive optimization system piggybacks on this yieldpoint mechanism to gather profile data. The thread scheduler provides an

extension point by which the runtime measurments component can install listeners that execute each time a yieldpoint is taken. Such listeners primarily serve to sample program execution to identify frequently-executed methods and call edges. Because these samples occur at well-known locations (prologues, epilogues, and loop backedges), the listener can easily attribute each sample to the appropriate

Java source method.

The Jikes RVM implementation introduces a weakness with this mechanism, in that samples can only occur in regions of code that have yieldpoints.  Some low-level Jikes RVM subsystems, such as the thread scheduler and the garbage collector, elide yieldpoints because

those regions of code rely on delicate state invariants that preclude thread switching. These uninterruptible regions can distort sampling accuracy by artificially inflating the probability of sampling  the first yieldpoint executed after the program leaves an uninterruptible region of code.