func parseMemoryType(value string) (memoryType, error) {
	if value == "" {
		return memoryUnspec, nil
	}
	mtype := 0
	for _, typestr := range strings.Split(value, ",") {
		t, ok := memoryNamedTypes[strings.ToLower(typestr)]
		if !ok {
			return memoryUnspec, policyError("unknown memory type value '%s'", typestr)
		}
		mtype |= int(t)
	}
	return memoryType(mtype), nil
}
parseMemoryType parses a memory type string, ideally produced by String()
package topologyaware
import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"
	"sigs.k8s.io/yaml"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"github.com/intel/cri-resource-manager/pkg/config"
	"github.com/intel/cri-resource-manager/pkg/cri/resource-manager/cache"
	"github.com/intel/cri-resource-manager/pkg/cri/resource-manager/kubernetes"
)
const (
	keyIsolationPreference = "prefer-isolated-cpus"
	keySharedCPUPreference = "prefer-shared-cpus"
	keyMemoryTypePreference = "memory-type"
	keyColdStartPreference = "cold-start"
	preferIsolatedCPUsKey = keyIsolationPreference + "." + kubernetes.ResmgrKeyNamespace
	preferSharedCPUsKey = keySharedCPUPreference + "." + kubernetes.ResmgrKeyNamespace
	preferMemoryTypeKey = keyMemoryTypePreference + "." + kubernetes.ResmgrKeyNamespace
	preferColdStartKey = keyColdStartPreference + "." + kubernetes.ResmgrKeyNamespace
)
type cpuClass int
var cpuClassNames = map[cpuClass]string{
	cpuNormal:   "normal",
	cpuReserved: "reserved",
}
const (
	cpuNormal cpuClass = iota
	cpuReserved
)
var memoryNamedTypes = map[string]memoryType{
	"dram":  memoryDRAM,
	"pmem":  memoryPMEM,
	"hbm":   memoryHBM,
	"mixed": memoryAll,
}
var memoryTypeNames = map[memoryType]string{
	memoryDRAM: "DRAM",
	memoryPMEM: "PMEM",
	memoryHBM:  "HBM",
}
type memoryType int
const (
	memoryUnspec memoryType = (0x1 << iota) >> 1
	memoryDRAM
	memoryPMEM
	memoryHBM
	memoryFirstUnusedBit
	memoryAll = memoryFirstUnusedBit - 1
	defaultMemoryType = memoryAll
)
func isolatedCPUsPreference(pod cache.Pod, container cache.Container) (bool, bool) {
	key := preferIsolatedCPUsKey
	value, ok := pod.GetEffectiveAnnotation(key, container.GetName())
	if !ok {
		return podIsolationPreference(pod, container)
	}
	preference, err := strconv.ParseBool(value)
	if err != nil {
		log.Error("invalid CPU isolation preference annotation (%q, %q): %v",
			key, value, err)
		return opt.PreferIsolated, false
	}
	log.Debug("%s: effective CPU isolation preference %v", container.PrettyName(), preference)
	return preference, true
}
func sharedCPUsPreference(pod cache.Pod, container cache.Container) (bool, bool) {
	key := preferSharedCPUsKey
	value, ok := pod.GetEffectiveAnnotation(key, container.GetName())
	if !ok {
		return podSharedCPUPreference(pod, container)
	}
	preference, err := strconv.ParseBool(value)
	if err != nil {
		log.Error("invalid shared CPU preference annotation (%q, %q): %v",
			key, value, err)
		return opt.PreferShared, false
	}
	log.Debug("%s: effective shared CPU preference %v", container.PrettyName(), preference)
	return preference, true
}
func memoryTypePreference(pod cache.Pod, container cache.Container) memoryType {
	key := preferMemoryTypeKey
	value, ok := pod.GetEffectiveAnnotation(key, container.GetName())
	if !ok {
		return podMemoryTypePreference(pod, container)
	}
	mtype, err := parseMemoryType(value)
	if err != nil {
		log.Error("invalid memory type preference (%q, %q): %v", key, value, err)
		return memoryUnspec
	}
	log.Debug("%s: effective cold start preference %v", container.PrettyName(), mtype)
	return mtype
}
func coldStartPreference(pod cache.Pod, container cache.Container) (ColdStartPreference, error) {
	key := preferColdStartKey
	value, ok := pod.GetEffectiveAnnotation(key, container.GetName())
	if !ok {
		return podColdStartPreference(pod, container)
	}
	preference := ColdStartPreference{}
	if err := yaml.Unmarshal([]byte(value), &preference); err != nil {
		log.Error("failed to parse cold start preference (%q, %q): %v",
			keyColdStartPreference, value, err)
		return ColdStartPreference{}, policyError("invalid cold start preference %q: %v",
			value, err)
	}
	if preference.Duration < 0 || time.Duration(preference.Duration) > time.Hour {
		return ColdStartPreference{}, policyError("cold start duration %s out of range",
			preference.Duration.String())
	}
	log.Debug("%s: effective cold start preference %v",
		container.PrettyName(), preference.Duration.String())
	return preference, nil
}
func podIsolationPreference(pod cache.Pod, container cache.Container) (bool, bool) {
	key := keyIsolationPreference
	value, ok := pod.GetResmgrAnnotation(key)
	if !ok {
		return opt.PreferIsolated, false
	}
	log.Warn("WARNING: using deprecated annotation %q", key)
	log.Warn("WARNING: consider using instead")
	log.Warn("WARNING:     %q, or", preferIsolatedCPUsKey+"/container."+container.GetName())
	log.Warn("WARNING:     %q", preferIsolatedCPUsKey+"/pod")
	if value == "false" || value == "true" {
		return (value[0] == 't'), true
	}
	preferences := map[string]bool{}
	if err := yaml.Unmarshal([]byte(value), &preferences); err != nil {
		log.Error("failed to parse isolation preference %s = '%s': %v",
			keyIsolationPreference, value, err)
		return opt.PreferIsolated, false
	}
	name := container.GetName()
	if pref, ok := preferences[name]; ok {
		log.Debug("%s per-container isolation preference '%v'", name, pref)
		return pref, true
	}
	log.Debug("%s defaults to isolation preference '%v'", name, opt.PreferIsolated)
	return opt.PreferIsolated, false
}
func podSharedCPUPreference(pod cache.Pod, container cache.Container) (bool, bool) {
	key := keySharedCPUPreference
	value, ok := pod.GetResmgrAnnotation(key)
	if !ok {
		return opt.PreferShared, false
	}
	log.Warn("WARNING: using deprecated annotation %q", key)
	log.Warn("WARNING: consider using instead")
	log.Warn("WARNING:     %q, or", preferSharedCPUsKey+"/container."+container.GetName())
	log.Warn("WARNING:     %q", preferSharedCPUsKey+"/pod")
	if value == "false" || value == "true" {
		return value[0] == 't', true
	}
	preferences := map[string]string{}
	if err := yaml.Unmarshal([]byte(value), &preferences); err != nil {
		log.Error("failed to parse shared CPU preference %s = '%s': %v",
			keySharedCPUPreference, value, err)
		return opt.PreferShared, false
	}
	name := container.GetName()
	pref, ok := preferences[name]
	if !ok {
		return opt.PreferShared, false
	}
	if pref == "false" || pref == "true" {
		return pref[0] == 't', true
	}
	log.Error("invalid shared CPU boolean preference for container %s: %s", name, pref)
	return opt.PreferShared, false
}
type ColdStartPreference struct {
	Duration config.Duration  
}
func podColdStartPreference(pod cache.Pod, container cache.Container) (ColdStartPreference, error) {
	key := keyColdStartPreference
	value, ok := pod.GetResmgrAnnotation(key)
	if !ok {
		return ColdStartPreference{}, nil
	}
	log.Warn("WARNING: using deprecated annotation %q", key)
	log.Warn("WARNING: consider using instead")
	log.Warn("WARNING:     %q, or", preferColdStartKey+"/container."+container.GetName())
	log.Warn("WARNING:     %q", preferColdStartKey+"/pod")
	preferences := map[string]ColdStartPreference{}
	if err := yaml.Unmarshal([]byte(value), &preferences); err != nil {
		log.Error("failed to parse cold start preference %s = '%s': %v",
			key, value, err)
		return ColdStartPreference{}, err
	}
	name := container.GetName()
	preference, ok := preferences[name]
	if !ok {
		log.Debug("container %s has no entry among cold start preferences", container.PrettyName())
		return ColdStartPreference{}, nil
	}
	if preference.Duration < 0 || time.Duration(preference.Duration) > time.Hour {
		return ColdStartPreference{}, fmt.Errorf("failed to validate cold start timeout %s: value out of scope", preference.Duration.String())
	}
	return preference, nil
}
func cpuAllocationPreferences(pod cache.Pod, container cache.Container) (int, int, bool, cpuClass) {
	namespace := container.GetNamespace()
	request := container.GetResourceRequirements().Requests[corev1.ResourceCPU]
	qosClass := pod.GetQOSClass()
	fraction := int(request.MilliValue())
	switch {
	case namespace == metav1.NamespaceSystem:
		return 0, fraction, false, cpuReserved
	case qosClass == corev1.PodQOSBurstable:
		return 0, fraction, false, cpuNormal
	case qosClass == corev1.PodQOSBestEffort:
		return 0, 0, false, cpuNormal
	}
	cores := fraction / 1000
	fraction = fraction % 1000
	preferIsolated, explicitIsolated := isolatedCPUsPreference(pod, container)
	preferShared, explicitShared := sharedCPUsPreference(pod, container)
	switch {
	case cores == 0:
		return 0, fraction, false, cpuNormal
	case cores < 2:
		if fraction > 0 {
			if preferShared {
				return 0, 1000*cores + fraction, false, cpuNormal
			}
			return cores, fraction, preferIsolated, cpuNormal
		}
		if preferShared && explicitShared {
			return 0, 1000*cores + fraction, false, cpuNormal
		}
		return cores, fraction, preferIsolated, cpuNormal
	default:
		if fraction > 0 {
			if !preferShared && explicitShared {
				return cores, fraction, preferIsolated && explicitIsolated, cpuNormal
			}
			return 0, 1000*cores + fraction, false, cpuNormal
		}
		if preferShared && explicitShared {
			return 0, 1000 * cores, false, cpuNormal
		}
		return cores, fraction, preferIsolated && explicitIsolated, cpuNormal
	}
}
func podMemoryTypePreference(pod cache.Pod, c cache.Container) memoryType {
	key := keyMemoryTypePreference
	value, ok := pod.GetResmgrAnnotation(key)
	if !ok {
		log.Debug("pod %s has no memory preference annotations", pod.GetName())
		return memoryUnspec
	}
	log.Warn("WARNING: using deprecated annotation %q", key)
	log.Warn("WARNING: consider using instead")
	log.Warn("WARNING:     %q, or", keyMemoryTypePreference+"/container."+c.GetName())
	log.Warn("WARNING:     %q", keyMemoryTypePreference+"/pod")
	pref := ""
	preferences := map[string]string{}
	if err := yaml.Unmarshal([]byte(value), &preferences); err == nil {
		name := c.GetName()
		p, ok := preferences[name]
		if !ok {
			log.Debug("container %s has no entry among memory preferences", c.PrettyName())
			return memoryUnspec
		}
		pref = p
	} else {
		pref = value
	}
	mtype, err := parseMemoryType(pref)
	if err != nil {
		log.Error("invalid memory type preference ('%s') in annotation %s: %v",
			pref, keyMemoryTypePreference, err)
		return memoryUnspec
	}
	log.Debug("container %s has effective memory preference: %s", c.PrettyName(), mtype)
	return mtype
}
func memoryAllocationPreference(pod cache.Pod, c cache.Container) (uint64, uint64, memoryType) {
	resources := c.GetResourceRequirements()
	mtype := memoryTypePreference(pod, c)
	req, lim := uint64(0), uint64(0)
	if memReq, ok := resources.Requests[corev1.ResourceMemory]; ok {
		req = uint64(memReq.Value())
	}
	if memLim, ok := resources.Limits[corev1.ResourceMemory]; ok {
		lim = uint64(memLim.Value())
	}
	return req, lim, mtype
}
func (t cpuClass) String() string {
	if cpuClassName, ok := cpuClassNames[t]; ok {
		return cpuClassName
	}
	return fmt.Sprintf("#UNNAMED-CPUCLASS(%d)", int(t))
}
func (t memoryType) String() string {
	str := ""
	sep := ""
	for _, bit := range []memoryType{memoryDRAM, memoryPMEM, memoryHBM} {
		if int(t)&int(bit) != 0 {
			str += sep + memoryTypeNames[bit]
			sep = ","
		}
	}
	return str
}