Implement native sigar_proc_cpu_get function

This commit is contained in:
Doug MacEachern 2007-03-11 21:46:41 +00:00
parent 171f2e021e
commit 93ef97aaa8
10 changed files with 139 additions and 106 deletions

View File

@ -1,3 +1,7 @@
2007-03-11 Doug MacEachern <dougm@hyperic.com>
* Implement native sigar_proc_cpu_get function
2007-03-07 Doug MacEachern <dougm@hyperic.com> 2007-03-07 Doug MacEachern <dougm@hyperic.com>
* Plug various handle+mem leaks on win32 * Plug various handle+mem leaks on win32

View File

@ -319,6 +319,18 @@ my %classes = (
plat => '*' plat => '*'
}, },
], ],
ProcCpu => [
{
name => 'percent', type => 'Double',
desc => 'Process cpu usage',
plat => '*'
},
{
name => 'last_time', type => 'Long',
desc => '',
plat => '*'
},
],
ProcState => [ ProcState => [
{ {
name => 'state', type => 'Char', name => 'state', type => 'Char',
@ -976,6 +988,14 @@ my %classes = (
$classes{DirUsage} = $classes{DirStat}; $classes{DirUsage} = $classes{DirStat};
my(%extends) = (
ProcCpu => 'ProcTime',
);
while (my($subclass, $superclass) = each %extends) {
push @{ $classes{$subclass} }, @{ $classes{$superclass} };
}
my %cmds = ( my %cmds = (
Mem => { Mem => {
AIX => 'top', AIX => 'top',

View File

@ -28,6 +28,7 @@ import org.hyperic.sigar.ptql.ProcessFinder;
*/ */
public class MultiProcCpu extends ProcCpu { public class MultiProcCpu extends ProcCpu {
private long pid;
private int nproc = 0; private int nproc = 0;
private static Map ptable = new HashMap(); private static Map ptable = new HashMap();
@ -99,4 +100,19 @@ public class MultiProcCpu extends ProcCpu {
public int getProcesses() { public int getProcesses() {
return this.nproc; return this.nproc;
} }
/**
* @return Pid of the process.
*/
public int hashCode() {
return (int)this.pid;
}
public boolean equals(Object cpu) {
if (!(cpu instanceof MultiProcCpu)) {
return false;
}
return ((MultiProcCpu)cpu).pid == this.pid;
}
} }

View File

@ -1,101 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar;
import java.util.HashMap;
import java.util.Map;
/**
* Extend ProcTime to provide process cpu percentage metric.
*/
public class ProcCpu extends ProcTime {
private static ProcCpu key = new ProcCpu();
private static Map ptable = new HashMap();
protected long lastTime = 0;
protected double percent = 0.0;
protected long pid;
private void getValues(Sigar sigar, long pid)
throws SigarException {
this.gather(sigar, pid);
}
static synchronized ProcCpu get(Sigar sigar, long pid)
throws SigarException {
ProcCpu cpu;
key.pid = pid;
cpu = (ProcCpu)ptable.get(key);
if (cpu == null) {
cpu = new ProcCpu();
cpu.pid = pid;
ptable.put(cpu, cpu);
}
long timeNow = System.currentTimeMillis();
double diff = timeNow - cpu.lastTime;
if (diff == 0) {
return cpu; //we were just called within < 1 second ago.
}
cpu.lastTime = timeNow;
long otime = cpu.total;
cpu.getValues(sigar, pid);
if (otime == 0) {
//XXX could/should pause first time called.
return cpu;
}
cpu.percent = ((cpu.total - otime) / diff);
if (cpu.percent >= 1.0) {
cpu.percent = 0.99;
}
return cpu;
}
/**
* @return Process CPU usage percentage.
*/
public double getPercent() {
return this.percent;
}
/**
* @return Pid of the process.
*/
public int hashCode() {
return (int)this.pid;
}
public boolean equals(Object cpu) {
if (!(cpu instanceof ProcCpu)) {
return false;
}
return ((ProcCpu)cpu).pid == this.pid;
}
}

View File

@ -472,7 +472,7 @@ public class Sigar implements SigarProxy {
* @exception SigarException on failure. * @exception SigarException on failure.
*/ */
public ProcCpu getProcCpu(long pid) throws SigarException { public ProcCpu getProcCpu(long pid) throws SigarException {
return ProcCpu.get(this, pid); return ProcCpu.fetch(this, pid);
} }
public ProcCpu getProcCpu(String pid) throws SigarException { public ProcCpu getProcCpu(String pid) throws SigarException {

View File

@ -58,7 +58,7 @@ public class MultiPs extends SigarCommandBase {
MultiProcCpu cpu = this.proxy.getMultiProcCpu(query); MultiProcCpu cpu = this.proxy.getMultiProcCpu(query);
println("Number of processes: " + cpu.getProcesses()); println("Number of processes: " + cpu.getProcesses());
println("Cpu usage: " + CpuPerc.format(cpu.getPercent())); println("Cpu usage: " + CpuPerc.format(cpu.getPercent()));
println("Cpu time: " + Ps.getCpuTime(cpu)); println("Cpu time: " + Ps.getCpuTime(cpu.getTotal()));
ProcMem mem = this.proxy.getMultiProcMem(query); ProcMem mem = this.proxy.getMultiProcMem(query);
println("Size: " + Sigar.formatSize(mem.getSize())); println("Size: " + Sigar.formatSize(mem.getSize()));

View File

@ -148,11 +148,15 @@ public class Ps extends SigarCommandBase {
println(join(getInfo(this.proxy, pid))); println(join(getInfo(this.proxy, pid)));
} }
public static String getCpuTime(ProcTime time) { public static String getCpuTime(long total) {
long t = time.getTotal() / 1000; long t = total / 1000;
return t/60 + ":" + t%60; return t/60 + ":" + t%60;
} }
public static String getCpuTime(ProcTime time) {
return getCpuTime(time.getTotal());
}
private static String getStartTime(long time) { private static String getStartTime(long time) {
if (time == 0) { if (time == 0) {
return "00:00"; return "00:00";

View File

@ -33,18 +33,30 @@ typedef unsigned __int32 sigar_uint32_t;
typedef unsigned __int64 sigar_uint64_t; typedef unsigned __int64 sigar_uint64_t;
typedef __int32 sigar_int32_t;
typedef __int64 sigar_int64_t;
#elif ULONG_MAX > 4294967295UL #elif ULONG_MAX > 4294967295UL
typedef unsigned int sigar_uint32_t; typedef unsigned int sigar_uint32_t;
typedef unsigned long sigar_uint64_t; typedef unsigned long sigar_uint64_t;
typedef int sigar_int32_t;
typedef long sigar_int64_t;
#else #else
typedef unsigned int sigar_uint32_t; typedef unsigned int sigar_uint32_t;
typedef unsigned long long sigar_uint64_t; typedef unsigned long long sigar_uint64_t;
typedef int sigar_int32_t;
typedef long long sigar_int64_t;
#endif #endif
#define SIGAR_FIELD_NOTIMPL -1 #define SIGAR_FIELD_NOTIMPL -1
@ -272,6 +284,20 @@ typedef struct {
SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_time_t *proctime); sigar_proc_time_t *proctime);
typedef struct {
/* must match sigar_proc_time_t fields */
sigar_uint64_t
start_time,
user,
sys,
total;
sigar_uint64_t last_time;
double percent;
} sigar_proc_cpu_t;
SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cpu_t *proccpu);
#define SIGAR_PROC_NAME_LEN 128 #define SIGAR_PROC_NAME_LEN 128
typedef struct { typedef struct {

View File

@ -65,7 +65,8 @@
char errbuf[256]; \ char errbuf[256]; \
char *ifconf_buf; \ char *ifconf_buf; \
int ifconf_len; \ int ifconf_len; \
char *self_path char *self_path; \
sigar_cache_t *proc_cpu
#if defined(WIN32) #if defined(WIN32)
# define SIGAR_INLINE __inline # define SIGAR_INLINE __inline

View File

@ -34,7 +34,10 @@ SIGAR_DECLARE(int) sigar_open(sigar_t **sigar)
(*sigar)->log_level = -1; /* log nothing by default */ (*sigar)->log_level = -1; /* log nothing by default */
(*sigar)->log_impl = NULL; (*sigar)->log_impl = NULL;
(*sigar)->log_data = NULL; (*sigar)->log_data = NULL;
(*sigar)->ptql_re_impl = NULL;
(*sigar)->ptql_re_data = NULL;
(*sigar)->self_path = NULL; (*sigar)->self_path = NULL;
(*sigar)->proc_cpu = NULL;
} }
return status; return status;
@ -48,6 +51,10 @@ SIGAR_DECLARE(int) sigar_close(sigar_t *sigar)
if (sigar->self_path) { if (sigar->self_path) {
free(sigar->self_path); free(sigar->self_path);
} }
if (sigar->proc_cpu) {
sigar_cache_destroy(sigar->proc_cpu);
}
return sigar_os_close(sigar); return sigar_os_close(sigar);
} }
@ -62,6 +69,62 @@ SIGAR_DECLARE(sigar_pid_t) sigar_pid_get(sigar_t *sigar)
} }
#endif #endif
/* XXX: add clear() function */
/* XXX: check for stale-ness using start_time */
SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cpu_t *proccpu)
{
sigar_cache_entry_t *entry;
sigar_proc_cpu_t *prev;
sigar_uint64_t otime, time_now = time(NULL) * 1000;
sigar_int64_t time_diff, total_diff;
int status;
if (!sigar->proc_cpu) {
sigar->proc_cpu = sigar_cache_new(128);
}
entry = sigar_cache_get(sigar->proc_cpu, pid);
if (entry->value) {
prev = (sigar_proc_cpu_t *)entry->value;
}
else {
prev = entry->value = malloc(sizeof(*prev));
SIGAR_ZERO(prev);
}
time_diff = time_now - prev->last_time;
proccpu->last_time = prev->last_time = time_now;
if (time_diff == 0) {
/* we were just called within < 1 second ago. */
memcpy(proccpu, prev, sizeof(*proccpu));
return SIGAR_OK;
}
otime = prev->total;
status =
sigar_proc_time_get(sigar, pid,
(sigar_proc_time_t *)proccpu);
if (status != SIGAR_OK) {
return status;
}
memcpy(prev, proccpu, sizeof(*prev));
if (otime == 0) {
/* first time called */
return SIGAR_OK;
}
total_diff = proccpu->total - otime;
proccpu->percent = total_diff / (double)time_diff;
return SIGAR_OK;
}
static char *sigar_error_string(int err) static char *sigar_error_string(int err)
{ {
switch (err) { switch (err) {