diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2011-05-20 08:27:02 -0700 |
---|---|---|
committer | Stephen Hemminger <shemminger@vyatta.com> | 2011-05-20 08:38:57 -0700 |
commit | c206df7d62af7b1c2f310e546c877c18095bc6d1 (patch) | |
tree | ee2856a71a5d217662eaa0d4c930b9f221d5637a /scripts/system/irq-affinity.pl | |
parent | af7183535b2b71b67fda70e2bc18900ccb308365 (diff) | |
download | vyatta-cfg-system-c206df7d62af7b1c2f310e546c877c18095bc6d1.tar.gz vyatta-cfg-system-c206df7d62af7b1c2f310e546c877c18095bc6d1.zip |
irq-affinity: use sysfs to read cpu topology
Change to using sysfs to read cpu topology. This makes code more
robust and follow the standard practice of other utilities.
As an added benefit, irq-affinty now handles offline cpu's and
other cases where cpu numbers are not fully populated.
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 { |