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

process: read AT_CLKTCK from the auxv #53

Merged
merged 1 commit into from
Jun 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 49 additions & 8 deletions internal/host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,71 @@ package host

import (
"bufio"
"encoding/binary"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"unsafe"
)

/*
#include <unistd.h>
*/
import "C"

var (
// cache host queries to redundant calculations
clockTicks *int64
bootTime *int64
)

func getNativeEndianness() binary.ByteOrder {
var i int32 = 0x00000001
u := unsafe.Pointer(&i)
if *((*byte)(u)) == 0x01 {
return binary.LittleEndian
}
return binary.BigEndian
}

const (
atClktck = 17
)

func getFromAuxv(what uint, whatName string) (uint, error) {
dataLen := int(unsafe.Sizeof(int(0)))
p, err := ioutil.ReadFile("/proc/self/auxv")
if err != nil {
return 0, err
}
native := getNativeEndianness()
for i := 0; i < len(p); {
var k, v uint

switch dataLen {
case 4:
k = uint(native.Uint32(p[i : i+dataLen]))
v = uint(native.Uint32(p[i+dataLen : i+dataLen*2]))
case 8:
k = uint(native.Uint64(p[i : i+dataLen]))
v = uint(native.Uint64(p[i+dataLen : i+dataLen*2]))
}
i += dataLen * 2
if k == what {
return v, nil
}
}
return 0, fmt.Errorf("cannot find %s in auxv", whatName)
}

// ClockTicks returns sysconf(SC_CLK_TCK).
func ClockTicks() int64 {
func ClockTicks() (int64, error) {
if clockTicks == nil {
ticks := int64(C.sysconf(C._SC_CLK_TCK))
ret, err := getFromAuxv(atClktck, "AT_CLKTCK")
if err != nil {
return -1, err
}
ticks := int64(ret)
clockTicks = &ticks
}
return *clockTicks
return *clockTicks, nil
}

// BootTime parses /proc/uptime returns the boot time in seconds since the
Expand Down
3 changes: 2 additions & 1 deletion internal/host/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import (

func TestClockTicks(t *testing.T) {
// no thorough test but it makes sure things are working
ticks := ClockTicks()
ticks, err := ClockTicks()
assert.Nil(t, err)
assert.True(t, ticks > 0)
}

Expand Down
16 changes: 12 additions & 4 deletions internal/process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type Process struct {
Hgroup string
}

// LookupGID returns the textual group ID, if it can be optained, or the
// LookupGID returns the textual group ID, if it can be obtained, or the
// decimal representation otherwise.
func LookupGID(gid string) (string, error) {
gidNum, err := strconv.Atoi(gid)
Expand All @@ -59,7 +59,7 @@ func LookupGID(gid string) (string, error) {
return g.Name, nil
}

// LookupUID return the textual user ID, if it can be optained, or the decimal
// LookupUID return the textual user ID, if it can be obtained, or the decimal
// representation otherwise.
func LookupUID(uid string) (string, error) {
uidNum, err := strconv.Atoi(uid)
Expand Down Expand Up @@ -192,8 +192,12 @@ func (p *Process) ElapsedTime() (time.Duration, error) {
if err != nil {
return 0, err
}
clockTicks, err := host.ClockTicks()
if err != nil {
return 0, err
}

sinceBoot = sinceBoot / host.ClockTicks()
sinceBoot = sinceBoot / clockTicks

bootTime, err := host.BootTime()
if err != nil {
Expand All @@ -213,7 +217,11 @@ func (p *Process) CPUTime() (time.Duration, error) {
if err != nil {
return 0, err
}
secs := (user + system) / host.ClockTicks()
clockTicks, err := host.ClockTicks()
if err != nil {
return 0, err
}
secs := (user + system) / clockTicks
cpu := time.Unix(secs, 0)
return cpu.Sub(time.Unix(0, 0)), nil
}