func (n *virtualnode) HintScore(hint topology.Hint) float64 {
	switch {
	case hint.CPUs != "":
		return cpuHintScore(hint, n.System().CPUSet())
	case hint.NUMAs != "":
		return OverfitPenalty * OverfitPenalty
	case hint.Sockets != "":
		return OverfitPenalty
	}
	return 0.0
}
HintScore calculates the (CPU) score of the node for the given topology hint.
package topologyaware
import (
	"fmt"
	system "github.com/intel/cri-resource-manager/pkg/sysfs"
	"github.com/intel/cri-resource-manager/pkg/topology"
	idset "github.com/intel/goresctrl/pkg/utils"
	"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
	"github.com/intel/cri-resource-manager/pkg/cri/resource-manager/kubernetes"
)
type NodeKind string
const (
	NilNode NodeKind = ""
	UnknownNode NodeKind = "unknown"
	SocketNode NodeKind = "socket"
	DieNode NodeKind = "die"
	NumaNode NodeKind = "numa node"
	VirtualNode NodeKind = "virtual node"
)
const (
	OverfitPenalty = 0.9
)
type Node interface {
	IsNil() bool
	Name() string
	Kind() NodeKind
	NodeID() int
	Parent() Node
	Children() []Node
	LinkParent(Node)
	AddChildren([]Node)
	IsSameNode(Node) bool
	IsRootNode() bool
	IsLeafNode() bool
	RootDistance() int
	NodeHeight() int
	System() system.System
	Policy() *policy
	DiscoverSupply(assignedNUMANodes []idset.ID) Supply
	GetSupply() Supply
	FreeSupply() Supply
	GrantedReservedCPU() int
	GrantedSharedCPU() int
	GetMemset(mtype memoryType) idset.IDSet
	AssignNUMANodes(ids []idset.ID)
	DepthFirst(func(Node) error) error
	BreadthFirst(func(Node) error) error
	Dump(string, ...int)
	dump(string, ...int)
	GetMemoryType() memoryType
	HasMemoryType(memoryType) bool
	GetPhysicalNodeIDs() []idset.ID
	GetScore(Request) Score
	HintScore(topology.Hint) float64
}
type node struct {
	policy   *policy      
	self     nodeself     
	name     string       
	id       int          
	kind     NodeKind     
	depth    int          
	parent   Node         
	children []Node       
	noderes  Supply       
	freeres  Supply       
	mem      idset.IDSet  
	pMem     idset.IDSet  
	hbm      idset.IDSet  
}
type nodeself struct {
	node Node
}
type socketnode struct {
	node                      
	id     idset.ID           
	syspkg system.CPUPackage  
}
type dienode struct {
	node                      
	id     idset.ID           
	syspkg system.CPUPackage  
}
type numanode struct {
	node                 
	id      idset.ID     
	sysnode system.Node  
}
type virtualnode struct {
	node  
}
var nilnode Node = &node{
	name:     "<nil node>",
	id:       -1,
	kind:     NilNode,
	depth:    -1,
	children: nil,
}
func (n *node) init(p *policy, name string, kind NodeKind, parent Node) {
	n.policy = p
	n.name = name
	n.kind = kind
	n.parent = parent
	n.id = -1
	n.LinkParent(parent)
	n.mem = idset.NewIDSet()
	n.pMem = idset.NewIDSet()
	n.hbm = idset.NewIDSet()
}
func (n *node) IsNil() bool {
	return n.kind == NilNode
}
func (n *node) Name() string {
	if n.IsNil() {
		return "<nil node>"
	}
	return n.name
}
func (n *node) Kind() NodeKind {
	return n.kind
}
func (n *node) NodeID() int {
	if n.IsNil() {
		return -1
	}
	return n.id
}
func (n *node) IsSameNode(other Node) bool {
	return n.NodeID() == other.NodeID()
}
func (n *node) IsRootNode() bool {
	return n.parent.IsNil()
}
func (n *node) IsLeafNode() bool {
	return len(n.children) == 0
}
func (n *node) RootDistance() int {
	if n.IsNil() {
		return -1
	}
	return n.depth
}
func (n *node) NodeHeight() int {
	if n.IsNil() {
		return -1
	}
	return n.policy.depth - n.depth
}
func (n *node) Parent() Node {
	if n.IsNil() {
		return nil
	}
	return n.parent
}
func (n *node) Children() []Node {
	if n.IsNil() {
		return nil
	}
	return n.children
}
func (n *node) LinkParent(parent Node) {
	n.parent = parent
	if !parent.IsNil() {
		parent.AddChildren([]Node{n})
	}
	n.depth = parent.RootDistance() + 1
}
func (n *node) AddChildren(nodes []Node) {
	n.children = append(n.children, nodes...)
}
func (n *node) Dump(prefix string, level ...int) {
	if !log.DebugEnabled() {
		return
	}
	lvl := 0
	if len(level) > 0 {
		lvl = level[0]
	}
	idt := indent(prefix, lvl)
	n.self.node.dump(prefix, lvl)
	log.Debug("%s  - %s", idt, n.noderes.DumpCapacity())
	log.Debug("%s  - %s", idt, n.freeres.DumpAllocatable())
	n.freeres.DumpMemoryState(idt + "  ")
	if n.mem.Size() > 0 {
		log.Debug("%s  - normal memory: %v", idt, n.mem)
	}
	if n.hbm.Size() > 0 {
		log.Debug("%s  - HBM memory: %v", idt, n.hbm)
	}
	if n.pMem.Size() > 0 {
		log.Debug("%s  - PMEM memory: %v", idt, n.pMem)
	}
	for _, grant := range n.policy.allocations.grants {
		cpuNodeID := grant.GetCPUNode().NodeID()
		memNodeID := grant.GetMemoryNode().NodeID()
		switch {
		case cpuNodeID == n.id && memNodeID == n.id:
			log.Debug("%s    + cpu+mem %s", idt, grant)
		case cpuNodeID == n.id:
			log.Debug("%s    + cpuonly %s", idt, grant)
		case memNodeID == n.id:
			log.Debug("%s    + memonly %s", idt, grant)
		}
	}
	if !n.Parent().IsNil() {
		log.Debug("%s  - parent: <%s>", idt, n.Parent().Name())
	}
	if len(n.children) > 0 {
		log.Debug("%s  - children:", idt)
		for _, c := range n.children {
			c.Dump(prefix, lvl+1)
		}
	}
}
func (n *node) dump(prefix string, level ...int) {
	n.self.node.dump(prefix, level...)
}
func (n *node) DepthFirst(fn func(Node) error) error {
	for _, c := range n.children {
		if err := c.DepthFirst(fn); err != nil {
			return err
		}
	}
	return fn(n)
}
func (n *node) BreadthFirst(fn func(Node) error) error {
	if err := fn(n); err != nil {
		return err
	}
	for _, c := range n.children {
		if err := c.BreadthFirst(fn); err != nil {
			return err
		}
	}
	return nil
}
func (n *node) System() system.System {
	return n.policy.sys
}
func (n *node) Policy() *policy {
	return n.policy
}
func (n *node) GetSupply() Supply {
	return n.self.node.GetSupply()
}
func (n *node) DiscoverSupply(assignedNUMANodes []idset.ID) Supply {
	return n.self.node.DiscoverSupply(assignedNUMANodes)
}
func (n *node) discoverSupply(assignedNUMANodes []idset.ID) Supply {
	if n.noderes != nil {
		return n.noderes.Clone()
	}
	if !n.IsLeafNode() {
		log.Debug("%s: cumulating child resources...", n.Name())
		if len(assignedNUMANodes) > 0 {
			log.Fatal("invalid pool setup: trying to attach NUMA nodes to non-leaf node %s",
				n.Name())
		}
		n.noderes = newSupply(n, cpuset.NewCPUSet(), cpuset.NewCPUSet(), cpuset.NewCPUSet(), 0, 0, nil, nil)
		for _, c := range n.children {
			supply := c.GetSupply()
			n.noderes.Cumulate(supply)
			n.mem.Add(c.GetMemset(memoryDRAM).Members()...)
			n.hbm.Add(c.GetMemset(memoryHBM).Members()...)
			n.pMem.Add(c.GetMemset(memoryPMEM).Members()...)
			log.Debug("  + %s", supply.DumpCapacity())
		}
		log.Debug("  = %s", n.noderes.DumpCapacity())
	} else {
		log.Debug("%s: discovering attached/assigned resources...", n.Name())
		mmap := createMemoryMap(0, 0, 0)
		cpus := cpuset.NewCPUSet()
		for _, nodeID := range assignedNUMANodes {
			node := n.System().Node(nodeID)
			nodeCPUs := node.CPUSet()
			meminfo, err := node.MemoryInfo()
			if err != nil {
				log.Fatal("%s: failed to get memory info for NUMA node #%d", n.Name(), nodeID)
			}
			switch node.GetMemoryType() {
			case system.MemoryTypeDRAM:
				n.mem.Add(nodeID)
				mmap.AddDRAM(meminfo.MemTotal)
				shortCPUs := kubernetes.ShortCPUSet(nodeCPUs)
				log.Debug("  + assigned DRAM NUMA node #%d (cpuset: %s, DRAM %.2fM)",
					nodeID, shortCPUs, float64(meminfo.MemTotal)/float64(1024*1024))
			case system.MemoryTypePMEM:
				n.pMem.Add(nodeID)
				mmap.AddPMEM(meminfo.MemTotal)
				log.Debug("  + assigned PMEM NUMA node #%d (DRAM %.2fM)", nodeID,
					float64(meminfo.MemTotal)/float64(1024*1024))
			case system.MemoryTypeHBM:
				n.hbm.Add(nodeID)
				mmap.AddHBM(meminfo.MemTotal)
				log.Debug("  + assigned HBMEM NUMA node #%d (DRAM %.2fM)",
					nodeID, float64(meminfo.MemTotal)/float64(1024*1024))
			default:
				log.Fatal("NUMA node #%d with unknown memory type %v", node.GetMemoryType())
			}
			allowed := nodeCPUs.Intersection(n.policy.allowed)
			isolated := allowed.Intersection(n.policy.isolated)
			reserved := allowed.Intersection(n.policy.reserved).Difference(isolated)
			sharable := allowed.Difference(isolated).Difference(reserved)
			if !reserved.IsEmpty() {
				log.Debug("    allowed reserved CPUs: %s", kubernetes.ShortCPUSet(reserved))
			}
			if !sharable.IsEmpty() {
				log.Debug("    allowed sharable CPUs: %s", kubernetes.ShortCPUSet(sharable))
			}
			if !isolated.IsEmpty() {
				log.Debug("    allowed isolated CPUs: %s", kubernetes.ShortCPUSet(isolated))
			}
			cpus = cpus.Union(allowed)
		}
		isolated := cpus.Intersection(n.policy.isolated)
		reserved := cpus.Intersection(n.policy.reserved).Difference(isolated)
		sharable := cpus.Difference(isolated).Difference(reserved)
		n.noderes = newSupply(n, isolated, reserved, sharable, 0, 0, mmap, nil)
		log.Debug("  = %s", n.noderes.DumpCapacity())
	}
	n.freeres = n.noderes.Clone()
	return n.noderes.Clone()
}
func (n *node) FreeSupply() Supply {
	return n.freeres
}
func (n *node) GetMemset(mtype memoryType) idset.IDSet {
	if n.self.node == nil {  
		return idset.NewIDSet()
	}
	return n.self.node.GetMemset(mtype)
}
func (n *node) AssignNUMANodes(ids []idset.ID) {
	n.self.node.AssignNUMANodes(ids)
}
func (n *node) assignNUMANodes(ids []idset.ID) {
	mem := createMemoryMap(0, 0, 0)
	for _, numaNodeID := range ids {
		if n.mem.Has(numaNodeID) || n.pMem.Has(numaNodeID) || n.hbm.Has(numaNodeID) {
			log.Warn("*** NUMA node #%d already discovered by or assigned to %s",
				numaNodeID, n.Name())
			continue
		}
		numaNode := n.policy.sys.Node(numaNodeID)
		memTotal := uint64(0)
		if meminfo, err := numaNode.MemoryInfo(); err != nil {
			log.Error("%s: failed to get memory info for NUMA node #%d",
				n.Name(), numaNodeID)
		} else {
			memTotal = meminfo.MemTotal
		}
		switch numaNode.GetMemoryType() {
		case system.MemoryTypeDRAM:
			mem.Add(memTotal, 0, 0)
			n.mem.Add(numaNodeID)
			log.Info("*** DRAM NUMA node #%d assigned to pool node %q",
				numaNodeID, n.Name())
		case system.MemoryTypePMEM:
			n.pMem.Add(numaNodeID)
			mem.Add(0, memTotal, 0)
			log.Info("*** PMEM NUMA node #%d assigned to pool node %q",
				numaNodeID, n.Name())
		case system.MemoryTypeHBM:
			n.hbm.Add(numaNodeID)
			mem.Add(0, 0, memTotal)
			log.Info("*** HBM NUMA node #%d assigned to pool node %q",
				numaNodeID, n.Name())
		default:
			log.Fatal("can't assign NUMA node #%d of type %v to pool node %q",
				numaNodeID, numaNode.GetMemoryType())
		}
	}
	n.noderes.AssignMemory(mem)
	n.freeres.AssignMemory(mem)
}
func (n *node) GetPhysicalNodeIDs() []idset.ID {
	return n.self.node.GetPhysicalNodeIDs()
}
func (n *node) GrantedReservedCPU() int {
	grantedReserved := n.freeres.GrantedReserved()
	for _, c := range n.children {
		grantedReserved += c.GrantedReservedCPU()
	}
	return grantedReserved
}
func (n *node) GrantedSharedCPU() int {
	grantedShared := n.freeres.GrantedShared()
	for _, c := range n.children {
		grantedShared += c.GrantedSharedCPU()
	}
	return grantedShared
}
func (n *node) GetScore(req Request) Score {
	f := n.FreeSupply()
	return f.GetScore(req)
}
func (n *node) HintScore(hint topology.Hint) float64 {
	return n.self.node.HintScore(hint)
}
func (n *node) GetMemoryType() memoryType {
	var memoryMask memoryType = 0x0
	if n.pMem.Size() > 0 {
		memoryMask |= memoryPMEM
	}
	if n.mem.Size() > 0 {
		memoryMask |= memoryDRAM
	}
	if n.hbm.Size() > 0 {
		memoryMask |= memoryHBM
	}
	return memoryMask
}
func (n *node) HasMemoryType(reqType memoryType) bool {
	nodeType := n.GetMemoryType()
	return (nodeType & reqType) == reqType
}
func (p *policy) NewNumaNode(id idset.ID, parent Node) Node {
	n := &numanode{}
	n.self.node = n
	n.node.init(p, fmt.Sprintf("NUMA node #%v", id), NumaNode, parent)
	n.id = id
	n.sysnode = p.sys.Node(id)
	return n
}
func (n *numanode) dump(prefix string, level ...int) {
	log.Debug("%s<NUMA node #%v>", indent(prefix, level...), n.id)
}
func (n *numanode) GetSupply() Supply {
	return n.noderes.Clone()
}
func (n *numanode) GetPhysicalNodeIDs() []idset.ID {
	return []idset.ID{n.id}
}
func (n *numanode) DiscoverSupply(assignedNUMANodes []idset.ID) Supply {
	return n.node.discoverSupply(assignedNUMANodes)
}
func (n *numanode) GetMemset(mtype memoryType) idset.IDSet {
	mset := idset.NewIDSet()
	if mtype&memoryDRAM != 0 {
		mset.Add(n.mem.Members()...)
	}
	if mtype&memoryHBM != 0 {
		mset.Add(n.hbm.Members()...)
	}
	if mtype&memoryPMEM != 0 {
		mset.Add(n.pMem.Members()...)
	}
	return mset
}
func (n *numanode) AssignNUMANodes(ids []idset.ID) {
	n.node.assignNUMANodes(ids)
}
func (n *numanode) HintScore(hint topology.Hint) float64 {
	switch {
	case hint.CPUs != "":
		return cpuHintScore(hint, n.sysnode.CPUSet())
	case hint.NUMAs != "":
		return numaHintScore(hint, n.id)
	case hint.Sockets != "":
		pkgID := n.sysnode.PackageID()
		score := socketHintScore(hint, n.sysnode.PackageID())
		if score > 0.0 {
			score /= float64(len(n.System().Package(pkgID).NodeIDs()))
		}
		return score
	}
	return 0.0
}
func (p *policy) NewDieNode(id idset.ID, parent Node) Node {
	pkg := parent.(*socketnode)
	n := &dienode{}
	n.self.node = n
	n.node.init(p, fmt.Sprintf("die #%v/%v", pkg.id, id), DieNode, parent)
	n.id = id
	n.syspkg = p.sys.Package(pkg.id)
	return n
}
func (n *dienode) dump(prefix string, level ...int) {
	log.Debug("%s<die #%v/%v>", indent(prefix, level...), n.syspkg.ID(), n.id)
}
func (n *dienode) GetSupply() Supply {
	return n.noderes.Clone()
}
func (n *dienode) GetPhysicalNodeIDs() []idset.ID {
	ids := make([]idset.ID, 0)
	ids = append(ids, n.id)
	for _, c := range n.children {
		cIds := c.GetPhysicalNodeIDs()
		ids = append(ids, cIds...)
	}
	return ids
}
func (n *dienode) DiscoverSupply(assignedNUMANodes []idset.ID) Supply {
	return n.node.discoverSupply(assignedNUMANodes)
}
func (n *dienode) GetMemset(mtype memoryType) idset.IDSet {
	mset := idset.NewIDSet()
	if mtype&memoryDRAM != 0 {
		mset.Add(n.mem.Members()...)
	}
	if mtype&memoryHBM != 0 {
		mset.Add(n.hbm.Members()...)
	}
	if mtype&memoryPMEM != 0 {
		mset.Add(n.pMem.Members()...)
	}
	return mset
}
func (n *dienode) AssignNUMANodes(ids []idset.ID) {
	n.node.assignNUMANodes(ids)
}
func (n *dienode) HintScore(hint topology.Hint) float64 {
	switch {
	case hint.CPUs != "":
		return cpuHintScore(hint, n.syspkg.CPUSet())
	case hint.NUMAs != "":
		return OverfitPenalty * dieHintScore(hint, n.id, n.syspkg)
	case hint.Sockets != "":
		score := socketHintScore(hint, n.syspkg.ID())
		if score > 0.0 {
			score /= float64(len(n.syspkg.DieNodeIDs(n.id)))
		}
		return score
	}
	return 0.0
}
func (p *policy) NewSocketNode(id idset.ID, parent Node) Node {
	n := &socketnode{}
	n.self.node = n
	n.node.init(p, fmt.Sprintf("socket #%v", id), SocketNode, parent)
	n.id = id
	n.syspkg = p.sys.Package(id)
	return n
}
func (n *socketnode) dump(prefix string, level ...int) {
	log.Debug("%s<socket #%v>", indent(prefix, level...), n.id)
}
func (n *socketnode) GetSupply() Supply {
	return n.noderes.Clone()
}
func (n *socketnode) GetPhysicalNodeIDs() []idset.ID {
	ids := make([]idset.ID, 0)
	ids = append(ids, n.id)
	for _, c := range n.children {
		cIds := c.GetPhysicalNodeIDs()
		ids = append(ids, cIds...)
	}
	return ids
}
func (n *socketnode) DiscoverSupply(assignedNUMANodes []idset.ID) Supply {
	return n.node.discoverSupply(assignedNUMANodes)
}
func (n *socketnode) GetMemset(mtype memoryType) idset.IDSet {
	mset := idset.NewIDSet()
	if mtype&memoryDRAM != 0 {
		mset.Add(n.mem.Members()...)
	}
	if mtype&memoryHBM != 0 {
		mset.Add(n.hbm.Members()...)
	}
	if mtype&memoryPMEM != 0 {
		mset.Add(n.pMem.Members()...)
	}
	return mset
}
func (n *socketnode) AssignNUMANodes(ids []idset.ID) {
	n.node.assignNUMANodes(ids)
}
func (n *socketnode) HintScore(hint topology.Hint) float64 {
	switch {
	case hint.CPUs != "":
		return cpuHintScore(hint, n.syspkg.CPUSet())
	case hint.NUMAs != "":
		return OverfitPenalty * numaHintScore(hint, n.syspkg.NodeIDs()...)
	case hint.Sockets != "":
		return socketHintScore(hint, n.id)
	}
	return 0.0
}
func (p *policy) NewVirtualNode(name string, parent Node) Node {
	n := &virtualnode{}
	n.self.node = n
	n.node.init(p, fmt.Sprintf("%s", name), VirtualNode, parent)
	return n
}
func (n *virtualnode) dump(prefix string, level ...int) {
	log.Debug("%s<virtual %s>", indent(prefix, level...), n.name)
}
func (n *virtualnode) GetSupply() Supply {
	return n.noderes.Clone()
}
func (n *virtualnode) DiscoverSupply(assignedNUMANodes []idset.ID) Supply {
	return n.node.discoverSupply(assignedNUMANodes)
}
func (n *virtualnode) GetMemset(mtype memoryType) idset.IDSet {
	mset := idset.NewIDSet()
	if mtype&memoryDRAM != 0 {
		mset.Add(n.mem.Members()...)
	}
	if mtype&memoryHBM != 0 {
		mset.Add(n.hbm.Members()...)
	}
	if mtype&memoryPMEM != 0 {
		mset.Add(n.pMem.Members()...)
	}
	return mset
}
func (n *virtualnode) AssignNUMANodes(ids []idset.ID) {
	log.Panic("cannot assign NUMA nodes #%s to %s",
		idset.NewIDSet(ids...).String(), n.Name())
}