lib/Kernel/irq.pm

SYNOPSIS

Interrupt helpers for kernel tests.

Take a snapshot of /proc/interrupts before and after a workload and compare the counters of the interrupts of interest:

my @irqs = get_device_irqs($controller);
my $before = get_interrupts();
# run the workload
my $after = get_interrupts();
my $delta = get_irq_total($after, @irqs) - get_irq_total($before, @irqs);

get_interrupts

my $snapshot = get_interrupts();

Reads /proc/interrupts on the SUT and returns a hash reference with:

Rows like ERR and MIS have one counter, not one per CPU.

get_irq_total

my $count = get_irq_total($snapshot, @irqs);

Returns the sum of the counters of all CPUs for the given interrupts of a snapshot from get_interrupts(). Dies if an interrupt is missing.

get_irq_per_cpu

my $counts = get_irq_per_cpu($snapshot, @irqs);

Returns a hash reference of the CPU number to the sum of the counters of the given interrupts on that CPU. Dies if an interrupt is missing.

get_irq_remapped

my $remapped = get_irq_remapped($snapshot, @irqs);

Returns a hash reference of each given interrupt to 1 if it goes through interrupt remapping (Intel VT-d or AMD-Vi), else 0, from a snapshot from get_interrupts(). Dies if an interrupt is missing.

On x86_64, the chip name of a remapped interrupt in /proc/interrupts starts with IR-, for example IR-PCI-MSIX-0000:02:00.0 or IR-IO-APIC. Other architectures do not use this prefix, so all interrupts are reported as not remapped there.

get_irqs_in_use

my @in_use = get_irqs_in_use($snapshot, @irqs);

Returns the given interrupts that have a row in a snapshot from get_interrupts(), in the given order. A driver can reserve more interrupts than it uses: get_device_irqs() returns all reserved interrupts, but only interrupts that the driver requested appear in /proc/interrupts. For example, a network card reserves interrupts for an RDMA driver that is not loaded, and the driver of a network interface that is down requests none.

get_device_irqs

my @irqs = get_device_irqs($sysfs_path);

Returns the interrupt numbers of a PCI device, for example /sys/devices/pci0000:00/0000:00:01.0. These are the MSI or MSI-X interrupts from msi_irqs if the device uses them, else the legacy interrupt from irq. Dies if the device has no interrupt. These are the interrupts that the driver reserved; see get_irqs_in_use() for the interrupts that it uses.

get_irq_affinity

my $affinity = get_irq_affinity(@irqs);

Returns a hash reference of each given interrupt to the CPUs that it may run on, as the kernel CPU list from /proc/irq/N/smp_affinity_list, for example 0-7,32-39. Reads all interrupts with one command.

set_irq_affinity

my @refused = set_irq_affinity(298 => '0', 299 => '16', ...);

Sets the CPUs that each given interrupt may run on, as a kernel CPU list written to /proc/irq/N/smp_affinity_list, with one command. Returns the interrupts whose affinity the kernel refused, for example interrupts that the kernel manages itself, such as the queue interrupts of NVMe. A running irqbalance can change the affinity again later.