func (c *collector) Describe(ch chan<- *prometheus.Desc) {
	for _, d := range descriptors {
		ch <- d
	}
}
Describe implements prometheus.Collector interface
package avx
import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"unsafe"
	bpf "github.com/cilium/ebpf"
	"github.com/intel/cri-resource-manager/pkg/cgroups"
	logger "github.com/intel/cri-resource-manager/pkg/log"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"golang.org/x/sys/unix"
)
const (
	LastCPUName = "last_cpu_avx_task_switches"
	AVXSwitchCountName = "avx_switch_count_per_cgroup"
	AllSwitchCountName = "all_switch_count_per_cgroup"
	LastUpdateNs = "last_update_ns"
	kernelTracepointPath = "/sys/kernel/debug/tracing/events"
	mapMemLockLimit = 524288
)
const (
	lastCPUDesc = iota
	avxSwitchCountDesc
	allSwitchCountDesc
	lastUpdateNsDesc
	numDescriptors
)
var descriptors = [numDescriptors]*prometheus.Desc{
	lastCPUDesc: prometheus.NewDesc(
		LastCPUName,
		"Number of task switches on the CPU where AVX512 instructions were used.",
		[]string{
			"cpu_id",
		}, nil,
	),
	avxSwitchCountDesc: prometheus.NewDesc(
		AVXSwitchCountName,
		"Number of task switches where AVX512 instructions were used in a particular cgroup.",
		[]string{
			"container_id",
		}, nil,
	),
	allSwitchCountDesc: prometheus.NewDesc(
		AllSwitchCountName,
		"Total number of task switches in a particular cgroup.",
		[]string{
			"container_id",
		}, nil,
	),
	lastUpdateNsDesc: prometheus.NewDesc(
		"last_update_ns",
		"Time since last AVX512 activity in a particular cgroup.",
		[]string{
			"container_id",
		}, nil,
	),
}
var (
	bpfBinaryName  = "avx512.o"
	bpfInstallpath = "/usr/libexec/bpf"
	log = logger.NewLogger("avx")
)
type collector struct {
	root string
	ebpf *bpf.Collection
	fds  []int
}
func enablePerfTracepoint(prog *bpf.Program, tracepoint string) (int, error) {
	id, err := ioutil.ReadFile(filepath.Join(kernelTracepointPath, tracepoint, "id"))
	if err != nil {
		return -1, errors.Wrap(err, "unable to read tracepoint ID")
	}
	tid, err := strconv.Atoi(strings.TrimSpace(string(id)))
	if err != nil {
		return -1, errors.New("unable to convert tracepoint ID")
	}
	attr := unix.PerfEventAttr{
		Type:        unix.PERF_TYPE_TRACEPOINT,
		Config:      uint64(tid),  
		Sample_type: unix.PERF_SAMPLE_RAW,
		Sample:      1,
		Wakeup:      1,
	}
	pfd, err := unix.PerfEventOpen(&attr, -1, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
	if err != nil {
		return -1, errors.Wrap(err, "unable to open perf events")
	}
	if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(pfd), unix.PERF_EVENT_IOC_ENABLE, 0); errno != 0 {
		return -1, errors.Errorf("unable to set up perf events: %s", errno)
	}
	if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(pfd), unix.PERF_EVENT_IOC_SET_BPF, uintptr(prog.FD())); errno != 0 {
		return -1, errors.Errorf("unable to attach bpf program to perf events: %s", errno)
	}
	return pfd, nil
}
func getKernelVersion() uint32 {
	var uts unix.Utsname
	err := unix.Uname(&uts)
	if err != nil {
		return 0
	}
	str := string(bytes.SplitN(uts.Release[:], []byte{0}, 2)[0])
	ver := strings.SplitN(str, ".", 3)
	major, err := strconv.ParseUint(ver[0], 10, 8)
	if err != nil {
		return 0
	}
	minor, err := strconv.ParseUint(ver[1], 10, 8)
	if err != nil {
		return uint32(major << 16)
	}
	return uint32(major<<16 + minor<<8)
}
func kernelVersionStr(v uint32) string {
	return fmt.Sprintf("%d.%d.0", v>>16, (v>>8)&0xff)
}
func NewCollector() (prometheus.Collector, error) {
	memlockLimit := &unix.Rlimit{
		Cur: mapMemLockLimit,
		Max: mapMemLockLimit,
	}
	err := unix.Setrlimit(unix.RLIMIT_MEMLOCK, memlockLimit)
	if err != nil {
		return nil, errors.Wrap(err, "unable to set rlimit")
	}
	spec, err := bpf.LoadCollectionSpec(filepath.Join(bpfInstallpath, bpfBinaryName))
	if err != nil {
		log.Info("Unable to load user eBPF (%v). Using default CollectionSpec from ELF program bytes", err)
		spec, err = bpf.LoadCollectionSpecFromReader(bytes.NewReader(program[:]))
		if err != nil {
			return nil, errors.Wrap(err, "unable to load default CollectionSpec from ELF program bytes")
		}
	}
	hostVer := getKernelVersion()
	progVer := spec.Programs["tracepoint__x86_fpu_regs_deactivated"].KernelVersion
	if hostVer < progVer {
		return nil, errors.Wrapf(err, "The host kernel version (v%s) is too old to run the AVX512 collector program. Minimum version is v%s.", kernelVersionStr(hostVer), kernelVersionStr(progVer))
	}
	collection, err := bpf.NewCollection(spec)
	if err != nil {
		return nil, errors.Wrap(err, "unable to create new Collection")
	}
	ffd, err := enablePerfTracepoint(collection.Programs["tracepoint__x86_fpu_regs_deactivated"], "x86_fpu/x86_fpu_regs_deactivated")
	if err != nil {
		return nil, errors.Wrap(err, "unable to enable fpu tracepoint")
	}
	sfd, err := enablePerfTracepoint(collection.Programs["tracepoint__sched_switch"], "sched/sched_switch")
	if err != nil {
		return nil, errors.Wrap(err, "unable to enable sched tracepoint")
	}
	return &collector{
		root: cgroups.GetV2Dir(),
		ebpf: collection,
		fds:  []int{ffd, sfd},
	}, nil
}