Last active
September 6, 2023 03:06
-
-
Save sequix/c5da2e76bcebd654003437a323cb114f to your computer and use it in GitHub Desktop.
machine-independent cpuset operations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -euo pipefail | |
| help() { | |
| printf "cpuset.sh version: 3.1\n" | |
| printf "usage:\n" | |
| printf "cpuset.sh union 0-1 2 3-4,5 => 0-5\n" | |
| printf "cpuset.sh intersect 0-9 4-6 4-5 => 4-5\n" | |
| printf "cpuset.sh minus 0-9 4-5 => 0-3,6-9\n" | |
| printf "cpuset.sh shrink 0,1,2,3 => 0-3\n" | |
| printf 'cpuset.sh expand 0-3 => 0\\n1\\n2\\n3\\n\n' | |
| printf "cpuset.sh tomask 0-15 => ffff\n" | |
| printf "cpuset.sh todigit ffff => 0-15\n" | |
| } | |
| expand() { | |
| local i=0 | |
| local c="" | |
| local lc="" | |
| local acc="" | |
| local lacc="" | |
| local src="$1" | |
| local rst | |
| declare -a rst | |
| for (( i=0; i<${#src}; i++ )); do | |
| c="${src:$i:1}" | |
| case "$c" in | |
| [0-9]) | |
| acc=$((acc*10+$c)) | |
| ;; | |
| -) | |
| if ! <<<"$lc" grep -q "[0-9]"; then | |
| echo "invalid hyphen in set $src" | |
| exit 1 | |
| fi | |
| lacc="$acc" | |
| acc="" | |
| ;; | |
| ,) | |
| if [ -n "$lacc" ]; then | |
| rst+=($(seq "$lacc" "$acc")) | |
| elif [ -n "$acc" ]; then | |
| rst+=("$acc") | |
| fi | |
| acc="" | |
| lacc="" | |
| ;; | |
| *) | |
| echo "invalid character '$c' in set $src" | |
| exit 1 | |
| ;; | |
| esac | |
| lc="$c" | |
| done | |
| if [ -n "$lacc" ]; then | |
| rst+=($(seq "$lacc" "$acc")) | |
| elif [ -n "$acc" ]; then | |
| rst+=("$acc") | |
| fi | |
| <<<"${rst[@]}" tr ' ' '\n' | sort -nu | |
| } | |
| expand_to_file() { | |
| local src="$1" | |
| local filename="" | |
| filename=$(mktemp) | |
| expand "$src" >"$filename" | |
| echo "$filename" | |
| } | |
| shrink_internal() { | |
| local cpus=("$@") | |
| local n=${#cpus[@]} | |
| if [ $n -eq 0 ]; then | |
| return | |
| elif [ $n -eq 1 ]; then | |
| echo "${cpus[0]}" | |
| return | |
| fi | |
| local i=0 | |
| local j=1 | |
| local ci="${cpus[0]}" | |
| local cj="" | |
| local cj1="" | |
| local rst="" | |
| for ((j=1; j < $n; j++)); do | |
| cj="${cpus[$j]}" | |
| cj1="${cpus[$((j-1))]}" | |
| if [ "$cj" -ne "$((cj1+1))" ]; then | |
| if [ "$j" -eq "$((i+1))" ]; then | |
| rst="${rst}${ci}," | |
| else | |
| rst="${rst}${ci}-${cj1}," | |
| fi | |
| i="$j" | |
| ci="${cj}" | |
| fi | |
| done | |
| if [ "$j" -eq "$((i+1))" ]; then | |
| rst="${rst}${ci}" | |
| else | |
| rst="${rst}${ci}-${cpus[$((j-1))]}" | |
| fi | |
| echo $rst | |
| } | |
| union() { | |
| local files | |
| declare -a files | |
| for cpus; do | |
| files+=($(expand_to_file "$cpus")) | |
| done | |
| shrink_internal $(sort -nu "${files[@]}") | |
| rm -f "${files[@]}" | |
| } | |
| intersect() { | |
| local files | |
| declare -a files | |
| for cpus; do | |
| files+=($(expand_to_file "$cpus")) | |
| done | |
| shrink_internal $(sort -n "${files[@]}" | uniq -c | awk "\$1==${#files[@]} {print \$2}") | |
| rm -f "${files[@]}" | |
| } | |
| minus() { | |
| local a="$1" | |
| local b="$2" | |
| local af="" | |
| local bf="" | |
| af=$(expand_to_file "$a") | |
| bf=$(expand_to_file "$b") | |
| shrink_internal $(sort -n "$af" "$bf" "$bf" | uniq -u) | |
| rm -f "$af" "$bf" | |
| } | |
| tomask() { | |
| local cpus | |
| cpus=($(expand "$1")) | |
| local n=${#cpus[@]} | |
| if [ $n -eq 0 ]; then | |
| echo 0 | |
| return | |
| fi | |
| local c=0 | |
| local ni=0 | |
| local nc="${cpus[0]}" | |
| local max="${cpus[$((n-1))]}" | |
| local rst="" | |
| local rst_c=0 | |
| for ((c=0; c<=max; c+=4)); do | |
| rst_c=0 | |
| while [ "$((c+3))" -ge "$nc" ]; do | |
| rst_c=$(( rst_c | (1<<(nc-c)) )) | |
| ni=$((ni+1)) | |
| if [ "$ni" -ge "$n" ]; then | |
| break | |
| fi | |
| nc=${cpus[$ni]} | |
| done | |
| rst="$(printf "%x" ${rst_c})${rst}" | |
| done | |
| echo "$rst" | |
| } | |
| todigit() { | |
| local c="" | |
| local src="$1" | |
| local i=${#src} | |
| local base=0 | |
| local rst | |
| declare -a rst | |
| for ((i=i-1; i>=0; i--)); do | |
| c=${src:$i:1} | |
| case "$c" in | |
| 0) | |
| true | |
| ;; | |
| 1) | |
| rst+=($((base+0))) | |
| ;; | |
| 2) | |
| rst+=($((base+1))) | |
| ;; | |
| 3) | |
| rst+=($((base+0))) | |
| rst+=($((base+1))) | |
| ;; | |
| 4) | |
| rst+=($((base+2))) | |
| ;; | |
| 5) | |
| rst+=($((base+0))) | |
| rst+=($((base+2))) | |
| ;; | |
| 6) | |
| rst+=($((base+1))) | |
| rst+=($((base+2))) | |
| ;; | |
| 7) | |
| rst+=($((base+0))) | |
| rst+=($((base+1))) | |
| rst+=($((base+2))) | |
| ;; | |
| 8) | |
| rst+=($((base+3))) | |
| ;; | |
| 9) | |
| rst+=($((base+0))) | |
| rst+=($((base+3))) | |
| ;; | |
| a|A) | |
| rst+=($((base+1))) | |
| rst+=($((base+3))) | |
| ;; | |
| b|B) | |
| rst+=($((base+0))) | |
| rst+=($((base+1))) | |
| rst+=($((base+3))) | |
| ;; | |
| c|C) | |
| rst+=($((base+2))) | |
| rst+=($((base+3))) | |
| ;; | |
| d|D) | |
| rst+=($((base+0))) | |
| rst+=($((base+2))) | |
| rst+=($((base+3))) | |
| ;; | |
| e|E) | |
| rst+=($((base+1))) | |
| rst+=($((base+2))) | |
| rst+=($((base+3))) | |
| ;; | |
| f|F) | |
| rst+=($((base+0))) | |
| rst+=($((base+1))) | |
| rst+=($((base+2))) | |
| rst+=($((base+3))) | |
| ;; | |
| *) | |
| echo "invalid mask '$src'" | |
| exit 1 | |
| ;; | |
| esac | |
| base=$((base+4)) | |
| done | |
| shrink_internal "${rst[@]}" | |
| } | |
| main() { | |
| if [ $# -eq 0 ]; then | |
| help | |
| exit 0 | |
| fi | |
| case "$1" in | |
| union) | |
| shift 1 | |
| if [ $# -eq 0 ]; then | |
| echo "at least 1 argument for union action" | |
| exit 1 | |
| fi | |
| union "$@" | |
| ;; | |
| intersect) | |
| shift 1 | |
| if [ $# -eq 0 ]; then | |
| echo "at least 1 argument for intersect action" | |
| exit 1 | |
| fi | |
| intersect "$@" | |
| ;; | |
| minus) | |
| if [ $# -ne 3 ]; then | |
| echo "expected exact 2 arguments for minus action" | |
| exit 1 | |
| fi | |
| minus "$2" "$3" | |
| ;; | |
| shrink) | |
| if [ $# -ne 2 ]; then | |
| echo "expected exact 1 argument for shrink action" | |
| exit 1 | |
| fi | |
| union "$2" | |
| ;; | |
| expand) | |
| if [ $# -ne 2 ]; then | |
| echo "expected exact 1 argument for expand action" | |
| exit 1 | |
| fi | |
| expand "$2" | |
| ;; | |
| tomask) | |
| if [ $# -ne 2 ]; then | |
| echo "expected exact 1 argument for tomask action" | |
| exit 1 | |
| fi | |
| tomask "$2" | |
| ;; | |
| todigit) | |
| if [ $# -ne 2 ]; then | |
| echo "expected exact 1 argument for todigit action" | |
| exit 1 | |
| fi | |
| todigit "$2" | |
| ;; | |
| *) | |
| echo "invalid action '$1'" | |
| help | |
| exit 1 | |
| ;; | |
| esac | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment