#!/bin/sh
#-*-sh-*-

#
# SPDX-License-Identifier: BSD-3-Clause
# Copyright © 2009, 2024 CNRS
# Copyright © 2009-2025 Inria.  All rights reserved.
# Copyright © 2009, 2011 Université Bordeaux
# Copyright © 2014 Cisco Systems, Inc.  All rights reserved.
# See COPYING in top-level directory.
#

HWLOC_top_srcdir="@HWLOC_top_srcdir@"
HWLOC_top_builddir="@HWLOC_top_builddir@"
srcdir="$HWLOC_top_srcdir/utils/hwloc"
builddir="$HWLOC_top_builddir/utils/hwloc"
calc="$builddir/hwloc-calc"
xmldir="$HWLOC_top_srcdir/tests/hwloc/xml"
linuxdir="$HWLOC_top_srcdir/tests/hwloc/linux"

HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc/.libs
export HWLOC_PLUGINS_PATH

HWLOC_DEBUG_CHECK=1
export HWLOC_DEBUG_CHECK

: ${TMPDIR=/tmp}
{
  tmp=`
    (umask 077 && mktemp -d "$TMPDIR/fooXXXXXX") 2>/dev/null
  ` &&
  test -n "$tmp" && test -d "$tmp"
} || {
  tmp=$TMPDIR/foo$$-$RANDOM
  (umask 077 && mkdir "$tmp")
} || exit $?
file="$tmp/test-hwloc-calc.output"

