I am interested in low-latency code and that`s why I tried to configure thread affinity. In particular, it was supposed to help to avoid context switches.
I have configured thread affinity using https://github.com/OpenHFT/Java-Thread-Affinity. I run very simple test code that just spins in a cycle checking a time condition.
long now = start;
while (true)
{
if (now < start + TimeUtils.NANOS_IN_SECOND * delay)
{
now = TimeUtils.now();
}
else
{
// Will be printed after 30 sec
if (TimeUtils.now() > start + TimeUtils.NANOS_IN_SECOND * (delay + 30))
{
final long finalNow = now;
System.out.println("Time is over at " +
TimeUtils.toInstant(finalNow) + " now: " +
TimeUtils.toInstant(TimeUtils.now()));
System.exit(0);
}
}
}
So, after the specified delay execution goes to "else" and approximately at the same time I see context switch. Is it an expected behavior? What is the specific reason for this? How can I avoid context switches in such cases?
Test Details
I build shadowJar from this repo: https://github.com/stepan2271/thread-affinity-example. Then I run it using the following command (one can play around with numbers here, it doesn`t have significant effect on test when delay > 60):
taskset -c 19 java -DtestLoopBindingCpu=3 -Ddelay=74 -cp demo-all.jar main.TestLoop
I also have the following test script to monitor context switches (should be run with ID of the Java thread that is bound to core)
#!/bin/bash
while [ true ]
do
date >> ~/demo-ctxt-switches.log
cat /proc/$1/status | grep ctxt >> ~/demo-ctxt-switches.log
sleep 3
done
Typical output of this script is the following:
Fri Oct 16 18:23:29 MSK 2020
voluntary_ctxt_switches: 90
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:32 MSK 2020
voluntary_ctxt_switches: 90
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:35 MSK 2020
voluntary_ctxt_switches: 90
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:38 MSK 2020
voluntary_ctxt_switches: 90
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:41 MSK 2020
voluntary_ctxt_switches: 91
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:44 MSK 2020
voluntary_ctxt_switches: 91
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:47 MSK 2020
voluntary_ctxt_switches: 91
nonvoluntary_ctxt_switches: 37
So, after some changes in start time these numbers become stable and then I see from 1 to 3 switches exactly (difference is less than 1 sec) at the time when code reaches "else" branch.
Deviations
Base configuration reproduces this behavior almost each time, while some deviations lead to situation when I didn`t manage to reproduce. Examples:
https://github.com/stepan2271/thread-affinity-example/tree/without-log4j
https://github.com/stepan2271/thread-affinity-example/tree/without-cached-nano-clock
Test environment
2 * Intel(R) Xeon(R) Gold 6244 CPU @ 3.60GHz
Red Hat Enterprise Linux 8.1 (Ootpa)
Cores are isolated using CPUAffinity in /etc/systemd/system.conf and /etc/systemd/user.conf
/etc/sysconfig/irqbalance is configured.
Openjdk 11.0.6 2020-01-14 LTS Runtime Environment 18.9