Skip to content

Commit 9de501b

Browse files
committed
process: read AT_CLKTCK from the auxv
read AT_CLKTCK directly from the auxv vector, so it is possible to use psgo without requiring cgo. This is what internally sysconf does, although it doesn't use /proc/self/auxv but read directly from memory. Signed-off-by: Giuseppe Scrivano <[email protected]>
1 parent 2e6ba54 commit 9de501b

File tree

3 files changed

+63
-13
lines changed

3 files changed

+63
-13
lines changed

internal/host/host.go

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,71 @@ package host
1818

1919
import (
2020
"bufio"
21+
"encoding/binary"
2122
"fmt"
23+
"io/ioutil"
2224
"os"
2325
"strconv"
2426
"strings"
27+
"unsafe"
2528
)
2629

27-
/*
28-
#include <unistd.h>
29-
*/
30-
import "C"
31-
3230
var (
3331
// cache host queries to redundant calculations
3432
clockTicks *int64
3533
bootTime *int64
3634
)
3735

36+
func getNativeEndianness() binary.ByteOrder {
37+
var i int32 = 0x00000001
38+
u := unsafe.Pointer(&i)
39+
if *((*byte)(u)) == 0x01 {
40+
return binary.LittleEndian
41+
}
42+
return binary.BigEndian
43+
}
44+
45+
const (
46+
atClktck = 17
47+
)
48+
49+
func getFromAuxv(what uint, whatName string) (uint, error) {
50+
dataLen := int(unsafe.Sizeof(int(0)))
51+
p, err := ioutil.ReadFile("/proc/self/auxv")
52+
if err != nil {
53+
return 0, err
54+
}
55+
native := getNativeEndianness()
56+
for i := 0; i < len(p); {
57+
var k, v uint
58+
59+
switch dataLen {
60+
case 4:
61+
k = uint(native.Uint32(p[i : i+dataLen]))
62+
v = uint(native.Uint32(p[i+dataLen : i+dataLen*2]))
63+
case 8:
64+
k = uint(native.Uint64(p[i : i+dataLen]))
65+
v = uint(native.Uint64(p[i+dataLen : i+dataLen*2]))
66+
}
67+
i += dataLen * 2
68+
if k == what {
69+
return v, nil
70+
}
71+
}
72+
return 0, fmt.Errorf("cannot find %s in auxv", whatName)
73+
}
74+
3875
// ClockTicks returns sysconf(SC_CLK_TCK).
39-
func ClockTicks() int64 {
76+
func ClockTicks() (int64, error) {
4077
if clockTicks == nil {
41-
ticks := int64(C.sysconf(C._SC_CLK_TCK))
78+
ret, err := getFromAuxv(atClktck, "AT_CLKTCK")
79+
if err != nil {
80+
return -1, err
81+
}
82+
ticks := int64(ret)
4283
clockTicks = &ticks
4384
}
44-
return *clockTicks
85+
return *clockTicks, nil
4586
}
4687

4788
// BootTime parses /proc/uptime returns the boot time in seconds since the

internal/host/host_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import (
2222

2323
func TestClockTicks(t *testing.T) {
2424
// no thorough test but it makes sure things are working
25-
ticks := ClockTicks()
25+
ticks, err := ClockTicks()
26+
assert.Nil(t, err)
2627
assert.True(t, ticks > 0)
2728
}
2829

internal/process/process.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type Process struct {
4545
Hgroup string
4646
}
4747

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

62-
// LookupUID return the textual user ID, if it can be optained, or the decimal
62+
// LookupUID return the textual user ID, if it can be obtained, or the decimal
6363
// representation otherwise.
6464
func LookupUID(uid string) (string, error) {
6565
uidNum, err := strconv.Atoi(uid)
@@ -192,8 +192,12 @@ func (p *Process) ElapsedTime() (time.Duration, error) {
192192
if err != nil {
193193
return 0, err
194194
}
195+
clockTicks, err := host.ClockTicks()
196+
if err != nil {
197+
return 0, err
198+
}
195199

196-
sinceBoot = sinceBoot / host.ClockTicks()
200+
sinceBoot = sinceBoot / clockTicks
197201

198202
bootTime, err := host.BootTime()
199203
if err != nil {
@@ -213,7 +217,11 @@ func (p *Process) CPUTime() (time.Duration, error) {
213217
if err != nil {
214218
return 0, err
215219
}
216-
secs := (user + system) / host.ClockTicks()
220+
clockTicks, err := host.ClockTicks()
221+
if err != nil {
222+
return 0, err
223+
}
224+
secs := (user + system) / clockTicks
217225
cpu := time.Unix(secs, 0)
218226
return cpu.Sub(time.Unix(0, 0)), nil
219227
}

0 commit comments

Comments
 (0)