set -e
(
  echo "# root --cpuset-output-format hwloc"
  $calc --if synthetic --input "node:4 core:4 pu:4" root --cpuset-output-format hwloc
  echo
  echo "# all --cof list"
  $calc --if synthetic --input "node:4 core:4 pu:4" all --cof list
  echo
  echo "# all --cpuset-output-format taskset"
  $calc --if synthetic --input "node:4 core:4 pu:4" all --cpuset-output-format taskset
  echo

  echo "# hex"
  $calc --if synthetic --input "node:4 core:4 pu:4" 0xf
  echo
  echo "# hex combination"
  $calc --if synthetic --input "node:4 core:4 pu:4" 0xf ~0x3 0xff0 '^0xf0'
  echo
  echo "# object combination"
  $calc --if synthetic --input "node:4 core:4 pu:4" core:0 pu:15 ~pu:0 '^pu:2'
  echo

  echo "# --no-smt NUMA Node range"
  $calc --if synthetic --input "node:4 core:4 pu:4" --no-smt node:2-3
  echo
  echo "# --no-smt hex"
  $calc --if synthetic --input "node:4 core:4 pu:4" --no-smt 0x1fe
  echo
  echo "# --no-smt=1 hex"
  $calc --if synthetic --input "node:4 core:4 pu:4" --no-smt=1 0x1fe
  echo
  echo "# --no-smt=2 hex"
  $calc --if synthetic --input "node:4 core:4 pu:4" --no-smt=2 0x1fe
  echo
  echo "# --no-smt=3 hex"
  $calc --if synthetic --input "node:4 core:4 pu:4" --no-smt=3 0x1fe
  echo
  echo "# --no-smt=4 hex"
  $calc --if synthetic --input "node:4 core:4 pu:4" --no-smt=4 0x1fe
  echo
  echo "# --no-smt=-1 hex"
  $calc --if synthetic --input "node:4 core:4 pu:4" --no-smt=-1 0x1fe
  echo

  echo "# even PUs"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:even
  echo
  echo "# NUMA Nodes 2+"
  $calc --if synthetic --input "node:4 core:4 pu:4" node:2-
  echo
  echo "# cores 12+"
  $calc --if synthetic --input "node:4 core:4 pu:4" core:12-
  echo
  echo "# PU wrapping range"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:62:10
  echo
  echo "# some PUs in all Cores"
  $calc --if synthetic --input "node:4 core:4 pu:4" core:all.pu:1:2
  echo
  echo "# one PU in odd Cores"
  $calc --if synthetic --input "node:4 core:4 pu:4" core:odd.pu:0
  echo
  echo "# combination of different ranges, hierarchical or not"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:6:2 core:3-4.pu:1-3 node:2.pu:14:2 node:3.core:3.pu:3
  echo

  echo "# number of Group0 when there are 3 group levels"
  $calc --if synthetic --input "group:2 node:2 group:2 pu:2" -N group0 all
  echo
  echo "# list of Group1 near one Group0 when there are 3 group levels"
  $calc --if synthetic --input "group:2 node:2 group:2 pu:2" -I group1 group0:0
  echo
  echo "# hierarchical list of Group0.Group2 near one NUMA when there are 3 group levels"
  $calc --if synthetic --input "group:2 node:2 group:2 pu:2" -H group0.group2 numa:3
  echo
  echo "# number of Group2 when there are 3 group levels"
  $calc --if synthetic --input "group:2 node:2 group:2 pu:2" -N group2 all
  echo

  echo "# Number of NUMA Nodes"
  $calc --if synthetic --input "node:4 core:4 pu:4" root --number-of node
  echo
  echo "# Number of Cores in a NUMA Node"
  $calc --if synthetic --input "node:4 core:4 pu:4" node:2 -N core
  echo
  echo "# Number of objects at depth 3 in a NUMA Node"
  $calc --if synthetic --input "node:4 core:4 pu:4" node:2 -N 3
  echo
  echo "# Number of MCDRAM subtype NUMA Nodes"
  $calc --if xml --input $xmldir/64intel64-fakeKNL-SNC4-hybrid.xml -N 'numa[mcdram]' all
  echo
  echo "# List of MCDRAM subtype NUMA Nodes near 2 L3"
  $calc --if xml --input $xmldir/64intel64-fakeKNL-SNC4-hybrid.xml -I 'numa[mcdram]' l3:1-2
  echo
  echo "# Hierarchical list of MCDRAM subtype NUMA nodes within Package (DDR node is ignored)"
  $calc --if xml --input $xmldir/64intel64-fakeKNL-SNC4-hybrid.xml -H 'pack.numa[mcdram]' 'numa[mcdram]:0' 'numa[ddr]:1' 'numa[mcdram]:3'
  echo
  echo "# List of default NUMA Nodes in a Package"
  $calc --if xml --input $xmldir/64intel64-fakeKNL-SNC4-hybrid.xml --default-nodes -I NUMANode -p Package:0
  echo
  echo "# Number of Memory Tiers"
  $calc --if xml --input $xmldir/64intel64-fakeKNL-SNC4-hybrid.xml -N memorytier all
  echo
  echo "# Memory Tier of a single node"
  $calc --if xml --input $xmldir/64intel64-fakeKNL-SNC4-hybrid.xml -I memorytier node:4
  echo
  echo "# Check that we don't mix a single input NUMA node with other local nodes"
  $calc --if synthetic -i "pack:2 [numa] group:2 [numa] [numa] pu:2" -I node node:2
  echo
  echo "# Check that we find CPU-less NUMA nodes like others"
  $calc --if synthetic -i "pack:4 [numa] pu:2" --restrict 0xc3 -I node node:1 node:2
  echo

  echo "# List of Machine objects"
  $calc --if synthetic --input "node:4 core:4 pu:4" root --intersect Machine
  echo
  echo "# List of NUMA Nodes in a range of Cores"
  $calc --if synthetic --input "node:4 core:4 pu:4" core:4-7 -I NUMANode
  echo
  echo "# List of NUMA Nodes in a range of Cores (again)"
  $calc --if synthetic --input "node:4 core:4 pu:4" core:10-15 -I NUMANode --oo
  echo

  echo "# Hierarchical spec for a range of PUs"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:2-3 --hierarchical group.pu
  echo
  echo "# Hierarchical spec for a range of PUs, with different separator"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:3-6 -H group.core --sep foo
  echo
  echo "# Hierarchical spec for a range of PUs (again)"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:3-6 -H core.pu
  echo
  echo "# List of PUs from another invocation with hierarchical output"
  $calc --if synthetic --input "node:4 core:4 pu:4" -I pu `$calc --if synthetic --input "node:4 core:4 pu:4" pu:3-6 -H core.pu`
  echo
  echo "# Hierarchical spec for a range of PUs (3 levels)"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:11:4 -H group.core.pu
  echo
  echo "# List of PUs from another invocation with hierarchical output (again)"
  $calc --if synthetic --input "node:4 core:4 pu:4" -I pu `$calc --if synthetic --input "node:4 core:4 pu:4" pu:11:4 -H group.core.pu`
  echo

  echo "# --largest"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:12-37 --largest
  echo
  echo "# --largest, with different separator"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:22-47 --largest --sep "_"
  echo

  echo "# Singlified output"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:22-47 --single
  echo
  echo "# Singlified PU list"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:22-47 --single --pulist
  echo

  echo "# PU list with physical output"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:33-37 --pulist --po
  echo
  echo "# NUMA Node list of physical output and different separator"
  $calc --if synthetic --input "node:4 core:4 pu:4" pu:30-37 --nodelist --po --sep foo
  echo

  echo "# Manipulating NUMA Nodes with nodesets"
  $calc --if synthetic --input "node:4 core:4 pu:4" -n node:1-2
  echo
  echo "# Nodeset output of PUs"
  $calc --if synthetic --input "node:4 core:4 pu:4" --no pu:63
  echo
  echo "# Converting NUMA Nodes from logical to physical"
  $calc --if synthetic --input "node:4 core:4 pu:4" --ni 0x5 --nodelist --po
  echo

  echo "# Search cores within single NUMA when they have multiple local NUMA nodes"
  $calc --if synthetic --input "pack:2 [numa] [numa] core:4 pu:1" sock:1.numa:1.core:1-2
  echo
  echo "# Search NUMA node within single Group when they have multiple local Groups"
  $calc --if synthetic --input "pack:2 [numa] group:2 core:4 1" --nodeset-output pack:1.group:1.numa:0
  echo

  echo "# Physical output of NUMA Nodes when out-of-order in the topology"
  $calc --if synthetic --input "node:4(indexes=3,2,1,0) pu:2" node:1-2 --po -I node
  echo
  echo "# Converting physical to logical PU indexes when complexly ordered in the topology"
  $calc --if synthetic --input "node:4 core:4 pu:4(indexes=node:core)" --pi pu:2-5 -I pu
  echo

  echo "# 4 local nodes near a Package (node:3-4@Die + node:5@Package + node:6@Machine)"
  $calc --if synthetic --input "[numa] pack:2 [numa] die:2 [numa] pu:2" --local-memory package:1
  echo
  echo "# 2 local nodes larger or equal to a Package (node:2@Package + node:6@Machine), with space separator"
  $calc --if synthetic --input "[numa] pack:2 [numa] die:2 [numa] pu:2" --local-memory-flags 1 --sep " " pack:0 --oo
  echo
  echo "# Best-locality local node near a PU (node:1@Die)"
  $calc --if synthetic --input "[numa] pack:2 [numa] die:2 [numa] pu:2" --best-memattr locality pu:3 --oo
  echo
  echo "# Best-capacity local node near a PU (node:6@Machine)"
  $calc --if synthetic --input "[numa(memory=1000000)] pack:2 [numa(memory=100000)] die:2 [numa(memory=1000)] pu:2" --best-memattr capacity pu:4
  echo

  echo
  echo "# no node is local to one pu of each package"
  $calc --if synthetic --input "pack:2 [numa] pu:2" --local-memory-flags small,large pack:all.pu:0 
  echo
  echo "# 1 node is local to one package and one pu of the other"
  $calc --if synthetic --input "pack:2 [numa] pu:2" --local-memory-flags small,large pack:0 pack:1.pu:0
  echo
  echo "# both nodes are local to one pu of each package, if intersecting"
  $calc --if synthetic --input "pack:2 [numa] pu:2" --local-memory-flags intersect pack:all.pu:0 --oo
  echo
  echo "# both nodes are local to one package and one pu of the other, if intersecting"
  $calc --if synthetic --input "pack:2 [numa] pu:2" --local-memory-flags intersect pack:0 pack:1.pu:0
  echo
  echo "# all local nodes"
  $calc --if synthetic --input "pack:2 [numa] pu:2" --local-memory-flags _all pu:0 --sep "%"
  echo

  echo
  echo "# CPU kind by index"
  $calc --if xml --input $linuxdir/fakeheterocpunuma.output --cpukind 1 all
  echo
  echo "# CPU kind by wrong index"
  $calc --if xml --input $linuxdir/fakeheterocpunuma.output --cpukind 3 all
  echo
  echo "# CPU kind by info attr"
  $calc --if xml --input $linuxdir/fakeheterocpunuma.output --cpukind FrequencyMaxMHz=3000 all
  echo
  echo "# Number of CPU kinds"
  $calc --if xml --input $linuxdir/fakeheterocpunuma.output -N cpukind 0xf0f0
  echo
  echo "# List of CPU kinds"
  $calc --if xml --input $linuxdir/fakeheterocpunuma.output -I cpukind 0xff00
  echo

  echo "# Caches with attributes"
  $calc --if synthetic --input "numa:2 l3:2 pu:1" numa:0 l3u:3
  echo
  echo "# Groups with attributes"
  $calc --if synthetic --input "group:2 numa:2 l2:2 l1d:2 pu:1" Group0:1 NUMA:0
  echo
  echo "# Caches without attributes"
  $calc --if synthetic --input "group:2 numa:2 l2:2 l1d:2 pu:1" l2:0-2 L1cache:13:3
  echo

  echo "# OS devices by name"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml os=eth6 os=eth4
  echo
  echo "# OS devices by name (again)"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml os=sdc os=sr0 ~os=sda
  echo
  echo "# OS devices by range"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml os:7-8
  echo
  echo "# PCI devices by range"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci:10-11
  echo
  echo "# PCI devices by vendors/device IDs and range wrapping around"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci'[1000:0062]':3:2
  echo
  echo "# PCI devices by vendors/device IDs and index"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci'[14e4:1639]':1
  echo
  echo "# PCI devices by vendors/device IDs and range"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci'[14e4:1639]':2-5
  echo
  echo "# PCI devices added"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci=0000:62:00.1 pci=0000:02:00.1
  echo
  echo "# PCI devices intersection"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci=0000:62:00.1 xpci=0000:02:00.0
  echo
  echo "# PCI devices intersection (again)"
  $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci=0000:02:00.0 xpci=0000:02:00.1
  echo
  echo "# Restrict"
  $calc -i "node:4 pu:4" --restrict 0xf0 --restrict-flags cpuless all -N pu
  $calc -i "node:4 pu:4" --restrict 0xf0 --restrict-flags cpuless all -N numa
  $calc -i "node:4 pu:4" --restrict-flags bynode,memless --restrict 0x3 all -N pu
  $calc -i "node:4 pu:4" --restrict 0xff0 --restrict-flags none all -N pu
  $calc -i "node:4 pu:4" --restrict-flags cpuless --restrict 0xff0 all -I numa --po
  echo

  echo "# Converting from hwloc cpusets to taskset"
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format taskset 0xf,0xf0,f00f
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format taskset --cpuset-input-format hwloc 1,3,5
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format taskset 1,3,5
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format taskset --cif hwloc 0xf...f
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cof taskset 0xf...f,0x1
  echo
  echo "# Converting from list cpusets to hwloc"
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format hwloc 3-
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format hwloc 3-4,7-34,62,66
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format hwloc --cpuset-input-format list 7
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cof hwloc --cif list 1,3,5
  echo
  echo "# Converting from taskset cpusets to list"
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format list 0xf000000f00000f00f
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format list --cif taskset 0x1234567
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cof list 0xf...f00
  echo

  echo "# Converting a cpuset to the systemd-dbus-api format"
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format systemd-dbus-api 0x01
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format systemd-dbus-api 0x80000001
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format systemd-dbus-api 0x8000000080000001
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format systemd-dbus-api 0xf000000f00000f00f
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format systemd-dbus-api "" && exit 1
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format systemd-dbus-api "0xf...f" && exit 1 # infinite cpuset cannot be represented -> KO
  $calc --if synthetic --input "node:4 core:4 pu:4"  --cpuset-output-format systemd-dbus-api --cpuset-input-format systemd-dbus-api "foo bar" && exit 1

  echo "# Converting a nodeset to the systemd-dbus-api format"
  $calc --if synthetic --input "node:4 core:4 pu:4"  --nodeset-output-format systemd-dbus-api node:0 node:2
  $calc --if synthetic --input "node:4 core:4 pu:4"  --nodeset-output-format systemd-dbus-api "" && exit 1
  $calc --if synthetic --input "node:4 core:4 pu:4"  --nodeset-output-format systemd-dbus-api "0xf...f" # infinite cpuset translates to a finite nodeset -> OK
  $calc --if synthetic --input "node:4 core:4 pu:4"  --nodeset-output-format systemd-dbus-api --cpuset-input-format systemd-dbus-api "foo bar" && exit 1
  echo

  echo "# Reading from stdin"
  cat << EOF | $calc --if synthetic --input "node:4 core:4 pu:4"
pu:0
core:0 core:15
node:0 node:3
0x0001 0x00002 0x000004 0x000000000008
0x0000000000000000000000000000000000000000000000000000000000000000000000000000001
0x1,0x0,0x0
root
EOF
  echo
  echo "# Reading infinite cpusets from stdin"
  cat << EOF | $calc --if synthetic --input "node:4 core:4 pu:4" -q
  0xf...f
0xf...f,abcd00
0xf...f,abcd,ef00
0xf...ff00
0xf...fff0000ffff0000
EOF
  echo
  echo "# Reading infinite cpusets from stdin and exporting to taskset"
  cat << EOF | $calc --if synthetic --input "node:4 core:4 pu:4" --cpuset-output-format taskset
  0xf...f
0xf...f,abcd00
0xf...f,abcd,ef00
0xf...ff00
0xf...fff0000ffff0000
EOF
  echo
) > "$file"
@DIFF@ @HWLOC_DIFF_U@ @HWLOC_DIFF_W@ $srcdir/test-hwloc-calc.output "$file"
rm -rf "$tmp"
