Last active
September 1, 2024 12:35
-
-
Save gekigek99/46f4683e3f9ed5411736dcded485c1f4 to your computer and use it in GitHub Desktop.
calculate the average cpu usage percent of the last second of a given pid
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This script calculates the average cpu usage percent of the last second (of a given pid, in this case the script itself). | |
// (*process.Process).CPUPercent() from "github.com/shirou/gopsutil/process" returns the average cpu usage percent since the process was started. | |
// If you call cpuPercent(p) every 10 seconds then the average cpu usage percent of the last 10 seconds is returned. | |
// | |
// cpuPercent first call returns the average cpu percent usage since the start of the process. | |
// | |
// Remember that if the process you are analyzing changes pid you have to update `pTracker` with the new pid (+new info) and remove the old pid. | |
// (not the case for this example though) | |
package main | |
import ( | |
"fmt" | |
"os" | |
"time" | |
"github.com/shirou/gopsutil/process" | |
) | |
// pStats keeps track of a single process stats | |
type pStats struct { | |
cpuTotalLast float64 | |
lifeTimeLast time.Duration | |
} | |
// pStatsByPid keeps track of multiple processes stats | |
// | |
// (pid is used as map key to access each single process stats) | |
type pStatsByPid map[int32]*pStats | |
// pTracker is the variable that stores all process stats in a pid map | |
var pTracker pStatsByPid = pStatsByPid{} | |
func main() { | |
// get current process | |
p, err := process.NewProcess(int32(os.Getpid())) | |
if err != nil { | |
fmt.Println(err.Error()) | |
os.Exit(1) | |
} | |
n := 0 | |
go func() { | |
timer := time.NewTimer(3000 * time.Millisecond) | |
for { | |
n++ | |
if n > 1000000 { | |
n = 0 | |
} | |
select { | |
case <-timer.C: | |
time.Sleep(3000 * time.Millisecond) | |
timer.Reset(3000 * time.Millisecond) | |
default: | |
} | |
} | |
}() | |
t := time.NewTicker(time.Second) | |
for { | |
<-tick.C | |
percent1, err := cpuPercent(p) | |
if err != nil { | |
fmt.Println(err.Error()) | |
continue | |
} | |
percent2, err := p.CPUPercent() | |
if err != nil { | |
fmt.Println(err.Error()) | |
continue | |
} | |
fmt.Printf("cpu usage (%d): script = %f\t-\tgopsutil = %f\n", p.Pid, percent1, percent2) | |
} | |
} | |
// cpuPercent returns the average cpu percent usage since last call | |
// | |
// cpuPercent first call returns the average cpu percent usage since the start of the process. | |
func cpuPercent(p *process.Process) (float64, error) { | |
crt_time, err := p.CreateTime() | |
if err != nil { | |
return -1, err | |
} | |
lifeTimeNow := time.Since(time.Unix(0, crt_time*int64(time.Millisecond))) | |
cput, err := p.Times() | |
if err != nil { | |
return -1, err | |
} | |
cpuTotalNow := cput.Total() | |
// update tracked pid | |
cpuTotalLast, lifeTimeLast := pTracker.upd(p.Pid, cpuTotalNow, lifeTimeNow) | |
cpuPercent := 100 * (cpuTotalNow - cpuTotalLast) / (lifeTimeNow - lifeTimeLast).Seconds() | |
return cpuPercent, nil | |
} | |
// upd specified pid and returns last cpu total and last life time. | |
// | |
// pTracker.upd(p.Pid, ..., ...) should be called before accessing pTracker[p.Pid] (if not it will be nil). | |
func (pTracker *pStatsByPid) upd(pid int32, cpuTotalNow float64, lifeTimeNow time.Duration) (float64, time.Duration) { | |
// if pid is not tracked, return 0, 0 | |
cpuTotalLast := 0.0 | |
lifeTimeLast := time.Duration(0) | |
// if pid is tracked, return last values | |
_, ok := (*pTracker)[pid] | |
if ok { | |
cpuTotalLast = (*pTracker)[pid].cpuTotalLast | |
lifeTimeLast = (*pTracker)[pid].lifeTimeLast | |
} | |
// update process stats in tracker | |
(*pTracker)[pid] = &pStats{ | |
cpuTotalLast: cpuTotalNow, | |
lifeTimeLast: lifeTimeNow, | |
} | |
return cpuTotalLast, lifeTimeLast | |
} | |
// rem removes pid from pTracker. | |
// | |
// it's safe to use even if pTracker does not contain pid. | |
func (pTracker *pStatsByPid) rem(pid int32) { | |
delete(*pTracker, pid) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment