The Pinned Thread Difference

To illustrate the advantage of a pinned thread, we code a program that launches a bunch of threads to do a simple task and pin one of them to a processor. At the end you can see that the pinned thread is much ahead of the other threads. That’s because the other threads have to compete for the available processors while the pinned thread has a whole processor for itself. Without context switches and interruptions the pinned thread can perform its job much faster than the other ones.

import com.coralblocks.coralthreads.Affinity;
import com.coralblocks.coralbits.util.SystemUtils;

public class ManyThreads {
	
	public static void main(String[] args) throws Exception {
		
		final int nThreads = SystemUtils.getInt("nThreads", 20);
		final int threadToBind = SystemUtils.getInt("threadToBind", 10);
		final int procToBind = SystemUtils.getInt("procToBind", 2);
		final long maxLong = SystemUtils.getLong("maxLong", 1000000000L);
		
		class PinnedThread extends Thread {
			
			long overlaps = 0;
			long count = 0;
			volatile boolean running = true;
			
			PinnedThread(String name) {
				super(name);
			}
			
			void stopMe() {
				running = false;
			}
			
			@Override
            public void run() {

				Affinity.bind();
				
				try {
					while(running) {
						if (count++ == maxLong) {
							overlaps++;
							count = 0;
						}
					}
				} finally {
					Affinity.unbind();
				}
            }
		}
		
		final PinnedThread[] threads = new PinnedThread[nThreads];
		
		for(int i = 0; i < threads.length; i++) {
			
			threads[i] = new PinnedThread(i == threadToBind ? "PinnedThread" : "Thread" + i);
		}	
			
		if (procToBind >= 0) Affinity.assignToProcessor(procToBind, threads[threadToBind]);
		
		for(PinnedThread t : threads) t.start();
		
		System.out.println();
		Affinity.printSituation();
		
		Runtime.getRuntime().addShutdownHook(new Thread() {
			
			@Override
			public void run() {

				for(PinnedThread t : threads) t.stopMe();
				for(PinnedThread t : threads) try { t.join(); } catch(Exception e) { }
				
				System.out.println();
				
				for(PinnedThread t : threads) {
					System.out.println(t.getName() + ": overlaps=" + t.overlaps + " count=" + t.count);
				}
			}
		});
	}
}

The output:

$ java -cp coralthreads-all.jar com.coralblocks.coralthreads.sample.ManyThreads

CpuInfo: [nChips=1, nCoresPerChip=4, hyper-threading=true, nProcessors=8, procIds=0,1,2,3,4,5,6,7]

Chip-0:
    Core-0:
        Processor-0: free
        Processor-4: free
    Core-1:
        Processor-1: free
        Processor-5: free
    Core-2:
        Processor-2: bound to PinnedThread (running pid=3406)
        Processor-6: free
    Core-3:
        Processor-3: free
        Processor-7: free

^C
Thread0: overlaps=18 count=219401874
Thread1: overlaps=19 count=261705318
Thread2: overlaps=18 count=610599006
Thread3: overlaps=18 count=134022214
Thread4: overlaps=18 count=706525436
Thread5: overlaps=18 count=53884487
Thread6: overlaps=17 count=614235810
Thread7: overlaps=18 count=288563757
Thread8: overlaps=18 count=437900710
Thread9: overlaps=18 count=913959165
PinnedThread: overlaps=87 count=402690338
Thread11: overlaps=17 count=965738516
Thread12: overlaps=18 count=847900384
Thread13: overlaps=19 count=6207215
Thread14: overlaps=19 count=19490349
Thread15: overlaps=18 count=60562201
Thread16: overlaps=17 count=940538865
Thread17: overlaps=18 count=730871356
Thread18: overlaps=18 count=187664691
Thread19: overlaps=17 count=719411214