Search code examples
c++boostipcshared-memorylatency

Latency jitters when using shared memory for IPC


I am using shared memory for transferring data between two process, using boost::interprocess::managed_shared_memory to allocate a vector as buffer and atomic variables for enforcing memory synchronization (similar to boost::lockfree::spsc_queue).

I was measuring the end-to-end latency for the setup with 2 processes -

  1. sender process - writes to the buffer in shared memory, and sleeps. So the rate at which it pushes data is in interval of around 55 microseconds.
  2. receiver process - runs a busy loop to see if something can be consumed from the buffer.

I am using a RingBuffer of size 4K (high for safety), although ideally a maximun of 1 element will be present in the buffer as per the current setup. Also, I am pushing data around 3 million times to get a good estimate for the end to end latency.

To measure the latency - I get the current time in nanoseconds and store it in a vector (resized to size 3 million at the beginning). I have a 6 core setup, with isolated cpus, and I do taskset to different cores for both sender and receiver process. I also make sure no other program is running from my end on the machine when doing this testing. Output of /proc/cmdline

initrd=\initramfs-linux-lts.img root=PARTUUID=cc2a533b-d26d-4995-9166-814d7f59444d rw isolcpus=0-4 intel_idle.max_cstate=0 idle=poll

I have already done the verification that all data transfer is accurate and nothing is lost. So simple row-wise subtraction of the timestamp is sufficient to get the latency.

I am getting latency of around a 300-400 nanosecods as mean and median of the distribution, but the standard deviation was too high (few thousands of nanos). On looking at the numbers, I found out that there are 2-3 instances where the latency shoots upto 600000 nanos, and then gradually comes down (in steps of around 56000 nanos - probably queueing is happening and consecutive pops from the buffer are successful). Attaching a sample "jitter" here -

568086 511243 454416 397646 340799 284018 227270 170599 113725 57022 396

If I filter out these jittery datapoints, the std_dev becomes very less. So I went digging into what can be the reason for this. Initially I was looking if there was some pattern, or if it is occuring periodically, but it doesnot seem so in my opinion.

I ran the receiver process with perf stat -d, it clearly shows the number of context switches to be 0.

Interestingly, when looking the receiver process's /proc/${pid}/status, I monitor voluntary_ctxt_switches, nonvoluntary_ctxt_switches and see that the nonvoluntary_ctxt_switches increase at a rate of around 1 per second, and voluntary_ctxt_switches is constant once the data sharing starts. But the problem is that for around the 200 seconds of my setup runtime, the number of latency spikes is around 2 or 3 and does not match the frequency of this context_switch numbers. (what is this count then?)

I also followed a thread which feels relevant, but cant get anything. For the core running the receiver process, the trace on core 1 with context switch is (But the number of spikes this time was 5)-

$ grep " 1)" trace | grep "=>"

1) jemallo-22010  =>    <idle>-0
2) <idle>-0    =>  kworker-138
3) kworker-138   =>    <idle>-0

I also checked the difference between /proc/interrupts before and after the run of the setup. The differences are

name receiver_core sender_core
enp1s0f0np1-0 2 0
eno1 0 3280
Non-maskable interrupts 25 25
Local timer interrupts 2K ~3M
Performance monitoring interrupts 25 25
Rescheduling interrupts 9 12
Function call interrupts 120 110
machine-check polls 1 1

I am not exactly sure of what most of these numbers represent. But I am curious as why there are rescheduling interrupts, and what is enp1s0f0np1-0.

It might be the case that the spike is not coming due to context switches at the first place, but a number of the range 600 mics does hunch towards that. Leads towards any other direction would be very helpful. I have also tried restarting the server.


Solution

  • Turns out the problem was indeed not related to context switch. I was also dumping the received data in a file. Stopping that recording removed the spikes. So, the high latency was due to some kind of write flush happening.