#!/bin/bash
 
defaultmask=7
defaultisolirq=27
defaultisolmask=8
 
cpucores=`grep ^processor /proc/cpuinfo | wc -l`
if test $cpucores -gt 16
then
  coremask=4294967295
elif test $cpucores -gt 8
then
  coremask=65535
elif test $cpucores -gt 4
then
  coremask=255
else  
  coremask=15  
fi
 
eval `cat /proc/cmdline | tr ' ' '\n' | grep isolcpus`
if test "$isolcpus"
then
  OLDIFS="$IFS"
  IFS=,
  isolmask=0
  for i in $isolcpus
  do
    thismask=$((2 ** $i))
    isolmask=$(($isolmask + $thismask))
  done
  IFS="$OLDIFS"
fi
if test "$isolmask"
then
  decidefaultmask=$(($coremask ^ $isolmask))
  defaultmask=`printf %x $decidefaultmask`
  decidefaultisolmask=$isolmask
  defaultisolmask=`printf %x $decidefaultisolmask`
fi
 
if test "$1" -a "$1" = --help
then
  echo "Usage: `basename $0` <mask> <isolirq> <isolmask>"
  echo "Function: Set SMP affinity mask of all IRQ threads to <mask>, except IRQs <isolirq> to <isolmask>"
  echo "          <mask> defaults to $defaultmask"
  echo "          <isolirq> defaults to $defaultisolirq"
  echo "          <isolmask> defaults to $defaultisolmask"
  echo "Options: none"
  exit 1
fi
 
strcmp() {
  if test -z "$1" -o -z "$2"
  then
    echo false
  else
    str1="$1"
    str2="$2"
    strlen1=`echo -n "$str1" | wc -c`
    strlen2=`echo -n "$str2" | wc -c`
    if test $strlen1 -gt $strlen2
    then
      str1="`echo $str1 | cut -c1-$strlen2`"
    elif test $strlen2 -gt $strlen1
    then
      str2="`echo $str2 | cut -c1-$strlen1`"
    fi
    test "$str1" = "$str2"
  fi
}
 
pidof()
{
  irqname="$1"
  if test -z "$irqname"
  then
    echo
    return
  fi
 
  cd /proc
  for pid in [0-9]*
  do
    taskname="`cat $pid/comm 2>/dev/null`"
    if test "$taskname"
    then
      if strcmp "$taskname" "$irqname"
      then
        echo $pid
        break
      fi
    fi
  done
  cd - >/dev/null
}
 
if test "$1"
then
  if echo $1 | grep -iq [^0-9a-f] 
  then
    echo "First argument for default mask is expected to be a lower-case hexadecimal number, not $1"
    exit 1
  fi
  mask=$1
else
  mask=$defaultmask
fi
 
if test "$2"
then
  if echo $2 | grep -q '[^0-9 ]'
  then
    echo "Second argument for isolated IRQs is expected to be a list of decimal numbers, not $2"
    exit 1
  fi
  isolirq="$2"
else
  isolirq="$defaultisolirq"
fi
 
if test "$3"
then
  if echo $1 | grep -iq [^0-9a-f] 
  then
    echo "Third argument for mask of isolated IRQs is expected to be a lower-case hexadecimal number, not $1"
    exit 1
  fi
  isolmask=$3
else
  isolmask=$defaultisolmask
fi
 
redcolor='\033[0;31m'
yellowcolor='\033[0;33m'
greencolor='\033[0;32m'
nocolor='\033[0m'
 
red() {
  printf $redcolor$@$nocolor
}
 
yellow() {
  printf $yellowcolor$@$nocolor
}
 
green() {
  printf $greencolor$@$nocolor
}
 
NOT() {
  echo `red NOT`
}
 
is() {
  echo `green is`
}
 
can() {
  echo `yellow can`
}
 
could() {
  echo `yellow could`
}
 
