1+ #! /bin/bash
2+
3+ # IRQ and Slice Analysis Script for L2 WiFi Access Point
4+ # Analyzes runtime state of IRQ distribution and systemd slice CPU affinity
5+
6+ set -euo pipefail
7+
8+ echo " === L2 WiFi Access Point - IRQ and Slice Analysis ==="
9+ echo " Generated: $( date) "
10+ echo " "
11+
12+ # Color codes for output
13+ RED=' \033[0;31m'
14+ GREEN=' \033[0;32m'
15+ YELLOW=' \033[1;33m'
16+ BLUE=' \033[0;34m'
17+ NC=' \033[0m' # No Color
18+
19+ # Function to print colored output
20+ print_status () {
21+ local status=$1
22+ local message=$2
23+ case $status in
24+ " OK" ) echo -e " ${GREEN} ✓${NC} $message " ;;
25+ " WARN" ) echo -e " ${YELLOW} ⚠${NC} $message " ;;
26+ " ERROR" ) echo -e " ${RED} ✗${NC} $message " ;;
27+ " INFO" ) echo -e " ${BLUE} ℹ${NC} $message " ;;
28+ esac
29+ }
30+
31+ # Check kernel parameters
32+ cmdline=$( cat /proc/cmdline)
33+ isolcpus=$( echo " $cmdline " | grep -o " isolcpus=[^ ]*" | cut -d= -f2 || echo " NOT SET" )
34+ print_status " INFO" " Isolated cores: $isolcpus "
35+
36+ # Ethernet IRQ L core distribution
37+ echo " "
38+ echo " === Ethernet IRQ L Cores ==="
39+ enp1s0_irqs=$( cat /proc/interrupts | grep " enp1s0" | awk ' {print $1}' | sed ' s/://' )
40+ if [ -n " $enp1s0_irqs " ]; then
41+ l_cores=" "
42+ for irq in $enp1s0_irqs ; do
43+ cpu_dist=$( grep " ^ *$irq :" /proc/interrupts | awk ' {for(i=2; i<=25; i++) if($i>0) printf "%d ", i-1}' )
44+ for cpu in $cpu_dist ; do
45+ if [ " $cpu " -lt 12 ]; then
46+ l_core=$cpu
47+ else
48+ l_core=$(( cpu - 12 ))
49+ fi
50+ l_cores=" $l_cores $l_core "
51+ done
52+ done
53+ l_cores=$( echo $l_cores | tr ' ' ' \n' | sort -u | tr ' \n' ' ' )
54+ echo " enp1s0 IRQs using L cores: $l_cores "
55+ else
56+ print_status " WARN" " No enp1s0 IRQs found"
57+ fi
58+
59+ # WiFi IRQ L core distribution
60+ echo " "
61+ echo " === WiFi IRQ L Cores ==="
62+ iwlwifi_irqs=$( cat /proc/interrupts | grep " iwlwifi" | awk ' {print $1}' | sed ' s/://' )
63+ if [ -n " $iwlwifi_irqs " ]; then
64+ l_cores=" "
65+ for irq in $iwlwifi_irqs ; do
66+ cpu_dist=$( grep " ^ *$irq :" /proc/interrupts | awk ' {for(i=2; i<=25; i++) if($i>0) printf "%d ", i-1}' )
67+ for cpu in $cpu_dist ; do
68+ if [ " $cpu " -lt 12 ]; then
69+ l_core=$cpu
70+ else
71+ l_core=$(( cpu - 12 ))
72+ fi
73+ l_cores=" $l_cores $l_core "
74+ done
75+ done
76+ l_cores=$( echo $l_cores | tr ' ' ' \n' | sort -u | tr ' \n' ' ' )
77+ echo " iwlwifi IRQs using L cores: $l_cores "
78+
79+ # Check expected cores 4,5,6,7
80+ for expected in 4 5 6 7; do
81+ if echo " $l_cores " | grep -q " $expected " ; then
82+ print_status " OK" " L core $expected : used"
83+ else
84+ print_status " WARN" " L core $expected : not used"
85+ fi
86+ done
87+ else
88+ print_status " WARN" " No iwlwifi IRQs found"
89+ fi
90+
91+ # Systemd slice CPU affinity
92+ echo " "
93+ echo " === Systemd Slice L Cores ==="
94+
95+ # Check global systemd CPU affinity
96+ echo " --- Global Systemd CPU Affinity ---"
97+ if [ -f " /etc/systemd/system.conf" ]; then
98+ global_cpu_affinity=$( grep " ^CPUAffinity=" /etc/systemd/system.conf | cut -d= -f2 || echo " not set" )
99+ echo " Global systemd CPUAffinity: $global_cpu_affinity "
100+ else
101+ echo " Global systemd CPUAffinity: not configured"
102+ fi
103+
104+ # Check main slices
105+ main_slices=(" network-services" " system" )
106+ for slice in " ${main_slices[@]} " ; do
107+ echo " --- $slice .slice ---"
108+ cgroup_path=" /sys/fs/cgroup/system.slice/$slice .slice"
109+
110+ if systemctl status " $slice .slice" > /dev/null 2>&1 ; then
111+ if [ -d " $cgroup_path " ] && [ -f " $cgroup_path /cpuset.cpus" ]; then
112+ cpu_affinity=$( cat " $cgroup_path /cpuset.cpus" )
113+ print_status " INFO" " CPU affinity: $cpu_affinity "
114+
115+ # Convert to L cores
116+ l_cores=" "
117+ for cpu in $( echo $cpu_affinity | tr ' ,' ' ' ) ; do
118+ if [[ $cpu =~ ^[0-9]+$ ]]; then
119+ if [ " $cpu " -lt 12 ]; then
120+ l_core=$cpu
121+ else
122+ l_core=$(( cpu - 12 ))
123+ fi
124+ l_cores=" $l_cores $l_core "
125+ elif [[ $cpu =~ ^([0-9]+)-([0-9]+)$ ]]; then
126+ start=${BASH_REMATCH[1]}
127+ end=${BASH_REMATCH[2]}
128+ for (( cpu= start; cpu<= end; cpu++ )) ; do
129+ if [ " $cpu " -lt 12 ]; then
130+ l_core=$cpu
131+ else
132+ l_core=$(( cpu - 12 ))
133+ fi
134+ l_cores=" $l_cores $l_core "
135+ done
136+ fi
137+ done
138+ l_cores=$( echo $l_cores | tr ' ' ' \n' | sort -u | tr ' \n' ' ' )
139+ echo " L cores: $l_cores "
140+ else
141+ print_status " INFO" " Slice loaded but no cgroup (no active services)"
142+ fi
143+ else
144+ print_status " ERROR" " Slice $slice .slice not found or not active"
145+ fi
146+ echo " "
147+ done
148+
149+ # Check per-daemon slices
150+ per_daemon_slices=(" kea" " pdns" " radvd" " hostapd" )
151+ for slice in " ${per_daemon_slices[@]} " ; do
152+ echo " --- $slice .slice ---"
153+ cgroup_path=" /sys/fs/cgroup/system.slice/$slice .slice"
154+
155+ if systemctl status " $slice .slice" > /dev/null 2>&1 ; then
156+ if [ -d " $cgroup_path " ] && [ -f " $cgroup_path /cpuset.cpus" ]; then
157+ cpu_affinity=$( cat " $cgroup_path /cpuset.cpus" )
158+ print_status " INFO" " CPU affinity: $cpu_affinity "
159+
160+ # Convert to L cores
161+ l_cores=" "
162+ for cpu in $( echo $cpu_affinity | tr ' ,' ' ' ) ; do
163+ if [[ $cpu =~ ^[0-9]+$ ]]; then
164+ if [ " $cpu " -lt 12 ]; then
165+ l_core=$cpu
166+ else
167+ l_core=$(( cpu - 12 ))
168+ fi
169+ l_cores=" $l_cores $l_core "
170+ elif [[ $cpu =~ ^([0-9]+)-([0-9]+)$ ]]; then
171+ start=${BASH_REMATCH[1]}
172+ end=${BASH_REMATCH[2]}
173+ for (( cpu= start; cpu<= end; cpu++ )) ; do
174+ if [ " $cpu " -lt 12 ]; then
175+ l_core=$cpu
176+ else
177+ l_core=$(( cpu - 12 ))
178+ fi
179+ l_cores=" $l_cores $l_core "
180+ done
181+ fi
182+ done
183+ l_cores=$( echo $l_cores | tr ' ' ' \n' | sort -u | tr ' \n' ' ' )
184+ echo " L cores: $l_cores "
185+ else
186+ print_status " INFO" " Slice loaded but no cgroup (no active services)"
187+ fi
188+ else
189+ print_status " WARN" " Slice $slice .slice not found or not active"
190+ fi
191+ echo " "
192+ done
193+
194+ # Service status summary
195+ echo " "
196+ echo " === Service Status ==="
197+ services=(" hostapd" " kea-dhcp4-server" " pdns-recursor" " radvd" )
198+ for service in " ${services[@]} " ; do
199+ if systemctl is-active " $service " > /dev/null 2>&1 ; then
200+ slice=$( systemctl show " $service " --property=Slice --value 2> /dev/null || echo " unknown" )
201+ nice_value=$( systemctl show " $service " --property=Nice --value 2> /dev/null || echo " 0" )
202+ print_status " OK" " $service : active (slice: $slice , nice: $nice_value )"
203+ else
204+ print_status " WARN" " $service : not active"
205+ fi
206+ done
207+
208+ # IRQ affinity service
209+ echo " "
210+ if systemctl is-active irq-affinity > /dev/null 2>&1 ; then
211+ print_status " OK" " IRQ affinity service: active"
212+ else
213+ print_status " WARN" " IRQ affinity service: not active"
214+ fi
215+
216+ echo " "
217+ echo " === Analysis Complete ==="
0 commit comments