//go:build linux

package cpu

import (
	
	
	
	
	
	
	

	
)

var ClocksPerSec = float64(100)

func init() {
	,  := exec.LookPath("getconf")
	if  != nil {
		return
	}
	,  := invoke.CommandWithContext(context.Background(), , "CLK_TCK")
	// ignore errors
	if  == nil {
		,  := strconv.ParseFloat(strings.TrimSpace(string()), 64)
		if  == nil {
			ClocksPerSec = 
		}
	}
}

func ( bool) ([]TimesStat, error) {
	return TimesWithContext(context.Background(), )
}

func ( context.Context,  bool) ([]TimesStat, error) {
	 := common.HostProc("stat")
	 := []string{}
	if  {
		,  := common.ReadLines()
		if  != nil || len() < 2 {
			return []TimesStat{}, nil
		}
		for ,  := range [1:] {
			if !strings.HasPrefix(, "cpu") {
				break
			}
			 = append(, )
		}
	} else {
		, _ = common.ReadLinesOffsetN(, 0, 1)
	}

	 := make([]TimesStat, 0, len())

	for ,  := range  {
		,  := parseStatLine()
		if  != nil {
			continue
		}
		 = append(, *)

	}
	return , nil
}

func sysCPUPath( int32,  string) string {
	return common.HostSys(fmt.Sprintf("devices/system/cpu/cpu%d", ), )
}

func finishCPUInfo( *InfoStat) error {
	var  []string
	var  error
	var  float64

	if len(.CoreID) == 0 {
		,  = common.ReadLines(sysCPUPath(.CPU, "topology/core_id"))
		if  == nil {
			.CoreID = [0]
		}
	}

	// override the value of c.Mhz with cpufreq/cpuinfo_max_freq regardless
	// of the value from /proc/cpuinfo because we want to report the maximum
	// clock-speed of the CPU for c.Mhz, matching the behaviour of Windows
	,  = common.ReadLines(sysCPUPath(.CPU, "cpufreq/cpuinfo_max_freq"))
	// if we encounter errors below such as there are no cpuinfo_max_freq file,
	// we just ignore. so let Mhz is 0.
	if  != nil || len() == 0 {
		return nil
	}
	,  = strconv.ParseFloat([0], 64)
	if  != nil {
		return nil
	}
	.Mhz =  / 1000.0 // value is in kHz
	if .Mhz > 9999 {
		.Mhz = .Mhz / 1000.0 // value in Hz
	}
	return nil
}

// CPUInfo on linux will return 1 item per physical thread.
//
// CPUs have three levels of counting: sockets, cores, threads.
// Cores with HyperThreading count as having 2 threads per core.
// Sockets often come with many physical CPU cores.
// For example a single socket board with two cores each with HT will
// return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1.
func () ([]InfoStat, error) {
	return InfoWithContext(context.Background())
}

func ( context.Context) ([]InfoStat, error) {
	 := common.HostProc("cpuinfo")
	,  := common.ReadLines()

	var  []InfoStat
	var  string

	 := InfoStat{CPU: -1, Cores: 1}
	for ,  := range  {
		 := strings.Split(, ":")
		if len() < 2 {
			continue
		}
		 := strings.TrimSpace([0])
		 := strings.TrimSpace([1])

		switch  {
		case "Processor":
			 = 
		case "processor":
			if .CPU >= 0 {
				 := finishCPUInfo(&)
				if  != nil {
					return , 
				}
				 = append(, )
			}
			 = InfoStat{Cores: 1, ModelName: }
			,  := strconv.ParseInt(, 10, 64)
			if  != nil {
				return , 
			}
			.CPU = int32()
		case "vendorId", "vendor_id":
			.VendorID = 
		case "cpu family":
			.Family = 
		case "model":
			.Model = 
		case "model name", "cpu":
			.ModelName = 
			if strings.Contains(, "POWER8") ||
				strings.Contains(, "POWER7") {
				.Model = strings.Split(, " ")[0]
				.Family = "POWER"
				.VendorID = "IBM"
			}
		case "stepping", "revision":
			 := 

			if  == "revision" {
				 = strings.Split(, ".")[0]
			}

			,  := strconv.ParseInt(, 10, 64)
			if  != nil {
				return , 
			}
			.Stepping = int32()
		case "cpu MHz", "clock":
			// treat this as the fallback value, thus we ignore error
			if ,  := strconv.ParseFloat(strings.Replace(, "MHz", "", 1), 64);  == nil {
				.Mhz = 
			}
		case "cache size":
			,  := strconv.ParseInt(strings.Replace(, " KB", "", 1), 10, 64)
			if  != nil {
				return , 
			}
			.CacheSize = int32()
		case "physical id":
			.PhysicalID = 
		case "core id":
			.CoreID = 
		case "flags", "Features":
			.Flags = strings.FieldsFunc(, func( rune) bool {
				return  == ',' ||  == ' '
			})
		case "microcode":
			.Microcode = 
		}
	}
	if .CPU >= 0 {
		 := finishCPUInfo(&)
		if  != nil {
			return , 
		}
		 = append(, )
	}
	return , nil
}

