|
| 1 | +#!/bin/bash |
| 2 | +# ! |
| 3 | +# ! Usage: ./cpu-map.sh -p <process_PIDs comma separated> -n <process_Name> |
| 4 | +# ! -g <group-name:affinity-range> |
| 5 | +# ! |
| 6 | +# ! Set the CPU affinity for a list of running processes |
| 7 | +# ! |
| 8 | +# ! Ex.: ./cpu-map.sh -n crimson -g "alien:4-31" |
| 9 | +# ! ./cpu-map.sh -p ($pgrep osd) -g "rocksdb:4-7" |
| 10 | +# ! |
| 11 | +# ! Important: the "affinity-range" must be a vlid argument for taskset. |
| 12 | +######################################################## |
| 13 | +# Please edit the following to suit your own needs |
| 14 | +# |
| 15 | +# Regex to define the group of threads names we want to set their affinity: |
| 16 | +proc_group_re="alien-store-tp|rocksdb|bstore|cfin" |
| 17 | +# Associate array to identify the group and the thread names |
| 18 | +declare -A thr_grp_re_name_map=([alien]="$proc_group_re") |
| 19 | +# Ditto for their default affinity range: |
| 20 | +declare -A thr_grp_range_map=([alien]="4-7") |
| 21 | +# You can define further groups as needed |
| 22 | + |
| 23 | +# Range of CPU cores available: i.e. nprocs - rectors |
| 24 | +free_cpu_avail="8-31" |
| 25 | + |
| 26 | +# Regex of threads to ignore: do not change their affinity |
| 27 | +proc_ignore_re="crimson-osd|reactor|log|syscall" |
| 28 | +######################################################## |
| 29 | +# Examples: |
| 30 | + |
| 31 | +# Run with 4 cores on a dual socket 8 CPucores per socket system, no hyperthreading |
| 32 | +#declare -A thr_grp_map=([alien-store-tp]="4-7" [rocksdb]="4-7" [bstore]="4-7" [cfin]="4-7" ) |
| 33 | + |
| 34 | +######################################################## |
| 35 | +# svcdev3 -- 56 cpus |
| 36 | +#declare -A thr_grp_map=([io_context_pool]="0-12" [msg-worker]="13-25" [ceph-osd]="26-38" ) |
| 37 | +#free_cpu_avail="39-55" |
| 38 | +#proc_group_re="io_context_pool|msg-worker|ceph-osd" |
| 39 | + |
| 40 | +######################################################## |
| 41 | +# sv1-cephX-- 32 cpus |
| 42 | +#declare -A thr_grp_map=([io_context_pool]="0-9" [msg-worker]="10-19" [ceph-osd]="20-29" ) |
| 43 | + |
| 44 | +# Run with 2 cores: |
| 45 | +# busiest threads is msgr-worker-1, the rest of the threads segregated to the other core -- this is per OSD process |
| 46 | +#declare -A thr_grp_map=([msgr-worker]="0-0") |
| 47 | +#free_cpu_avail="1-1" |
| 48 | +# Regex to define the group of threads we want on its own cpu core |
| 49 | +#proc_group_re="msgr-worker" |
| 50 | + |
| 51 | +# Run with 4 cores: |
| 52 | +#declare -A thr_grp_map=([msgr-worker]="0-0" [bstore_kv]="1-1" [tp_osd_tp]="2-2") |
| 53 | +#free_cpu_avail="3-3" |
| 54 | +#proc_group_re="msgr-worker|bstore_kv|tp_osd_tp" |
| 55 | + |
| 56 | +# Run with 8 cores: |
| 57 | +#declare -A thr_grp_map=([msgr-worker]="0-1" [bstore_kv]="2-3" [tp_osd_tp]="4-5") |
| 58 | +#free_cpu_avail="6-7" |
| 59 | +#proc_group_re="msgr-worker|bstore_kv|tp_osd_tp" |
| 60 | + |
| 61 | +# Run with 16 cores: |
| 62 | +#declare -A thr_grp_map=([msgr-worker]="0-1" [bstore_kv]="2-3" [tp_osd_tp]="4-5" [rocksdb]="6-7") |
| 63 | +#free_cpu_avail="8-15" |
| 64 | +#proc_group_re="msgr-worker|bstore_kv|tp_osd_tp|rocksdb" |
| 65 | + |
| 66 | +######################################################## |
| 67 | + |
| 68 | +# cores 16-31 are for FIO only |
| 69 | + |
| 70 | +usage() { |
| 71 | + cat $0 | grep ^"# !" | cut -d"!" -f2- |
| 72 | +} |
| 73 | + |
| 74 | +# Given a thread name, find its affinity from $thr_grp_map[] |
| 75 | +getaffinity() { |
| 76 | + local name="$1" |
| 77 | + local regex="$2" |
| 78 | + if [ -z "$regex" ]; then |
| 79 | + echo '' |
| 80 | + fi |
| 81 | +} |
| 82 | + |
| 83 | +# process arguments |
| 84 | +while getopts 'p:n:g:' option; do |
| 85 | + case "$option" in |
| 86 | + p) PROCESSES=$OPTARG # this should be a , separated list of pids |
| 87 | + ;; |
| 88 | + n) PROCESSES=$(pgrep --newest --exact $OPTARG) |
| 89 | + ;; |
| 90 | + # TBD. extend this argument into a map {thread_name:cpu-range} |
| 91 | + g) CPUGROUP_STR=$OPTARG |
| 92 | + CPUGROUP=true |
| 93 | + IFS=':' read -r -a cpu_grp_lst <<< "$CPUGROUP_STR" |
| 94 | + #echo ${cpu_grp_lst[@]} #ok |
| 95 | + # cpu_grp_lst[0] is the group name, |
| 96 | + # cpu_grp_lst[1] is the group cpu range |
| 97 | + ;; |
| 98 | + :) printf "missing argument for -%s\n" "$OPTARG" >&2 |
| 99 | + usage >&2 |
| 100 | + exit 1 |
| 101 | + ;; |
| 102 | + \?) printf "illegal option: -%s\n" "$OPTARG" >&2 |
| 103 | + usage >&2 |
| 104 | + exit 1 |
| 105 | + ;; |
| 106 | + esac |
| 107 | +done |
| 108 | + |
| 109 | +if [ $# -eq 0 ]; then usage >&2; exit 1; fi |
| 110 | + |
| 111 | +declare -a other=() |
| 112 | +next_avail_cpu=0 |
| 113 | +max_cpus=$(nproc) |
| 114 | +cpu_used=1 |
| 115 | +j=0 # last index of the other[] array |
| 116 | + |
| 117 | +function get_affinity() { |
| 118 | + local i="$1" |
| 119 | +} |
| 120 | + |
| 121 | +IFS=', ' read -r -a proc_list <<< "$PROCESSES" |
| 122 | +for PID in "${proc_list[@]}"; do |
| 123 | + if [ -e "/proc/$PID/task" ]; then |
| 124 | + # get list of threads for given PID |
| 125 | + THREADS=$(ls /proc/$PID/task) |
| 126 | + for i in $THREADS; do |
| 127 | + if [ "$CPUGROUP" = true ]; then |
| 128 | + pgroup_re=${thr_grp_re_name_map[${cpu_grp_lst[0]}]} |
| 129 | + t_name=$(grep -E "$pgroup_re" /proc/$i/comm ) |
| 130 | + if [ -n "$t_name" ]; then |
| 131 | + affinity=${cpu_grp_lst[1]} |
| 132 | + else |
| 133 | + # this thread is not in the group, check if we want to skip it |
| 134 | + t_name=$(grep -E "$proc_ignore_re" /proc/$i/comm ) |
| 135 | + |
| 136 | + if [ -n "$t_name" ] && [ "$CPUGROUP" = true ]; then |
| 137 | + echo "Skipping $i" |
| 138 | + continue |
| 139 | + else |
| 140 | + # so its affinity will be on the remaining cpu set |
| 141 | + other[$(( j++ ))]="$i" |
| 142 | + fi |
| 143 | + fi |
| 144 | + else |
| 145 | + # if we use them all CPUs, rotate |
| 146 | + affinity=$(( next_avail_cpu++ % max_cpus )) |
| 147 | + cpu_used=$(( cpu_used | ( 1 << $affinity ))) |
| 148 | + printf "cpu_used: 0x%x\n" $cpu_used |
| 149 | + fi |
| 150 | + echo "$t_name: taskset -c -p $affinity $i" |
| 151 | + taskset -c -p $affinity $i |
| 152 | + done # threads |
| 153 | + else |
| 154 | + echo "Process $PID does not exist" |
| 155 | + fi |
| 156 | +done # PID |
| 157 | + |
| 158 | +# Assign the affinity to the other threads on the remaining non-used cpus |
| 159 | +echo "Threads in the remaining set all with the remaining processor ids:" |
| 160 | +#echo "${other[@]}" |
| 161 | +for x in "${other[@]}"; do |
| 162 | + if [ "$CPUGROUP" ]; then |
| 163 | + echo taskset -c -p $free_cpu_avail $x |
| 164 | + else |
| 165 | + rem_affinity=$(printf "0x%x\n" $(( cpu_used ^ 0xfffffff ))) |
| 166 | + echo taskset -p $rem_affinity $x |
| 167 | + fi |
| 168 | +done |
0 commit comments