cd /proc/irq
 
 
for irq in `ls -1d [0-9]* | sort -n`
do
  irqshare=1
  while true
  do
    namedir="`find $irq/* -type d -print0 | xargs -0 printf %s@ | cut -d@ -f$irqshare`"
    if test "$namedir"
    then
      irqname=`basename "$namedir"`
      taskname=`echo irq/$irq-$irqname`
      pid=`pidof $taskname`
      if test -z "$pid"
      then
        taskname=`echo $irq-$irqname`
        pid=`pidof $taskname`
      fi  
      if test "$pid"
      then
        realcore10=`ps -o psr $pid | sed 's/^ *//' | grep ^[0-9]`
        realcoremask10=$((2 ** $realcore10))
        affinity=`grep Cpus_allowed: ../$pid/status | cut -f2 | sed s/^0*//`
        flags=`cat ../$pid/stat | sed 's/(.*)/comm/' | cut -d" " -f 9`
      else
        irqname=
      fi
    else
      if test $irqshare -gt 1
      then
        break
      fi
      irqname=
    fi
    if echo $isolirq | tr " " "\n" | grep -q ^$irq$
    then
      thismask=$isolmask
    else
      thismask=$mask
    fi
    if test "$irqname"
    then
      if test $(($flags & 0x04000000)) != 0
      then
        echo -n Affinity mask of interrupt $irq $irqname can `NOT` be modified, since it has the PF_NO_SETAFFINITY flag set
        if test $((0x$affinity - 0x$thismask)) = 0
        then
          if test $(($realcoremask10 & 0x$thismask)) != 0
          then
            echo ", but the affinity mask 0x$affinity of thread $irqname (PID $pid) fortunately `is` correct, and the thread is currently running on core $realcore10 which `is` ok"
          else
            echo ", but the affinity mask 0x$affinity of thread $irqname (PID $pid) fortunately `is` correct; however, the thread is currently running on core $realcore10 which is `NOT` ok"
          fi
        else
          if test $(($realcoremask10 & 0x$thismask)) != 0
          then
            echo ", but although the affinity mask of thread $irqname (PID $pid) is 0x$affinity which is `NOT` ok, the thread is currently running on core $realcore10 which `is` ok"
          else
            echo ", and because the affinity mask of thread $irqname (PID $pid) unfortunately is 0x$affinity which is `NOT` ok, the thread is running on core $realcore10 which is `NOT` ok"
          fi
        fi
      fi
    fi
    current_smp_affinity="`cat $irq/smp_affinity`"
    if test $((0x$current_smp_affinity - 0x$thismask)) != 0
    then
      if ! echo $thismask >$irq/smp_affinity 2>/dev/null
      then
        echo -n Default SMP affinity mask of interrupt $irq $irqname is 0x$current_smp_affinity and could `NOT` be set to 0x$thismask
        andorbut=but
      else
        echo -n Default SMP affinity mask of interrupt $irq $irqname was 0x$current_smp_affinity and `is` now corrected to 0x$thismask
        andorbut=and
      fi
    else
      echo -n Default SMP affinity mask of interrupt $irq $irqname `is` 0x$thismask and already correct
      andorbut=and
    fi
    if test "$irqname"
    then
      if test $((0x$affinity - 0x$thismask)) = 0
      then
        if test $(($realcoremask10 & 0x$thismask)) != 0
        then
          echo ", $andorbut the affinity mask 0x$affinity of thread $irqname (PID $pid) fortunately `is` correct, and the thread is currently running on core $realcore10 which `is` ok"
        else
          echo ", $andorbut the affinity mask 0x$affinity of thread $irqname (PID $pid) fortunately `is` correct; however, the thread is currently running on core $realcore10 which is `NOT` ok"
        fi
      else
        if taskset -p $thismask $pid >/dev/null 2>&1
        then
          echo -n ", $andorbut the affinity mask of thread $irqname (PID $pid) is 0x$affinity which is `NOT` ok, but successfully attempted to be modified to 0x$thismask"
          realcore10=`ps -o psr $pid | sed 's/^ *//' | grep ^[0-9]`
          realcoremask10=$((2 ** $realcore10))
          affinity=`grep Cpus_allowed: ../$pid/status | cut -f2 | sed s/^0*//`
          if test $((0x$affinity - 0x$thismask)) = 0
          then
            if test $(($realcoremask10 & 0x$thismask)) != 0
            then
              echo " and `is` now 0x$thismask, and the thread is currently running on core $realcore10 which `is` ok"
            else
              echo " and `is` now 0x$thismask, but the thread is currently running on core $realcore10 which is `NOT` ok"
            fi
          else
            echo -n , but still is 0x$affinity which `is`
            if test $((0x$affinity & 0x$thismask)) != 0
            then
              if test $(($realcoremask10 & 0x$thismask)) != 0
              then
                echo " potentially ok, and the thread is currently running on core $realcore10 which also `is` ok"
              else 
                echo " potentially ok, but the thread is currently running on core $realcore10 which is `NOT` ok"
              fi
            else
              if test $(($realcoremask10 & 0x$thismask)) != 0
              then
                echo " `NOT` ok, but the thread is currently running on core $realcore10 which `is` ok"
              else
                echo " `NOT` ok, and the thread is in fact currently running on core $realcore10 which is `NOT` ok"
              fi
            fi 
          fi
        else
          echo ", but the affinity mask of thread $irqname (PID $pid) is 0x$affinity which is `NOT` ok and could `NOT` be corrected"
        fi
      fi
    else
      echo
    fi
  irqshare=`expr $irqshare + 1`
  done
done