func parseStatLine( string) (*TimesStat, error) {
	 := strings.Fields()

	if len() == 0 {
		return nil, errors.New("stat does not contain cpu info")
	}

	if !strings.HasPrefix([0], "cpu") {
		return nil, errors.New("not contain cpu")
	}

	 := [0]
	if  == "cpu" {
		 = "cpu-total"
	}
	,  := strconv.ParseFloat([1], 64)
	if  != nil {
		return nil, 
	}
	,  := strconv.ParseFloat([2], 64)
	if  != nil {
		return nil, 
	}
	,  := strconv.ParseFloat([3], 64)
	if  != nil {
		return nil, 
	}
	,  := strconv.ParseFloat([4], 64)
	if  != nil {
		return nil, 
	}
	,  := strconv.ParseFloat([5], 64)
	if  != nil {
		return nil, 
	}
	,  := strconv.ParseFloat([6], 64)
	if  != nil {
		return nil, 
	}
	,  := strconv.ParseFloat([7], 64)
	if  != nil {
		return nil, 
	}

	 := &TimesStat{
		CPU:     ,
		User:     / ClocksPerSec,
		Nice:     / ClocksPerSec,
		System:   / ClocksPerSec,
		Idle:     / ClocksPerSec,
		Iowait:   / ClocksPerSec,
		Irq:      / ClocksPerSec,
		Softirq:  / ClocksPerSec,
	}
	if len() > 8 { // Linux >= 2.6.11
		,  := strconv.ParseFloat([8], 64)
		if  != nil {
			return nil, 
		}
		.Steal =  / ClocksPerSec
	}
	if len() > 9 { // Linux >= 2.6.24
		,  := strconv.ParseFloat([9], 64)
		if  != nil {
			return nil, 
		}
		.Guest =  / ClocksPerSec
	}
	if len() > 10 { // Linux >= 3.2.0
		,  := strconv.ParseFloat([10], 64)
		if  != nil {
			return nil, 
		}
		.GuestNice =  / ClocksPerSec
	}

	return , nil
}

func ( context.Context,  bool) (int, error) {
	if  {
		 := 0
		// https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_pslinux.py#L599
		 := common.HostProc("cpuinfo")
		,  := common.ReadLines()
		if  == nil {
			for ,  := range  {
				 = strings.ToLower()
				if strings.HasPrefix(, "processor") {
					++
				}
			}
		}
		if  == 0 {
			 := common.HostProc("stat")
			,  = common.ReadLines()
			if  != nil {
				return 0, 
			}
			for ,  := range  {
				if len() >= 4 && strings.HasPrefix(, "cpu") && '0' <= [3] && [3] <= '9' { // `^cpu\d` regexp matching
					++
				}
			}
		}
		return , nil
	}
	// physical cores
	// https://github.com/giampaolo/psutil/blob/122174a10b75c9beebe15f6c07dcf3afbe3b120d/psutil/_pslinux.py#L621-L629
	 := make(map[string]bool)
	if ,  := filepath.Glob(common.HostSys("devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list"));  == nil {
		for ,  := range  {
			,  := common.ReadLines()
			if  != nil || len() != 1 {
				continue
			}
			[[0]] = true
		}
		 := len()
		if  != 0 {
			return , nil
		}
	}
	// https://github.com/giampaolo/psutil/blob/122174a10b75c9beebe15f6c07dcf3afbe3b120d/psutil/_pslinux.py#L631-L652
	 := common.HostProc("cpuinfo")
	,  := common.ReadLines()
	if  != nil {
		return 0, 
	}
	 := make(map[int]int)
	 := make(map[string]int)
	for ,  := range  {
		 = strings.ToLower(strings.TrimSpace())
		if  == "" {
			// new section
			,  := ["physical id"]
			,  := ["cpu cores"]
			if  &&  {
				[] = 
			}
			 = make(map[string]int)
			continue
		}
		 := strings.Split(, ":")
		if len() < 2 {
			continue
		}
		[0] = strings.TrimSpace([0])
		if [0] == "physical id" || [0] == "cpu cores" {
			,  := strconv.Atoi(strings.TrimSpace([1]))
			if  != nil {
				continue
			}
			[[0]] = 
		}
	}
	 := 0
	for ,  := range  {
		 += 
	}
	return , nil
}