forked from kubernetes/kubernetes
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request kubernetes#29 from intelsdi-x/squall0gd/ext-iso-di…
…scovery-module CPU Discovery
- Loading branch information
Showing
3 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package cputopology | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
) | ||
|
||
// CPU struct contains information about logical CPU. | ||
type CPU struct { | ||
// SocketID represents socket where CPU is. | ||
SocketID int | ||
// CoreID represents core where CPU is. | ||
CoreID int | ||
// CPUID is unique CPU number. | ||
CPUID int | ||
// IsIsolated stores information is CPU is not use by OS scheduler. | ||
IsIsolated bool | ||
// IsInUse stores information is CPU already reserved. | ||
IsInUse bool | ||
} | ||
|
||
type CPUTopology struct { | ||
CPU []CPU | ||
Lock sync.Mutex | ||
} | ||
|
||
func (c *CPUTopology) GetNumSockets() int { | ||
socketCounter := 0 | ||
for _, cpu := range c.CPU { | ||
if cpu.SocketID > socketCounter { | ||
socketCounter = cpu.SocketID | ||
} | ||
} | ||
return socketCounter + 1 | ||
} | ||
|
||
func (c *CPUTopology) GetSocket(socketID int) (cores []CPU) { | ||
for _, cpu := range c.CPU { | ||
if cpu.SocketID == socketID { | ||
cores = append(cores, cpu) | ||
} | ||
} | ||
return | ||
} | ||
|
||
func (c *CPUTopology) GetCore(socketID, coreID int) (cpus []CPU) { | ||
for _, cpu := range c.CPU { | ||
if cpu.SocketID == socketID && cpu.CoreID == coreID { | ||
cpus = append(cpus, cpu) | ||
} | ||
} | ||
return | ||
} | ||
|
||
func (c *CPUTopology) GetCPU(cpuid int) *CPU { | ||
for idx, _ := range c.CPU { | ||
if c.CPU[idx].CPUID == cpuid { | ||
return &c.CPU[idx] | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (c *CPUTopology) Reserve(cpuid int) error { | ||
c.Lock.Lock() | ||
defer c.Lock.Unlock() | ||
cpuAddress := c.GetCPU(cpuid) | ||
if cpuAddress.IsInUse { | ||
return fmt.Errorf("selected core(%d) is in use.", cpuid) | ||
} | ||
cpuAddress.IsInUse = true | ||
return nil | ||
} | ||
|
||
func (c *CPUTopology) Reclaim(cpuid int) { | ||
c.Lock.Lock() | ||
defer c.Lock.Unlock() | ||
cpuAddress := c.GetCPU(cpuid) | ||
cpuAddress.IsInUse = false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package discovery | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io/ioutil" | ||
"os/exec" | ||
"strconv" | ||
"strings" | ||
|
||
"k8s.io/kubernetes/cluster/addons/iso-client/cputopology" | ||
) | ||
|
||
func DiscoverTopology() (*cputopology.CPUTopology, error) { | ||
isolatedCPUs, err := isolcpus() | ||
if err != nil { | ||
return nil, err | ||
} | ||
lscpuOutput, err := lscpuExecution() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return cpuParse(lscpuOutput, isolatedCPUs) | ||
} | ||
|
||
func lscpuExecution() (string, error) { | ||
var stdout bytes.Buffer | ||
|
||
cmd := exec.Command("lscpu", "-p") | ||
|
||
cmd.Stdout = &stdout | ||
err := cmd.Run() | ||
if err != nil { | ||
return "", fmt.Errorf("Cannot run lscpu: %q", err) | ||
} | ||
return stdout.String(), nil | ||
} | ||
|
||
func isolcpus() ([]int, error) { | ||
data, err := ioutil.ReadFile("/proc/cmdline") | ||
if err != nil { | ||
return nil, fmt.Errorf("Cannot read /proc/cmdline: %q", err) | ||
} | ||
return retriveIsolcpus(string(data)) | ||
} | ||
|
||
func retriveIsolcpus(data string) ([]int, error) { | ||
var isolcpusValues []string | ||
var cpus []int | ||
|
||
data = strings.Trim(data, "\n") | ||
|
||
for _, parameter := range strings.Split(data, " ") { | ||
parameterParts := strings.Split(parameter, "=") | ||
if len(parameterParts) != 2 { | ||
continue | ||
} | ||
key := parameterParts[0] | ||
if key != "isolcpus" { | ||
continue | ||
} | ||
isolcpusValues = append(isolcpusValues, strings.Split(parameterParts[1], ",")...) | ||
} | ||
|
||
for _, cpu := range isolcpusValues { | ||
parsedCPU, err := strconv.Atoi(cpu) | ||
if err != nil { | ||
return nil, fmt.Errorf("Cannot retrive isolcpu from list: %q", err) | ||
} | ||
cpus = append(cpus, parsedCPU) | ||
} | ||
return cpus, nil | ||
} | ||
|
||
func cpuParse(lscpuStringOutput string, isolatedCPUs []int) (*cputopology.CPUTopology, error) { | ||
lscpuRawSlice := strings.Split(lscpuStringOutput, "\n") | ||
var cpuTopology cputopology.CPUTopology | ||
|
||
for _, line := range lscpuRawSlice { | ||
if strings.Index(line, "#") != -1 || strings.Compare(line, "") == 0 { | ||
continue | ||
} | ||
|
||
var cpuid, core, socket int | ||
_, err := fmt.Sscanf(line, "%d,%d,%d", &cpuid, &core, &socket) | ||
if err != nil { | ||
return nil, fmt.Errorf("Cannot parse lscpu output: %q", err) | ||
} | ||
|
||
cpuTopology.CPU = append(cpuTopology.CPU, cputopology.CPU{ | ||
SocketID: socket, | ||
CoreID: core, | ||
CPUID: cpuid, | ||
IsIsolated: isCPUIsolated(cpuid, isolatedCPUs), | ||
}) | ||
|
||
} | ||
|
||
return &cpuTopology, nil | ||
} | ||
|
||
func isCPUIsolated(cpuid int, isolatedCPUs []int) bool { | ||
for _, isolatedCPU := range isolatedCPUs { | ||
if cpuid == isolatedCPU { | ||
return true | ||
} | ||
} | ||
return false | ||
} |