// getDetails fills in CPU, memory, and command line details for the process func (proc *Process) getDetails(cmdline string) error { mem := sigar.ProcMem{} if err := mem.Get(proc.Pid); err != nil { return fmt.Errorf("error getting process mem for pid=%d: %v", proc.Pid, err) } proc.Mem = &ProcMemStat{ Size: mem.Size, Rss: mem.Resident, Share: mem.Share, } cpu := sigar.ProcTime{} if err := cpu.Get(proc.Pid); err != nil { return fmt.Errorf("error getting process cpu time for pid=%d: %v", proc.Pid, err) } proc.Cpu = &ProcCpuTime{ Start: cpu.FormatStartTime(), Total: cpu.Total, User: cpu.User, System: cpu.Sys, } if cmdline == "" { args := sigar.ProcArgs{} if err := args.Get(proc.Pid); err != nil { return fmt.Errorf("error getting process arguments for pid=%d: %v", proc.Pid, err) } proc.CmdLine = strings.Join(args.List, " ") } else { proc.CmdLine = cmdline } return nil }
func main() { pids := gosigar.ProcList{} pids.Get() // ps -eo pid,ppid,stime,time,rss,user,state,command fmt.Print(" PID PPID STIME TIME RSS USER S COMMAND\n") for _, pid := range pids.List { state := gosigar.ProcState{} mem := gosigar.ProcMem{} time := gosigar.ProcTime{} args := gosigar.ProcArgs{} if err := state.Get(pid); err != nil { continue } if err := mem.Get(pid); err != nil { continue } if err := time.Get(pid); err != nil { continue } if err := args.Get(pid); err != nil { continue } fmt.Printf("%5d %5d %s %s %6d %-15s %c %s\n", pid, state.Ppid, time.FormatStartTime(), time.FormatTotal(), mem.Resident/1024, state.Username, state.State, strings.Join(args.List, " ")) } }
func GetProcess(pid int) (*Process, error) { state := sigar.ProcState{} mem := sigar.ProcMem{} cpu := sigar.ProcTime{} args := sigar.ProcArgs{} err := state.Get(pid) if err != nil { return nil, fmt.Errorf("Error getting state info: %v", err) } err = mem.Get(pid) if err != nil { return nil, fmt.Errorf("Error getting mem info: %v", err) } err = cpu.Get(pid) if err != nil { return nil, fmt.Errorf("Error getting cpu info: %v", err) } err = args.Get(pid) if err != nil { return nil, fmt.Errorf("Error getting command line: %v", err) } cmdLine := strings.Join(args.List, " ") proc := Process{ Pid: pid, Ppid: state.Ppid, Name: state.Name, State: getProcState(byte(state.State)), Username: state.Username, CmdLine: cmdLine, Mem: mem, Cpu: cpu, } proc.ctime = time.Now() return &proc, nil }
func GetProcess(pid int, cmdline string) (*Process, error) { state := sigar.ProcState{} if err := state.Get(pid); err != nil { return nil, fmt.Errorf("error getting process state for pid=%d: %v", pid, err) } mem := sigar.ProcMem{} if err := mem.Get(pid); err != nil { return nil, fmt.Errorf("error getting process mem for pid=%d: %v", pid, err) } cpu := sigar.ProcTime{} if err := cpu.Get(pid); err != nil { return nil, fmt.Errorf("error getting process cpu time for pid=%d: %v", pid, err) } if cmdline == "" { args := sigar.ProcArgs{} if err := args.Get(pid); err != nil { return nil, fmt.Errorf("error getting process arguments for pid=%d: %v", pid, err) } cmdline = strings.Join(args.List, " ") } proc := Process{ Pid: pid, Ppid: state.Ppid, Name: state.Name, State: getProcState(byte(state.State)), Username: state.Username, CmdLine: cmdline, Mem: mem, Cpu: cpu, ctime: time.Now(), } return &proc, nil }
// SampleEnvironment queries the runtime system for various interesting metrics, // storing the resulting values in the set of metric gauges maintained by // RuntimeStatSampler. This makes runtime statistics more convenient for // consumption by the time series and status systems. // // This method should be called periodically by a higher level system in order // to keep runtime statistics current. func (rsr *RuntimeStatSampler) SampleEnvironment() { // Record memory and call stats from the runtime package. // TODO(mrtracy): memory statistics will not include usage from RocksDB. // Determine an appropriate way to compute total memory usage. numCgoCall := runtime.NumCgoCall() numGoroutine := runtime.NumGoroutine() // It might be useful to call ReadMemStats() more often, but it stops the // world while collecting stats so shouldn't be called too often. ms := runtime.MemStats{} runtime.ReadMemStats(&ms) // Retrieve Mem and CPU statistics. pid := os.Getpid() mem := gosigar.ProcMem{} if err := mem.Get(pid); err != nil { log.Errorf("unable to get mem usage: %v", err) } cpu := gosigar.ProcTime{} if err := cpu.Get(pid); err != nil { log.Errorf("unable to get cpu usage: %v", err) } // Time statistics can be compared to the total elapsed time to create a // useful percentage of total CPU usage, which would be somewhat less accurate // if calculated later using downsampled time series data. now := rsr.clock.PhysicalNow() dur := float64(now - rsr.lastNow) // cpu.{User,Sys} are in milliseconds, convert to nanoseconds. newUtime := int64(cpu.User) * 1e6 newStime := int64(cpu.Sys) * 1e6 uPerc := float64(newUtime-rsr.lastUtime) / dur sPerc := float64(newStime-rsr.lastStime) / dur pausePerc := float64(ms.PauseTotalNs-rsr.lastPauseTime) / dur rsr.lastNow = now rsr.lastUtime = newUtime rsr.lastStime = newStime rsr.lastPauseTime = ms.PauseTotalNs // Log summary of statistics to console. cgoRate := float64((numCgoCall-rsr.lastCgoCall)*int64(time.Second)) / dur log.Infof("runtime stats: %s RSS, %d goroutines, %s active, %.2fcgo/sec, %.2f/%.2f %%(u/s)time, %.2f %%gc (%dx)", humanize.IBytes(mem.Resident), numGoroutine, humanize.IBytes(ms.Alloc), cgoRate, uPerc, sPerc, pausePerc, ms.NumGC-rsr.lastNumGC) if log.V(2) { log.Infof("memstats: %+v", ms) } if logOSStats != nil { logOSStats() } rsr.lastCgoCall = numCgoCall rsr.lastNumGC = ms.NumGC rsr.cgoCalls.Update(numCgoCall) rsr.goroutines.Update(int64(numGoroutine)) rsr.allocBytes.Update(int64(ms.Alloc)) rsr.sysBytes.Update(int64(ms.Sys)) rsr.gcCount.Update(int64(ms.NumGC)) rsr.gcPauseNS.Update(int64(ms.PauseTotalNs)) rsr.gcPausePercent.Update(pausePerc) rsr.cpuUserNS.Update(newUtime) rsr.cpuUserPercent.Update(uPerc) rsr.cpuSysNS.Update(newStime) rsr.cpuSysPercent.Update(sPerc) rsr.rss.Update(int64(mem.Resident)) }
// SampleEnvironment queries the runtime system for various interesting metrics, // storing the resulting values in the set of metric gauges maintained by // RuntimeStatSampler. This makes runtime statistics more convenient for // consumption by the time series and status systems. // // This method should be called periodically by a higher level system in order // to keep runtime statistics current. func (rsr *RuntimeStatSampler) SampleEnvironment() { // Record memory and call stats from the runtime package. // TODO(mrtracy): memory statistics will not include usage from RocksDB. // Determine an appropriate way to compute total memory usage. numCgoCall := runtime.NumCgoCall() numGoroutine := runtime.NumGoroutine() // It might be useful to call ReadMemStats() more often, but it stops the // world while collecting stats so shouldn't be called too often. // NOTE: the MemStats fields do not get decremented when memory is released, // to get accurate numbers, be sure to subtract. eg: ms.Sys - ms.HeapReleased for // current memory reserved. ms := runtime.MemStats{} runtime.ReadMemStats(&ms) // Retrieve Mem and CPU statistics. pid := os.Getpid() mem := gosigar.ProcMem{} if err := mem.Get(pid); err != nil { log.Errorf(context.TODO(), "unable to get mem usage: %v", err) } cpu := gosigar.ProcTime{} if err := cpu.Get(pid); err != nil { log.Errorf(context.TODO(), "unable to get cpu usage: %v", err) } // Time statistics can be compared to the total elapsed time to create a // useful percentage of total CPU usage, which would be somewhat less accurate // if calculated later using downsampled time series data. now := rsr.clock.PhysicalNow() dur := float64(now - rsr.lastNow) // cpu.{User,Sys} are in milliseconds, convert to nanoseconds. newUtime := int64(cpu.User) * 1e6 newStime := int64(cpu.Sys) * 1e6 uPerc := float64(newUtime-rsr.lastUtime) / dur sPerc := float64(newStime-rsr.lastStime) / dur pausePerc := float64(ms.PauseTotalNs-rsr.lastPauseTime) / dur rsr.lastNow = now rsr.lastUtime = newUtime rsr.lastStime = newStime rsr.lastPauseTime = ms.PauseTotalNs var cgoAllocated, cgoTotal uint64 if getCgoMemStats != nil { var err error cgoAllocated, cgoTotal, err = getCgoMemStats() if err != nil { log.Warningf(context.TODO(), "problem fetching CGO memory stats: %s, CGO stats will be empty.", err) } } goAllocated := ms.Alloc goTotal := ms.Sys - ms.HeapReleased // Log summary of statistics to console. cgoRate := float64((numCgoCall-rsr.lastCgoCall)*int64(time.Second)) / dur log.Infof(context.TODO(), "runtime stats: %s RSS, %d goroutines, %s/%s/%s GO alloc/idle/total, %s/%s CGO alloc/total, %.2fcgo/sec, %.2f/%.2f %%(u/s)time, %.2f %%gc (%dx)", humanize.IBytes(mem.Resident), numGoroutine, humanize.IBytes(goAllocated), humanize.IBytes(ms.HeapIdle-ms.HeapReleased), humanize.IBytes(goTotal), humanize.IBytes(cgoAllocated), humanize.IBytes(cgoTotal), cgoRate, uPerc, sPerc, pausePerc, ms.NumGC-rsr.lastNumGC) if log.V(2) { log.Infof(context.TODO(), "memstats: %+v", ms) } rsr.lastCgoCall = numCgoCall rsr.lastNumGC = ms.NumGC rsr.cgoCalls.Update(numCgoCall) rsr.goroutines.Update(int64(numGoroutine)) rsr.goAllocBytes.Update(int64(goAllocated)) rsr.goTotalBytes.Update(int64(goTotal)) rsr.cgoAllocBytes.Update(int64(cgoAllocated)) rsr.cgoTotalBytes.Update(int64(cgoTotal)) rsr.gcCount.Update(int64(ms.NumGC)) rsr.gcPauseNS.Update(int64(ms.PauseTotalNs)) rsr.gcPausePercent.Update(pausePerc) rsr.cpuUserNS.Update(newUtime) rsr.cpuUserPercent.Update(uPerc) rsr.cpuSysNS.Update(newStime) rsr.cpuSysPercent.Update(sPerc) rsr.rss.Update(int64(mem.Resident)) }