Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using purego on darwin #1700

Closed
uubulb opened this issue Aug 30, 2024 · 1 comment
Closed

Using purego on darwin #1700

uubulb opened this issue Aug 30, 2024 · 1 comment

Comments

@uubulb
Copy link
Contributor

uubulb commented Aug 30, 2024

Is your feature request related to a problem? Please describe.
cgo implementions on darwin #66

Describe the solution you'd like
purego has relatively good support for Darwin, perhaps gopsutil can use it to replace current cgo implementations.
I tried to port perCPUTimes with purego and it seems working:

package main

import (
	"fmt"
	"unsafe"

	"github.com/ebitengine/purego"
)

const (
	KERN_SUCCESS            = 0
	PROCESSOR_CPU_LOAD_INFO = 2

	CPU_STATE_USER          = 0
	CPU_STATE_SYSTEM        = 1
	CPU_STATE_IDLE          = 2
	CPU_STATE_NICE          = 3
	CPU_STATE_MAX           = 4
)

var (
	hostProcessorInfo func(host uint32, flavor int, outProcessorCount *uint32, outProcessorInfo uintptr,
		outProcessorInfoCnt *uint32) int
	machHostSelf func() uint32
	machTaskSelf func() uint32
	vmDeallocate func(targetTask uint32, vmAddress, vmSize uintptr) int
)

var ClocksPerSec = float64(128)

type processorCpuLoadInfo struct {
	cpuTicks [CPU_STATE_MAX]uint32
}

type cpuStat struct {
	CPU    string
	User   float64
	System float64
	Nice   float64
	Idle   float64
}

func main() {
	mach, err := purego.Dlopen("/usr/lib/system/libsystem_kernel.dylib", purego.RTLD_LAZY|purego.RTLD_GLOBAL)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer purego.Dlclose(mach)

	purego.RegisterLibFunc(&hostProcessorInfo, mach, "host_processor_info")
	purego.RegisterLibFunc(&machHostSelf, mach, "mach_host_self")
	purego.RegisterLibFunc(&machTaskSelf, mach, "mach_task_self")
	purego.RegisterLibFunc(&vmDeallocate, mach, "vm_deallocate")

	var count, ncpu uint32
	var cpuload *processorCpuLoadInfo

	status := hostProcessorInfo(machHostSelf(), PROCESSOR_CPU_LOAD_INFO, &ncpu,
		uintptr(unsafe.Pointer(&cpuload)), &count)

	if status != KERN_SUCCESS {
		return
	}

	defer vmDeallocate(machTaskSelf(), uintptr(unsafe.Pointer(cpuload)), uintptr(ncpu))

	ret := []cpuStat{}
	loads := unsafe.Slice(cpuload, ncpu)

	for i := 0; i < int(ncpu); i++ {
		c := cpuStat{
			CPU:    fmt.Sprintf("cpu%d", i),
			User:   float64(loads[i].cpuTicks[CPU_STATE_USER]) / ClocksPerSec,
			System: float64(loads[i].cpuTicks[CPU_STATE_SYSTEM]) / ClocksPerSec,
			Nice:   float64(loads[i].cpuTicks[CPU_STATE_NICE]) / ClocksPerSec,
			Idle:   float64(loads[i].cpuTicks[CPU_STATE_IDLE]) / ClocksPerSec,
		}

		ret = append(ret, c)
	}

	fmt.Println(ret)
}

The output values should resemble those of the cgo counterpart.

Describe alternatives you've considered
N/A

Additional context
N/A

@shirou
Copy link
Owner

shirou commented Aug 31, 2024

Thank you for your suggestion. Yes, I completely and totally agree. I've always thought that purego is a great library for gopsutil. However, there is one problem—I don't own a mac, so I can't develop on it. I look forward to contributions from everyone!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants