Skip to content

Commit

Permalink
cpu[darwin]: separetes cpu_darwin to cgo and nocgo to get CPUTimes.
Browse files Browse the repository at this point in the history
  • Loading branch information
shirou committed Oct 10, 2015
1 parent 3303647 commit a95dde9
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 100 deletions.
100 changes: 0 additions & 100 deletions cpu/cpu_darwin.go
Expand Up @@ -2,27 +2,10 @@

package cpu

/*
#include <stdlib.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#include <libproc.h>
#include <mach/processor_info.h>
#include <mach/vm_map.h>
*/
import "C"

import (
"bytes"
"encoding/binary"
"fmt"
"os/exec"
"strconv"
"strings"
"unsafe"
)

// sys/resource.h
Expand All @@ -38,89 +21,6 @@ const (
// default value. from time.h
var ClocksPerSec = float64(128)

// these CPU times for darwin is borrowed from influxdb/telegraf.

func perCPUTimes() ([]CPUTimesStat, error) {
var (
count C.mach_msg_type_number_t
cpuload *C.processor_cpu_load_info_data_t
ncpu C.natural_t
)

status := C.host_processor_info(C.host_t(C.mach_host_self()),
C.PROCESSOR_CPU_LOAD_INFO,
&ncpu,
(*C.processor_info_array_t)(unsafe.Pointer(&cpuload)),
&count)

if status != C.KERN_SUCCESS {
return nil, fmt.Errorf("host_processor_info error=%d", status)
}

// jump through some cgo casting hoops and ensure we properly free
// the memory that cpuload points to
target := C.vm_map_t(C.mach_task_self_)
address := C.vm_address_t(uintptr(unsafe.Pointer(cpuload)))
defer C.vm_deallocate(target, address, C.vm_size_t(ncpu))

// the body of struct processor_cpu_load_info
// aka processor_cpu_load_info_data_t
var cpu_ticks [C.CPU_STATE_MAX]uint32

// copy the cpuload array to a []byte buffer
// where we can binary.Read the data
size := int(ncpu) * binary.Size(cpu_ticks)
buf := C.GoBytes(unsafe.Pointer(cpuload), C.int(size))

bbuf := bytes.NewBuffer(buf)

var ret []CPUTimesStat

for i := 0; i < int(ncpu); i++ {
err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks)
if err != nil {
return nil, err
}

c := CPUTimesStat{
CPU: fmt.Sprintf("cpu%d", i),
User: float64(cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
System: float64(cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
Nice: float64(cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
Idle: float64(cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
}

ret = append(ret, c)
}

return ret, nil
}

func allCPUTimes() ([]CPUTimesStat, error) {
var count C.mach_msg_type_number_t = C.HOST_CPU_LOAD_INFO_COUNT
var cpuload C.host_cpu_load_info_data_t

status := C.host_statistics(C.host_t(C.mach_host_self()),
C.HOST_CPU_LOAD_INFO,
C.host_info_t(unsafe.Pointer(&cpuload)),
&count)

if status != C.KERN_SUCCESS {
return nil, fmt.Errorf("host_statistics error=%d", status)
}

c := CPUTimesStat{
CPU: "cpu-total",
User: float64(cpuload.cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
System: float64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
Nice: float64(cpuload.cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
Idle: float64(cpuload.cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
}

return []CPUTimesStat{c}, nil

}

func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
if percpu {
return perCPUTimes()
Expand Down
107 changes: 107 additions & 0 deletions cpu/cpu_darwin_cgo.go
@@ -0,0 +1,107 @@
// +build darwin
// +build cgo

package cpu

/*
#include <stdlib.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#include <libproc.h>
#include <mach/processor_info.h>
#include <mach/vm_map.h>
*/
import "C"

import (
"bytes"
"encoding/binary"
"fmt"
"unsafe"
)

// these CPU times for darwin is borrowed from influxdb/telegraf.

func perCPUTimes() ([]CPUTimesStat, error) {
var (
count C.mach_msg_type_number_t
cpuload *C.processor_cpu_load_info_data_t
ncpu C.natural_t
)

status := C.host_processor_info(C.host_t(C.mach_host_self()),
C.PROCESSOR_CPU_LOAD_INFO,
&ncpu,
(*C.processor_info_array_t)(unsafe.Pointer(&cpuload)),
&count)

if status != C.KERN_SUCCESS {
return nil, fmt.Errorf("host_processor_info error=%d", status)
}

// jump through some cgo casting hoops and ensure we properly free
// the memory that cpuload points to
target := C.vm_map_t(C.mach_task_self_)
address := C.vm_address_t(uintptr(unsafe.Pointer(cpuload)))
defer C.vm_deallocate(target, address, C.vm_size_t(ncpu))

// the body of struct processor_cpu_load_info
// aka processor_cpu_load_info_data_t
var cpu_ticks [C.CPU_STATE_MAX]uint32

// copy the cpuload array to a []byte buffer
// where we can binary.Read the data
size := int(ncpu) * binary.Size(cpu_ticks)
buf := C.GoBytes(unsafe.Pointer(cpuload), C.int(size))

bbuf := bytes.NewBuffer(buf)

var ret []CPUTimesStat

for i := 0; i < int(ncpu); i++ {
err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks)
if err != nil {
return nil, err
}

c := CPUTimesStat{
CPU: fmt.Sprintf("cpu%d", i),
User: float64(cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
System: float64(cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
Nice: float64(cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
Idle: float64(cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
}

ret = append(ret, c)
}

return ret, nil
}

func allCPUTimes() ([]CPUTimesStat, error) {
var count C.mach_msg_type_number_t = C.HOST_CPU_LOAD_INFO_COUNT
var cpuload C.host_cpu_load_info_data_t

status := C.host_statistics(C.host_t(C.mach_host_self()),
C.HOST_CPU_LOAD_INFO,
C.host_info_t(unsafe.Pointer(&cpuload)),
&count)

if status != C.KERN_SUCCESS {
return nil, fmt.Errorf("host_statistics error=%d", status)
}

c := CPUTimesStat{
CPU: "cpu-total",
User: float64(cpuload.cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
System: float64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
Nice: float64(cpuload.cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
Idle: float64(cpuload.cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
}

return []CPUTimesStat{c}, nil

}
14 changes: 14 additions & 0 deletions cpu/cpu_darwin_nocgo.go
@@ -0,0 +1,14 @@
// +build darwin
// +build !cgo

package cpu

import "github.com/shirou/gopsutil/common"

func perCPUTimes() ([]CPUTimesStat, error) {
return []CPUTimesStat{}, common.NotImplementedError
}

func allCPUTimes() ([]CPUTimesStat, error) {
return []CPUTimesStat{}, common.NotImplementedError
}

1 comment on commit a95dde9

@FarnazMostowfi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Guys, I am trying to install Telegraf on Darwin 10.8 and I get this error: github.com/shirou/gopsutil/cpu.Cvar_mach_task_self: undefined: mach_task_self_
Any idea what is happening? is this a compatibility problem?
Appreciate your help.
Farnaz

Please sign in to comment.