Skip to content

Commit

Permalink
Merge pull request kubernetes#29 from intelsdi-x/squall0gd/ext-iso-di…
Browse files Browse the repository at this point in the history
…scovery-module

CPU Discovery
  • Loading branch information
pprokop authored Mar 31, 2017
2 parents 042dec1 + e58abc4 commit 901642e
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 0 deletions.
8 changes: 8 additions & 0 deletions cluster/addons/iso-client/coreaffinity-isolator.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
// "k8s.io/apimachinery/pkg/util/uuid"

aff "k8s.io/kubernetes/cluster/addons/iso-client/coreaffinity"
"k8s.io/kubernetes/cluster/addons/iso-client/discovery"
)

const (
Expand All @@ -27,6 +28,13 @@ const (
func main() {
flag.Parse()
glog.Info("Starting ...")
cpuTopo, err := discovery.DiscoverTopology()
if err != nil {
glog.Fatalf("Cannot retrive CPU topology: %q", err)
}

glog.Infof("Detected topology: %v", cpuTopo)

var wg sync.WaitGroup
// Starting isolatorServer
server := aff.NewIsolator(name, isolatorLocalAddress)
Expand Down
80 changes: 80 additions & 0 deletions cluster/addons/iso-client/cputopology/cpu.go
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
}
109 changes: 109 additions & 0 deletions cluster/addons/iso-client/discovery/cpu_discovery.go
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
}

0 comments on commit 901642e

Please sign in to comment.