master
go 62 lines 1.46 KB
Raw
1 //go:build !windows
2
3 // SPDX-License-Identifier: GPL-3.0-or-later
4
5 package ndexec
6
7 import (
8 "os"
9 "runtime"
10 "syscall"
11 "time"
12 )
13
14 // ResourceUsage captures OS-reported resource counters for a completed process.
15 type ResourceUsage struct {
16 User time.Duration
17 System time.Duration
18 MaxRSSBytes int64
19 ReadBytes int64
20 WriteBytes int64
21 }
22
23 func (u ResourceUsage) totalCPU() time.Duration {
24 return u.User + u.System
25 }
26
27 func extractUsage(ps *os.ProcessState) ResourceUsage {
28 if ps == nil {
29 return ResourceUsage{}
30 }
31 usage := ResourceUsage{}
32 if sys := ps.SysUsage(); sys != nil {
33 if ru, ok := sys.(*syscall.Rusage); ok && ru != nil {
34 usage.User = time.Duration(ru.Utime.Sec)*time.Second + time.Duration(ru.Utime.Usec)*time.Microsecond
35 usage.System = time.Duration(ru.Stime.Sec)*time.Second + time.Duration(ru.Stime.Usec)*time.Microsecond
36 usage.MaxRSSBytes = convertMaxRSS(int64(ru.Maxrss))
37 usage.ReadBytes = blocksToBytes(int64(ru.Inblock))
38 usage.WriteBytes = blocksToBytes(int64(ru.Oublock))
39 }
40 }
41 return usage
42 }
43
44 // convertMaxRSS normalizes platform-specific MaxRSS units: Linux and BSD
45 // derivatives report KiB while Darwin already uses bytes.
46 func convertMaxRSS(raw int64) int64 {
47 bytes := raw
48 switch runtime.GOOS {
49 case "linux", "android", "freebsd", "openbsd", "netbsd", "dragonfly":
50 bytes *= 1024
51 }
52 return bytes
53 }
54
55 const blockSize = 512
56
57 func blocksToBytes(blocks int64) int64 {
58 if blocks <= 0 {
59 return 0
60 }
61 return blocks * blockSize
62 }