diff options
Diffstat (limited to 'scripts/system/irq-affinity.pl')
-rwxr-xr-x | scripts/system/irq-affinity.pl | 94 |
1 files changed, 61 insertions, 33 deletions
diff --git a/scripts/system/irq-affinity.pl b/scripts/system/irq-affinity.pl index d12b7ed0..79bf7d58 100755 --- a/scripts/system/irq-affinity.pl +++ b/scripts/system/irq-affinity.pl @@ -20,6 +20,9 @@ use warnings; use strict; use Sys::Syslog qw(:standard :macros); +my $PATH_SYS_SYSTEM = "/sys/devices/system"; +my $PATH_SYS_CPU0 = $PATH_SYS_SYSTEM . "/cpu/cpu0"; + die "Usage: $0 ifname {auto | mask} { debug }\n" if ($#ARGV < 1); my ($ifname, $mask, $debug) = @ARGV; @@ -30,7 +33,7 @@ die "Error: Interface $ifname does not exist\n" my $logopt = defined($debug) ? "perror" : ""; openlog("irq-affinity", $logopt, LOG_LOCAL0); -my ( $cpus, $cores ) = cpuinfo(); +my ($cpus, undef, $threads) = cpuinfo(); if ($mask eq 'auto') { affinity_auto($ifname); @@ -43,6 +46,13 @@ exit 0; # Get current irq assignments by reading /proc/interrupts # returns reference to hash of interrupt infromation for given interface # i.e. {'eth1'} => 22, {'eth1-tx-1'} => 31, ... +# +# Code based on parsing in irqbalance program +# +# Format of /proc/interrupts is: +# +# CPU0 CPU1 +# 72: 1637 0 PCI-MSI-edge eth3 sub irqinfo { my $ifname = shift; my $irqmap; @@ -50,16 +60,27 @@ sub irqinfo { open( my $f, '<', "/proc/interrupts" ) or die "Can't read /proc/interrupts"; + # first line is the header we don't need + <$f>; + while (<$f>) { chomp; - my @cols = split; + # lines with letters in front are special, like NMI count. + # # First column is IRQ number (and colon) - next unless /^\s*(\d+):\s/; + # after that match as many entries with digits + last unless /^\s*(\d+):\s/; my $irq = $1; - # Skip columns for IRQ's per CPU - foreach my $name ( @cols[ $cpus+1 .. $#cols ] ) { + my @cols = split; + + # skip the irq number and all counts + do { + shift @cols; + } while ($cols[0] =~ /^\d+$/); + + foreach my $name ( @cols ) { $name =~ s/,$//; next unless ($name eq $ifname || $name =~ /^$ifname-/ ); @@ -72,41 +93,49 @@ sub irqinfo { return $irqmap; } -# Determine number of cpus and cores -sub cpuinfo { - my ($cpus, $cores); - my $sockets = 1; - open( my $f, '<', "/proc/cpuinfo" ) - or die "Can't read /proc/cpuinfo"; +# count the bits set in a mapping file +sub path_sibling { + my $path = shift; + my $result = 0; - while (<$f>) { - chomp; - if (/^cpu cores\s+:\s(\d+)$/) { - $cores = $1; - } - elsif (/^processor\s+:\s+(\d+)$/) { - $cpus = $1 + 1; - } - elsif (/^physical id\s+:\s+(\d+)$/) { - $sockets = $1 + 1; - } - } + open (my $f, '<', $path) + or die "can't open $path : $!"; + + my $line = <$f>; close $f; + chomp $line; - syslog(LOG_DEBUG, "cpus=%d cores=%d sockets=%d\n", - $cpus, $cores, $sockets); + for my $mask (split(/,/, $line)) { + my $bits = hex($mask); + + for (; $bits > 0; $bits /= 2) { + ++$result if ($bits & 1); + } + } - $cores *= $sockets; - return ( $cpus, $cores ); + return $result; } -# Determine hyperthreading factor -# most CPU's have either 1 or 2 threads per core -sub threads_per_core { - return 1 unless defined($cores); +# Determine number of cpu topology information +# +# This algorithm is based on the command lscpu from util-linux +# it cases like multiple socket, offline cpus, etc +sub cpuinfo { + my $cpu = 0; + + while ( -e $PATH_SYS_SYSTEM . '/cpu/cpu' . $cpu ) { + ++$cpu; + } + + my $thread = path_sibling($PATH_SYS_CPU0 . '/topology/thread_siblings'); + my $core = path_sibling($PATH_SYS_CPU0 . '/topology/core_siblings') / $thread; + my $socket = $cpu / $core / $thread; + + syslog(LOG_DEBUG, "cpus=%d cores=%d threads=%d sockets=%d\n", + $cpu, $core, $thread, $socket); - return $cpus / $cores; + return ($cpu, $core, $thread); } # Set affinity value for a irq @@ -155,7 +184,6 @@ sub skip_cpu { # For multi-queue NIC choose next cpu to be on next core sub next_cpu { my $origcpu = shift; - my $threads = threads_per_core(); my $cpu = $origcpu; do { |