#!/bin/sh
# SPDX-License-Identifier: GPL-2.0+
#
# Produce awk statements roughly depicting the system's CPU and cache
# layout.  If the required information is not available, produce
# error messages as awk comments.  Successful exit regardless.
#
# Usage: kvm-assign-cpus.sh /path/to/sysfs

T=/tmp/kvm-assign-cpus.sh.$$
trap 'rm -rf $T' 0 2
mkdir $T

sysfsdir=${1-/sys/devices/system/node}
if ! cd "$sysfsdir" > $T/msg 2>&1
then
	sed -e 's/^/# /' < $T/msg
	exit 0
fi
nodelist="`ls -d node*`"
for i in node*
do
	if ! test -d $i/
	then
		echo "# Not a directory: $sysfsdir/node*"
		exit 0
	fi
	for j in $i/cpu*/cache/index*
	do
		if ! test -d $j/
		then
			echo "# Not a directory: $sysfsdir/$j"
			exit 0
		else
			break
		fi
	done
	indexlist="`ls -d $i/cpu* | grep 'cpu[0-9][0-9]*' | head -1 | sed -e 's,^.*$,ls -d &/cache/index*,' | sh | sed -e 's,^.*/,,'`"
	break
done
for i in node*/cpu*/cache/index*/shared_cpu_list
do
	if ! test -f $i
	then
		echo "# Not a file: $sysfsdir/$i"
		exit 0
	else
		break
	fi
done
firstshared=
for i in $indexlist
do
	rm -f $T/cpulist
	for n in node*
	do
		f="$n/cpu*/cache/$i/shared_cpu_list"
		if ! cat $f > $T/msg 2>&1
		then
			sed -e 's/^/# /' < $T/msg
			exit 0
		fi
		cat $f >> $T/cpulist
	done
	if grep -q '[-,]' $T/cpulist
	then
		if test -z "$firstshared"
		then
			firstshared="$i"
		fi
	fi
done
if test -z "$firstshared"
then
	splitindex="`echo $indexlist | sed -e 's/ .*$//'`"
else
	splitindex="$firstshared"
fi
nodenum=0
for n in node*
do
	cat $n/cpu*/cache/$splitindex/shared_cpu_list | sort -u -k1n |
	awk -v nodenum="$nodenum" '
	BEGIN {
		idx = 0;
	}

	{
		nlists = split($0, cpulists, ",");
		for (i = 1; i <= nlists; i++) {
			listsize = split(cpulists[i], cpus, "-");
			if (listsize == 1)
				cpus[2] = cpus[1];
			for (j = cpus[1]; j <= cpus[2]; j++) {
				print "cpu[" nodenum "][" idx "] = " j ";";
				idx++;
			}
		}
	}

	END {
		print "nodecpus[" nodenum "] = " idx ";";
	}'
	nodenum=`expr $nodenum + 1`
done
echo "numnodes = $nodenum;"
