5

I am trying to optimise getting GPIO interrupts into userspace. On the single core rpi 1 I couldn't get rid of quite some timing jitter, which makes sense as there's a lot of stuff going on on the cpu.

Now with the dual core rpi2, I wanted to try this again.

The idea would be:

  • have 2 cores handle the OS including as many interrupt sources as possible.
  • have 1 core handling the BCM2708 GPIO catchall handler and my kernel modules IRQ
  • have 1 core running the userspace program

isolcpus worked nicely to get 2 cpus not being scheduled by regular tasks, but I am struggling with the irqs.

root@ucnraspberrypi2-1:~# echo 3 > /proc/irq/52/smp_affinity
bash: echo: write error: Input/output error

I get the same for any irq when I want to change cpu affinity.

Is that not implemented in the IRQ driver? If not, is there a hardware reason?

Any ideas? Thanks ...

=======

Here's my /proc/interrupts:

root@ucnraspberrypi2-1:~# cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3       
 16:          0          0          0          0   ARMCTRL  bcm2708_fb dma
 24:        466          0          0          0   ARMCTRL  DMA IRQ
 25:       2370          0          0          0   ARMCTRL  DMA IRQ
 32:   17257562          0          0          0   ARMCTRL  dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1
 52:          1          0          0          0   ARMCTRL  BCM2708 GPIO catchall handler
 65:         63          0          0          0   ARMCTRL  ARM Mailbox IRQ
 66:          2          0          0          0   ARMCTRL  VCHIQ doorbell
 75:          1          0          0          0   ARMCTRL
 79:          4          0          0          0   ARMCTRL  bcm2708_i2c.1
 80:          0          0          0          0   ARMCTRL  bcm2708_spi.0
 83:         33          0          0          0   ARMCTRL  uart-pl011
 84:      70207          0          0          0   ARMCTRL  mmc0
 99:     340237     325956     304090     304089   ARMCTRL  arch_timer
273:          1          0          0          0      GPIO  Some gpio pin description
FIQ:              usb_fiq
IPI0:          0          0          0          0  CPU wakeup interrupts
IPI1:          0          0          0          0  Timer broadcast interrupts
IPI2:     238100      75472     303997     303996  Rescheduling interrupts
IPI3:          2          2          4          4  Function call interrupts
IPI4:        126         10          0          0  Single function call interrupts
IPI5:          0          0          0          0  CPU stop interrupts
IPI6:          0          0          0          0  IRQ work interrupts
IPI7:          0          0          0          0  completion interrupts
Err:          0
F1Linux
  • 1,677
  • 1
  • 15
  • 32
BeerSerc
  • 151
  • 1
  • 2

2 Answers2

1

Check if your kernel is built with CONFIG_REGMAP_IRQ=Y. If not, you will not be able to map IRQs to CPUs.

Bear in mind that even if IRQ mapping is enabled, there may be hardware limitation preventing a particular IRQ from being remapped. There are interrupts which are specific to a given core (a prime example is the division by zero IRQ in x86).

Edit: I have just checked, and the latest Pi OS kernel allows to remap the interrupts, and some interrupts (e.g. 38) can be remapped. As I explained above, some interrupts simply cannot be remapped, and you are expected to get IO error if you try to change the affinity of such interrupts.

Dmitry Grigoryev
  • 28,277
  • 6
  • 54
  • 147
1

Below is a script I wrote to configure CPU Affinity that can be adapted (to some more or less degree) to achieve your objective- ring-fencing a core for dedicated processing. What the below code does is restricts the OS to working on Cores 0-2 leaving Core 3 of our 4-core processor to exclusively perform video encoding which is indeed a CPU intensive operation. Since the application "Motion" I'm using is single threaded, it could only ever use a single core at any one time.

"taskset" is used to pin motion to the specified core. So since the OS can only work on cores 0-2, no timeslicing happens on core 3 where the video encoding occurs.

I've tested the following provided code and proven it does separate the CPU processing in the described way.

Cut-n-paste the code below into a file. Change the target of "taskset" from "motion" to your application. Then chmod 700 the file and execute it once you've made whatever other tweaks you care to make:

#!/bin/bash

# Backup /etc/systemd/system.conf before we tweak it:
cp -p /etc/systemd/system.conf /etc/systemd/system.conf.ORIGINAL

# Limit OS to using only first 3 cores:
sed -i "s/#CPUAffinity=1 2/CPUAffinity=0 1 2/" /etc/systemd/system.conf


echo "Automate setting CPU Affinity for Motion on boot"

cat <<'EOF'> /home/pi/scripts/set-cpu-affinity.sh
#!/bin/bash

# Note: the number following cp is the CPU/core number in this case three
taskset -cp 3 $(pgrep motion|cut -d ' ' -f2)

EOF


chmod 700 /home/pi/scripts/set-cpu-affinity.sh
chown pi:pi /home/pi/scripts/set-cpu-affinity.sh

# Note use of * Wants * directive to create a dependent relationship on Motion already being started:
cat <<EOF> /etc/systemd/system/set-cpu-affinity.service
[Unit]
Description=Set CPU Affinity for the Motion process after it starts on boot
Wants=motion.service

[Service]
User=root
Group=root
Type=oneshot
ExecStart=/home/pi/scripts/set-cpu-affinity.sh

[Install]
WantedBy=multi-user.target

EOF


systemctl enable set-cpu-affinity.service

# Change ownership of all files created by this script FROM user "root" TO user "pi":
chown -R pi:pi /home/pi
F1Linux
  • 1,677
  • 1
  • 15
  • 32