Compare commits

...

5 Commits

Author SHA1 Message Date
unknown 494ed4ed3e Some metrics are missing the '/sec' suffix. This fix first tries to add
the counter without the '/sec' and if fails, try again with it. If the
second call fails, throw an exception.This issue must be addressed at the
java level (and not C code), since the counter names must be translated
before to support i18n native OS locals.
Please also note, the C code (at Pdh.c), tries to do the same, but at
this level we cannot use the translation mechanism the Java level offers,
hence this fix won't handle non-English i18n locals.
2014-09-03 14:26:02 +03:00
root f12b8e32d3 process args and query (ptql) string - support dbcs for windows 2013-11-04 12:07:38 +00:00
root 9c931654d7 (German) support for getting a set of formatted metrics 2013-10-22 07:33:06 +00:00
root 797d8a9edf adding disk io per process and bug fixes 2013-10-09 07:59:48 +00:00
Netta Gavrieli 449de48cea Java - Fixed loading native libraries from paths that contain international characters.
This fixes Hyperic bug https://jira.hyperic.com/browse/HQ-4227
2013-10-06 10:13:21 +00:00
28 changed files with 932 additions and 116 deletions

View File

@ -94,6 +94,7 @@ my %has_name_arg = map { $_, 1 } qw(FileSystemUsage DiskUsage
FileAttrs DirStat DirUsage
NetInterfaceConfig NetInterfaceStat);
my %proc_no_arg = map { $_, 1 } qw(stat);
my %get_not_impl = map { $_, 1 } qw(net_address net_route net_connection net_stat cpu_perc
@ -568,6 +569,7 @@ use vars qw(%classes %cmds);
plat => '*'
},
],
ProcMem => [
{
name => 'size', type => 'Long',
@ -668,6 +670,59 @@ use vars qw(%classes %cmds);
plat => '*'
},
],
ProcDiskIO => [
{
name => 'bytes_read', type => 'Long',
desc => 'Bytes Read',
plat => 'LW'
},
{
name => 'bytes_written', type => 'Long',
desc => 'Bytes Written',
plat => 'LW'
},
{
name => 'bytes_total', type => 'Long',
desc => 'Bytes Total',
plat => 'LWAHS'
}
],
ProcCumulativeDiskIO => [
{
name => 'bytes_read', type => 'Long',
desc => 'Bytes Read from Start',
plat => 'LW'
},
{
name => 'bytes_written', type => 'Long',
desc => 'Bytes Written from Start',
plat => 'LW'
},
{
name => 'bytes_total', type => 'Long',
desc => 'Bytes Total from Start',
plat => 'LWAHS'
}
],
DumpPidCache => [
{
name => 'dummy', type => 'Long',
desc => 'Dummy',
plat => 'LWAHS'
}
],
DumpPidCache => [
{
name => 'dummy', type => 'Long',
desc => 'Dummy',
plat => 'LWAHS'
}
],
ProcState => [
{
name => 'state', type => 'Char',

View File

@ -17,6 +17,7 @@
package org.hyperic.jni;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.StringTokenizer;
import java.net.URL;
import java.net.URLClassLoader;
@ -315,7 +316,16 @@ public class ArchLoader {
if ((file != null) &&
((file = file.getParentFile()) != null))
{
String dir = URLDecoder.decode(file.toString());
String dir;
try {
// Passing UTF-8 according to the recommendation in the URLDecoder.decode JavaDoc.
dir = URLDecoder.decode(file.toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
String msg = "Unsupported encoding in file name: " + file.toString();
ArchLoaderException archLoaderException = new ArchLoaderException(msg);
archLoaderException.initCause(e);
throw archLoaderException;
}
if (findNativeLibrary(dir, libName)) {
return dir;
}

View File

@ -665,6 +665,17 @@ JNIEXPORT jlongArray SIGAR_JNIx(getProcList)
return procarray;
}
jstring getProcArgStr(char *arg, JNIEnv *env) {
jstring s;
#ifdef WIN32
WCHAR warg[3000];
SIGAR_A2W(arg, warg, sizeof(warg));
s = JENV->NewString(env, (const jchar *)warg, wcslen(warg));
#else
s = JENV->NewStringUTF(env, arg);
#endif
return s;
}
JNIEXPORT jobjectArray SIGAR_JNIx(getProcArgs)
(JNIEnv *env, jobject sigar_obj, jlong pid)
@ -685,7 +696,8 @@ JNIEXPORT jobjectArray SIGAR_JNIx(getProcArgs)
SIGAR_CHEX;
for (i=0; i<procargs.number; i++) {
jstring s = JENV->NewStringUTF(env, procargs.data[i]);
jstring s = getProcArgStr(procargs.data[i], env);
JENV->SetObjectArrayElement(env, argsarray, i, s);
SIGAR_CHEX;
}
@ -1298,16 +1310,26 @@ JNIEXPORT void SIGAR_JNI(ptql_SigarProcessQuery_create)
{
int status;
jboolean is_copy;
const char *ptql;
sigar_ptql_query_t *query;
sigar_ptql_error_t error;
#ifdef WIN32
LPCTSTR ptql;
char ptql_ch[3000];
ptql = (LPCTSTR)JENV->GetStringChars(env, jptql, &is_copy);
SIGAR_W2A((LPCWSTR)ptql, ptql_ch, sizeof(ptql_ch));
status = sigar_ptql_query_create(&query, ptql_ch, &error);
if (is_copy) {
JENV->ReleaseStringChars(env, jptql, (const jchar *)ptql);
}
#else
const char *ptql;
ptql = JENV->GetStringUTFChars(env, jptql, &is_copy);
status = sigar_ptql_query_create(&query, (char *)ptql, &error);
if (is_copy) {
JENV->ReleaseStringUTFChars(env, jptql, ptql);
}
#endif
if (status != SIGAR_OK) {
sigar_throw_ptql_malformed(env, error.message);
}

View File

@ -172,6 +172,34 @@ JNIEXPORT void SIGAR_JNI(win32_Pdh_pdhRemoveCounter)
}
}
JNIEXPORT void SIGAR_JNI(win32_Pdh_pdhCollectQueryDataOverSecond)
(JNIEnv *env, jclass cur, jlong query)
{
HQUERY h_query = (HQUERY)query;
PdhCollectQueryData(h_query);
Sleep(1000);
PdhCollectQueryData(h_query);
}
JNIEXPORT jdouble SIGAR_JNI(win32_Pdh_pdhGetFormattedValue)
(JNIEnv *env, jclass cur, jlong counter)
{
HCOUNTER h_counter = (HCOUNTER)counter;
PDH_STATUS status;
PDH_FMT_COUNTERVALUE fmt_value;
status = PdhGetFormattedCounterValue(h_counter,
PDH_FMT_DOUBLE,
(LPDWORD)NULL,
&fmt_value);
if (status != ERROR_SUCCESS) {
win32_throw_exception(env, get_error_message(status));
return 0;
}
return fmt_value.doubleValue;
}
JNIEXPORT jdouble SIGAR_JNI(win32_Pdh_pdhGetValue)
(JNIEnv *env, jclass cur, jlong query, jlong counter, jboolean fmt)
{
@ -353,6 +381,7 @@ JNIEXPORT jobjectArray SIGAR_JNI(win32_Pdh_pdhGetInstances)
return array;
}
JNIEXPORT jobjectArray SIGAR_JNI(win32_Pdh_pdhGetKeys)
(JNIEnv *env, jclass cur, jstring cp)
{

View File

@ -295,71 +295,55 @@ public class FileInfo extends FileAttrs implements java.io.Serializable {
ArrayList changes = new ArrayList();
if (this.getMtime() != info.getMtime()) {
changes.add(new Diff("Mtime",
formatDate(info.getMtime()),
changes.add(new Diff("Mtime", formatDate(info.getMtime()),
formatDate(this.getMtime())));
}
else if (this.getCtime() != info.getCtime()) {
changes.add(new Diff("Ctime",
formatDate(info.getCtime()),
} else if (this.getCtime() != info.getCtime()) {
changes.add(new Diff("Ctime", formatDate(info.getCtime()),
formatDate(this.getCtime())));
}
else {
//no point in checking the rest if all times are the same.
//or should we include atime in the diff?
return "";
}
if (this.getPermissions() != info.getPermissions()) {
changes.add(new Diff("Perms",
info.getPermissionsString(),
this.getPermissionsString()));
changes.add(new Diff("Perms", info.getPermissionsString(), this
.getPermissionsString()));
}
if (this.getType() != info.getType()) {
changes.add(new Diff("Type",
info.getTypeString(),
this.getTypeString()));
changes.add(new Diff("Type", info.getTypeString(), this
.getTypeString()));
}
if (this.getUid() != info.getUid()) {
changes.add(new Diff("Uid",
info.getUid(),
this.getUid()));
changes.add(new Diff("Uid", info.getUid(), this.getUid()));
}
if (this.getGid() != info.getGid()) {
changes.add(new Diff("Gid",
info.getGid(),
this.getGid()));
changes.add(new Diff("Gid", info.getGid(), this.getGid()));
}
if (this.getSize() != info.getSize()) {
changes.add(new Diff("Size",
info.getSize(),
this.getSize()));
changes.add(new Diff("Size", info.getSize(), this.getSize()));
}
if (!OperatingSystem.IS_WIN32) {
if (this.getInode() != info.getInode()) {
changes.add(new Diff("Inode",
info.getInode(),
this.getInode()));
changes.add(new Diff("Inode", info.getInode(), this.getInode()));
}
if (this.getDevice() != info.getDevice()) {
changes.add(new Diff("Device",
info.getDevice(),
this.getDevice()));
changes.add(new Diff("Device", info.getDevice(), this
.getDevice()));
}
if (this.getNlink() != info.getNlink()) {
changes.add(new Diff("Nlink",
info.getNlink(),
this.getNlink()));
changes.add(new Diff("Nlink", info.getNlink(), this.getNlink()));
}
}
/* if changes were not detected then return empty String */
if (changes.isEmpty()){
return "";
}
StringBuffer sb = format(changes);
if (this.dirStatEnabled) {
sb.append(diff(info.stat));
@ -389,7 +373,9 @@ public class FileInfo extends FileAttrs implements java.io.Serializable {
stat();
return this.mtime != oldInfo.mtime;
boolean isModified = isModified(this.oldInfo);
return isModified;
}
public boolean changed()
@ -455,4 +441,49 @@ public class FileInfo extends FileAttrs implements java.io.Serializable {
return fetchInfo(sigar, name, false);
}
private boolean isModified(FileInfo info){
/* Check modified time */
if (this.getMtime() != info.getMtime()) {
return true;
} else if (this.getCtime() != info.getCtime()) {
return true;
}
if (this.getPermissions() != info.getPermissions()) {
return true;
}
if (this.getType() != info.getType()) {
return true;
}
if (this.getUid() != info.getUid()) {
return true;
}
if (this.getGid() != info.getGid()) {
return true;
}
if (this.getSize() != info.getSize()) {
return true;
}
if (!OperatingSystem.IS_WIN32) {
if (this.getInode() != info.getInode()) {
return true;
}
if (this.getDevice() != info.getDevice()) {
return true;
}
if (this.getNlink() != info.getNlink()) {
return true;
}
}
return false;
}
}

View File

@ -41,6 +41,8 @@ public class Sigar implements SigarProxy {
private static String loadError = null;
public static final long FIELD_NOTIMPL = -1;
public static final int PID_PROC_CPU_CACHE = 1;
public static final int PID_PROC_IO_CACHE = 2;
/**
* The Sigar java version.
@ -633,6 +635,57 @@ public class Sigar implements SigarProxy {
Integer.parseInt(port));
}
/**
* Get process disk IO info.
* @param pid THe process id.
* @exception SigarException on failure.
*/
public ProcDiskIO getProcDiskIO(long pid) throws SigarException {
try {
return ProcDiskIO.fetch(this, pid);
} catch (UnsatisfiedLinkError linkErrorException) {
// We want to handle exceptions gracefully even if the linked
// shared library is older and isn't compiled with the ProcDiskIO APIs.
// The downside of this is that we throw SigarNotImplemented exception
// also when the shared library can't be loaded.
SigarException sigarException = new SigarNotImplementedException();
sigarException.initCause(linkErrorException);
throw sigarException;
}
}
public ProcDiskIO getProcDiskIO(String pid) throws SigarException {
return getProcDiskIO(convertPid(pid));
}
/**
* Get process cumulative disk IO info.
* @param pid THe process id.
* @exception SigarException on failure.
*/
public ProcCumulativeDiskIO getProcCumulativeDiskIO(long pid) throws SigarException {
try {
return ProcCumulativeDiskIO.fetch(this, pid);
} catch (UnsatisfiedLinkError linkErrorException) {
// We want to handle exceptions gracefully even if the linked
// shared library is older and isn't compiled with the ProcDiskIO APIs.
// The downside of this is that we throw SigarNotImplemented exception
// also when the shared library can't be loaded.
SigarException sigarException = new SigarNotImplementedException();
sigarException.initCause(linkErrorException);
throw sigarException;
}
}
public ProcCumulativeDiskIO getProcCumulativeDiskIO(String pid) throws SigarException {
return getProcCumulativeDiskIO(convertPid(pid));
}
public DumpPidCache dumpPidCache() throws SigarException {
return DumpPidCache.fetch(this);
}
/**
* Get the cumulative cpu time for the calling thread.
*/

View File

@ -106,6 +106,16 @@ public interface SigarProxy {
public long getProcPort(String protocol, String port) throws SigarException;
public ProcDiskIO getProcDiskIO(long pid) throws SigarException;
public ProcDiskIO getProcDiskIO(String pid) throws SigarException;
public ProcCumulativeDiskIO getProcCumulativeDiskIO(long pid) throws SigarException;
public ProcCumulativeDiskIO getProcCumulativeDiskIO(String pid) throws SigarException;
public DumpPidCache dumpPidCache() throws SigarException;
public FileSystem[] getFileSystemList() throws SigarException;
public FileSystemMap getFileSystemMap() throws SigarException;

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2006-2007 Hyperic, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hyperic.sigar.cmd;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.SigarPermissionDeniedException;
/**
* Display all pid cache information.
*/
public class PidCacheInfo extends SigarCommandBase {
public PidCacheInfo(Shell shell) {
super(shell);
}
public PidCacheInfo() {
super();
}
protected boolean validateArgs(String[] args) {
return true;
}
public String getUsageShort() {
return "Display cache info for CPU cache and for IO cache";
}
public boolean isPidCompleter() {
return false;
}
public void output(String[] args) throws SigarException {
sigar.dumpPidCache();
}
}

View File

@ -100,6 +100,14 @@ public class ProcInfo extends SigarCommandBase {
try {
println("credname=" + sigar.getProcCredName(pid));
} catch (SigarException e) {}
try {
println("diskio=" + sigar.getProcDiskIO(pid));
} catch (SigarException e) {}
try {
println("cumulative diskio=" + sigar.getProcCumulativeDiskIO(pid));
} catch (SigarException e) {}
}
public static void main(String[] args) throws Exception {

View File

@ -102,6 +102,8 @@ public class Shell extends ShellBase {
registerCommandHandler("time", new Time(this));
registerCommandHandler("ulimit", new Ulimit(this));
registerCommandHandler("who", new Who(this));
registerCommandHandler("pid_cache_info", new PidCacheInfo(this));
if (SigarLoader.IS_WIN32) {
registerCommandHandler("service", new Win32Service(this));
registerCommandHandler("fversion", new FileVersionInfo(this));

View File

@ -19,6 +19,8 @@ package org.hyperic.sigar.jmx;
import org.hyperic.sigar.ProcCpu;
import org.hyperic.sigar.ProcFd;
import org.hyperic.sigar.ProcMem;
import org.hyperic.sigar.ProcUtil;
import org.hyperic.sigar.ProcDiskIO;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.SigarProxy;
@ -31,21 +33,25 @@ import org.hyperic.sigar.SigarProxyCache;
public class SigarProcess implements SigarProcessMBean {
private static final Long NOTIMPL = new Long(Sigar.FIELD_NOTIMPL);
private Sigar sigarImpl;
private SigarProxy sigar;
private long pid = -1;
public SigarProcess() {
this(new Sigar());
}
public SigarProcess(Sigar sigar) {
this.sigarImpl = sigar;
this.sigarImpl = new Sigar();
this.sigar = SigarProxyCache.newInstance(sigarImpl);
}
public SigarProcess(SigarProxy sigar) {
this.sigar = sigar;
}
public void close() {
if (this.sigarImpl != null) {
this.sigarImpl.close();
}
}
private RuntimeException unexpectedError(String type,
SigarException e) {
@ -57,8 +63,7 @@ public class SigarProcess implements SigarProcessMBean {
private synchronized ProcMem getMem() {
try {
long pid = this.sigar.getPid();
return this.sigar.getProcMem(pid);
return this.sigar.getProcMem(getPid());
} catch (SigarException e) {
throw unexpectedError("Mem", e);
}
@ -66,22 +71,40 @@ public class SigarProcess implements SigarProcessMBean {
private synchronized ProcCpu getCpu() {
try {
long pid = this.sigar.getPid();
return this.sigar.getProcCpu(pid);
return this.sigar.getProcCpu(getPid());
} catch (SigarException e) {
throw unexpectedError("Cpu", e);
}
}
private synchronized ProcFd getFd() {
private synchronized ProcDiskIO getDiskIO() {
try {
long pid = this.sigar.getPid();
return this.sigar.getProcFd(pid);
return this.sigar.getProcDiskIO(getPid());
} catch (SigarException e) {
throw unexpectedError("Fd", e);
throw unexpectedError("DiskIO", e);
}
}
private synchronized ProcFd getFd() throws SigarException {
return this.sigar.getProcFd(getPid());
}
public long getPid() {
if (this.pid < 0) {
return this.sigar.getPid();
}
else {
return this.pid;
}
}
public void setPid(long pid) {
this.pid = pid;
}
public Long getMemSize() {
return new Long(getMem().getSize());
}
@ -119,7 +142,11 @@ public class SigarProcess implements SigarProcessMBean {
}
public Long getOpenFd() {
try {
return new Long(getFd().getTotal());
} catch (SigarException e) {
return NOTIMPL;
}
}
public static void main(String args[]) {
@ -132,4 +159,9 @@ public class SigarProcess implements SigarProcessMBean {
System.out.println("TimeSys=" + proc.getTimeSys());
System.out.println("OpenFd=" + proc.getOpenFd());
}
public Double getBytesReadWriteTotal() {
return new Double(getDiskIO().getBytesTotal());
}
}

View File

@ -44,4 +44,6 @@ public interface SigarProcessMBean {
public Double getCpuUsage();
public Long getOpenFd();
public Double getBytesReadWriteTotal();
}

View File

@ -133,11 +133,11 @@ public class TestFileInfo extends SigarTestCase {
tmp.deleteOnExit();
traceln("TMP=" + file);
try {
// try {
//stat() mtime is in seconds, this happens to quick to detect change.
Thread.sleep(1000 * 1);
} catch (InterruptedException e) {
}
//Thread.sleep(1000 * 1);
// } catch (InterruptedException e) {
// }
try {
FileInfo info = sigar.getFileInfo(file);

View File

@ -0,0 +1,57 @@
package org.hyperic.sigar.test;
import org.hyperic.sigar.ProcDiskIO;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
public class TestProcDiskIO extends SigarTestCase {
public TestProcDiskIO(String name) {
super(name);
}
private void traceDiskIO(Sigar sigar, long pid) throws Exception {
ProcDiskIO procDiskIO;
try {
procDiskIO = sigar.getProcDiskIO(pid);
} catch (SigarException e) {
traceln("pid " + pid + ": " + e.getMessage());
// throw e;
return;
}
long bytesRead = procDiskIO.getBytesRead();
long bytesWritten = procDiskIO.getBytesWritten();
long bytesTotal = procDiskIO.getBytesTotal();
traceln("Pid=" + pid);
traceln("Bytes Read=" + Sigar.formatSize(bytesRead));
traceln("Bytes Written=" + Sigar.formatSize(bytesWritten));
traceln("Bytes Total=" + Sigar.formatSize(bytesTotal));
if (bytesRead != -1 && bytesWritten != -1 && bytesTotal != -1) {
assertTrue("Bytes total should equal bytesRead + bytesWritten",
(bytesTotal == bytesRead + bytesWritten));
}
}
public void testCreate() throws Exception {
Sigar sigar = getSigar();
boolean caughtException = false;
try {
sigar.getProcDiskIO(getInvalidPid());
} catch (SigarException e) {
caughtException = true;
}
assertTrue("Test on invalid PID should have thrown an exception.", caughtException);
long[] pids = sigar.getProcList();
for (int i=0; i<pids.length; i++) {
traceDiskIO(sigar, pids[i]);
}
}
}

View File

@ -20,6 +20,8 @@ package org.hyperic.sigar.win32;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
@ -284,6 +286,24 @@ public class Pdh extends Win32 {
return trans.toString();
}
private long addPdhCounter(String path, boolean format) throws Win32Exception {
long counter;
/*
* Some metrics are missing the '/sec' suffix. This flow,
* first tries to add the counter without the '/sec' and
* if fails, try again with it. If the seconds call fails,
* throw an exception.This issue must be addressed
* at the java level (and not C code), since the counter
* names must be translated before.
*/
try {
counter = pdhAddCounter(this.query, translate(path));
} catch (Win32Exception e) {
counter = pdhAddCounter(this.query, translate(path + "/sec"));
}
return counter;
}
private double getValue(String path, boolean format)
throws Win32Exception {
@ -291,8 +311,8 @@ public class Pdh extends Win32 {
pdhConnectMachine(this.hostname);
}
long counter =
pdhAddCounter(this.query, translate(path));
long counter = addPdhCounter(path, format);
try {
return pdhGetValue(this.query, counter, format);
} finally {
@ -353,6 +373,60 @@ public class Pdh extends Win32 {
return pdhGetObjects();
}
/**
sigar is compatible with java 1.4 (no generics there)
**/
public Map getFormattedValues(Collection paths) throws Win32Exception {
if (this.hostname != null) {
pdhConnectMachine(this.hostname);
}
Map res = new HashMap();
Map counters = new HashMap();
/*
* no for each loop either
*/
Iterator pathsIt = paths.iterator();
while (pathsIt.hasNext()) {
String path = (String)pathsIt.next();
try {
counters.put(path, new Long(pdhAddCounter(this.query, translate(path))));
} catch ( Win32Exception ex) {
}
}
if (counters.size() > 0) {
try {
pdhCollectQueryDataOverSecond(this.query);
pathsIt = paths.iterator();
while (pathsIt.hasNext()) {
try {
String path = (String)pathsIt.next();
Long c = (Long)counters.get(path);
if (c != null) {
double val = pdhGetFormattedValue(c.longValue());
res.put(path, new Double(val));
}
} catch (Exception ex) {
}
}
} finally {
Iterator countersIt = counters.values().iterator();
while (countersIt.hasNext()) {
try {
Long counter = (Long)countersIt.next();
pdhRemoveCounter(counter.longValue());
} catch (Win32Exception ex) {
}
}
}
}
return res;
}
public static final native int validate(String path);
private static final native void pdhConnectMachine(String host)
@ -383,6 +457,13 @@ public class Pdh extends Win32 {
private static final native int pdhLookupPerfIndex(String name)
throws Win32Exception;
private static final native void pdhCollectQueryDataOverSecond(long query)
throws Win32Exception;
private static final native double pdhGetFormattedValue(long counter)
throws Win32Exception;
/**
* Main method for dumping the entire PDH
*

View File

@ -284,6 +284,47 @@ typedef struct {
SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_mem_t *procmem);
typedef struct {
sigar_uint64_t
bytes_read,
bytes_written,
bytes_total;
} sigar_proc_disk_io_t;
SIGAR_DECLARE(int) sigar_proc_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_disk_io_t *proc_disk_io);
typedef struct {
sigar_uint64_t
bytes_read,
bytes_written,
bytes_total;
sigar_uint64_t last_time;
sigar_uint64_t
bytes_read_diff,
bytes_written_diff,
bytes_total_diff;
} sigar_cached_proc_disk_io_t;
typedef struct {
sigar_uint64_t
bytes_read,
bytes_written,
bytes_total;
} sigar_proc_cumulative_disk_io_t;
SIGAR_DECLARE(int) sigar_proc_cumulative_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cumulative_disk_io_t *proc_cumulative_disk_io);
typedef struct {
sigar_uint64_t dummy;
}sigar_dump_pid_cache_t;
SIGAR_DECLARE(int) sigar_dump_pid_cache_get(sigar_t *sigar, sigar_dump_pid_cache_t *info);
typedef struct {
sigar_uid_t uid;
sigar_gid_t gid;

View File

@ -66,7 +66,8 @@
sigar_cache_t *proc_cpu; \
sigar_cache_t *net_listen; \
sigar_cache_t *net_services_tcp; \
sigar_cache_t *net_services_udp
sigar_cache_t *net_services_udp;\
sigar_cache_t *proc_io
#if defined(WIN32)
# define SIGAR_INLINE __inline
@ -339,11 +340,15 @@ int sigar_get_iftype(const char *name, int *type, int *inst);
#define SIGAR_NIC_LOOPBACK "Local Loopback"
#define SIGAR_NIC_ETHERNET "Ethernet"
#define SIGAR_NIC_NETROM "AMPR NET/ROM"
#define PID_CACHE_CLEANUP_PERIOD 1000*60*10 /* 10 minutes */
#define PID_CACHE_ENTRY_EXPIRE_PERIOD 1000*60*20 /* 20 minutes */
#ifndef WIN32
#include <netdb.h>
#endif
#define PROC_PID_CPU_CACHE 1
#define PROC_PID_IO_CACHE 2
#define SIGAR_HOSTENT_LEN 1024
#if defined(_AIX)
#define SIGAR_HAS_HOSTENT_DATA

View File

@ -170,15 +170,21 @@ struct sigar_cache_entry_t {
sigar_cache_entry_t *next;
sigar_uint64_t id;
void *value;
sigar_uint64_t last_access_time;
};
typedef struct {
sigar_cache_entry_t **entries;
unsigned int count, size;
void (*free_value)(void *ptr);
sigar_uint64_t entry_expire_period;
sigar_uint64_t cleanup_period_millis;
sigar_uint64_t last_cleanup_time;
} sigar_cache_t;
sigar_cache_t *sigar_cache_new(int size);
sigar_cache_t *sigar_expired_cache_new(int size, sigar_uint64_t cleanup_period_millis, sigar_uint64_t entry_expire_period);
void sigar_cache_dump(sigar_cache_t *table);
sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table,
sigar_uint64_t key);

View File

@ -745,6 +745,23 @@ int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
return SIGAR_OK;
}
int sigar_proc_cumulative_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cumulative_disk_io_t *cumulative_proc_disk_io)
{
int status = sigar_getprocs(sigar, pid);
struct procsinfo64 *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
cumulative_proc_disk_io->bytes_read = SIGAR_FIELD_NOTIMPL;
cumulative_proc_disk_io->bytes_written = SIGAR_FIELD_NOTIMPL;
cumulative_proc_disk_io->bytes_total = pinfo->pi_ioch;
return SIGAR_OK;
}
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{

View File

@ -1241,6 +1241,13 @@ int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
return SIGAR_OK;
}
int sigar_proc_cumulative_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cumulative_disk_io_t *proc_cumulative_disk_io)
{
return SIGAR_ENOTIMPL;
}
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{

View File

@ -305,6 +305,25 @@ int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
return SIGAR_OK;
}
int sigar_proc_cumulative_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cumulative_disk_io_t *proc_cumulative_disk_io)
{
int status = sigar_pstat_getproc(sigar, pid);
struct pst_status *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
proc_cumulative_disk_io->bytes_read = SIGAR_FIELD_NOTIMPL;
proc_cumulative_disk_io->bytes_written = SIGAR_FIELD_NOTIMPL;
proc_cumulative_disk_io->bytes_total = pinfo->pst_ioch;
return SIGAR_OK;
}
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{

View File

@ -767,6 +767,34 @@ int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
return SIGAR_OK;
}
SIGAR_INLINE sigar_uint64_t get_named_proc_token(char *buffer,
char *token) {
char *ptr = strstr(buffer, token);
if (!ptr) {
return SIGAR_FIELD_NOTIMPL;
}
ptr = sigar_skip_token(ptr);
return sigar_strtoul(ptr);
}
int sigar_proc_cumulative_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cumulative_disk_io_t *proc_cumulative_disk_io)
{
char buffer[BUFSIZ];
int status = SIGAR_PROC_FILE2STR(buffer, pid, "/io");
if (status != SIGAR_OK) {
return status;
}
proc_cumulative_disk_io->bytes_read = get_named_proc_token(buffer, "\nread_bytes");
proc_cumulative_disk_io->bytes_written = get_named_proc_token(buffer, "\nwrite_bytes");
proc_cumulative_disk_io->bytes_total = proc_cumulative_disk_io->bytes_read + proc_cumulative_disk_io->bytes_written;
return SIGAR_OK;
}
#define NO_ID_MSG "[proc_cred] /proc/%lu" PROC_PSTATUS " missing "
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,

View File

@ -405,7 +405,7 @@ int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
cpu->idle += xcpu->idle;
cpu->nice += xcpu->nice;
cpu->wait += xcpu->wait;
cpu->total = xcpu->total;
cpu->total += xcpu->total;
}
return SIGAR_OK;
@ -717,6 +717,21 @@ int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
return SIGAR_OK;
}
int sigar_proc_cumulative_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cumulative_disk_io_t *proc_cumulative_disk_io)
{
prusage_t usage;
int status;
if ((status = sigar_proc_usage_get(sigar, &usage, pid)) != SIGAR_OK) {
return status;
}
proc_cumulative_disk_io->bytes_read = SIGAR_FIELD_NOTIMPL;
proc_cumulative_disk_io->bytes_written = SIGAR_FIELD_NOTIMPL;
proc_cumulative_disk_io->bytes_total = usage.pr_ioch;
return SIGAR_OK;
}
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{

View File

@ -317,6 +317,8 @@ typedef struct {
sigar_uint64_t handles;
sigar_uint64_t threads;
sigar_uint64_t page_faults;
sigar_uint64_t bytes_read;
sigar_uint64_t bytes_written;
} sigar_win32_pinfo_t;
typedef struct {

View File

@ -58,6 +58,8 @@ typedef enum {
#define PERF_TITLE_PPID 1410
#define PERF_TITLE_PRIORITY 682
#define PERF_TITLE_START_TIME 684
#define PERF_TITLE_IO_READ_BYTES_SEC 1420
#define PERF_TITLE_IO_WRITE_BYTES_SEC 1422
typedef enum {
PERF_IX_CPUTIME,
@ -70,6 +72,8 @@ typedef enum {
PERF_IX_PPID,
PERF_IX_PRIORITY,
PERF_IX_START_TIME,
PERF_IX_IO_READ_BYTES_SEC,
PERF_IX_IO_WRITE_BYTES_SEC,
PERF_IX_MAX
} perf_proc_offsets_t;
@ -1187,6 +1191,23 @@ SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_proc_cumulative_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cumulative_disk_io_t *proc_cumulative_disk_io)
{
int status = get_proc_info(sigar, pid);
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
proc_cumulative_disk_io->bytes_read = pinfo->bytes_read;
proc_cumulative_disk_io->bytes_written = pinfo->bytes_written;
proc_cumulative_disk_io->bytes_total = proc_cumulative_disk_io->bytes_read + proc_cumulative_disk_io->bytes_written;
return SIGAR_OK;
}
#define TOKEN_DAC (STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY)
SIGAR_DECLARE(int)
@ -1418,6 +1439,12 @@ static int get_proc_info(sigar_t *sigar, sigar_pid_t pid)
case PERF_TITLE_START_TIME:
perf_offsets[PERF_IX_START_TIME] = offset;
break;
case PERF_TITLE_IO_READ_BYTES_SEC:
perf_offsets[PERF_IX_IO_READ_BYTES_SEC] = offset;
break;
case PERF_TITLE_IO_WRITE_BYTES_SEC:
perf_offsets[PERF_IX_IO_WRITE_BYTES_SEC] = offset;
break;
}
}
@ -1443,6 +1470,8 @@ static int get_proc_info(sigar_t *sigar, sigar_pid_t pid)
pinfo->handles = PERF_VAL(PERF_IX_HANDLE_CNT);
pinfo->threads = PERF_VAL(PERF_IX_THREAD_CNT);
pinfo->page_faults = PERF_VAL(PERF_IX_PAGE_FAULTS);
pinfo->bytes_read = PERF_VAL(PERF_IX_IO_READ_BYTES_SEC);
pinfo->bytes_written = PERF_VAL(PERF_IX_IO_WRITE_BYTES_SEC);
return SIGAR_OK;
}
@ -3504,6 +3533,7 @@ int sigar_who_list_get_win32(sigar_t *sigar,
#define SIGAR_ARCH "x86"
#endif
int sigar_os_sys_info_get(sigar_t *sigar,
sigar_sys_info_t *sysinfo)
{
@ -3552,10 +3582,24 @@ int sigar_os_sys_info_get(sigar_t *sigar,
}
}
else {
// not nt work station
if (version.dwMinorVersion == 0 || version.dwMinorVersion ==1) {
vendor_name = "Windows 2008";
vendor_version = "2008";
code_name = "Longhorn Server";
}
else if (version.dwMinorVersion == 2) {
vendor_name = "Windows 2012";
vendor_version = "2012";
code_name = "Windows Server 8";
}
else {
// defaults
vendor_name = "Windows Unknown";
vendor_version = "2012";
}
}
}
SIGAR_SSTRCPY(sysinfo->name, "Win32");

View File

@ -59,6 +59,7 @@ SIGAR_DECLARE(int) sigar_open(sigar_t **sigar)
(*sigar)->net_listen = NULL;
(*sigar)->net_services_tcp = NULL;
(*sigar)->net_services_udp = NULL;
(*sigar)->proc_io = NULL;
}
return status;
@ -91,6 +92,11 @@ SIGAR_DECLARE(int) sigar_close(sigar_t *sigar)
if (sigar->net_services_udp) {
sigar_cache_destroy(sigar->net_services_udp);
}
if (sigar->proc_io) {
sigar_cache_destroy(sigar->proc_io);
}
return sigar_os_close(sigar);
}
@ -118,7 +124,7 @@ SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid,
int status;
if (!sigar->proc_cpu) {
sigar->proc_cpu = sigar_cache_new(128);
sigar->proc_cpu = sigar_expired_cache_new(128, PID_CACHE_CLEANUP_PERIOD, PID_CACHE_ENTRY_EXPIRE_PERIOD);
}
entry = sigar_cache_get(sigar->proc_cpu, pid);
@ -167,6 +173,106 @@ SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid,
return SIGAR_OK;
}
void copy_cached_disk_io_into_disk_io( sigar_cached_proc_disk_io_t *cached, sigar_proc_disk_io_t *proc_disk_io) {
proc_disk_io->bytes_read = cached->bytes_read_diff;
proc_disk_io->bytes_written = cached->bytes_written_diff;
proc_disk_io->bytes_total = cached->bytes_total_diff;
}
sigar_uint64_t get_io_diff(sigar_uint64_t current_value, sigar_uint64_t prev_value, sigar_uint64_t time_diff) {
double io_diff;
sigar_uint64_t int_io_diff;
if ( current_value == SIGAR_FIELD_NOTIMPL ) {
return SIGAR_FIELD_NOTIMPL;
}
io_diff = (( current_value - prev_value)/(double)time_diff)*SIGAR_MSEC;
int_io_diff = (sigar_uint64_t)io_diff;
if (int_io_diff >=0) {
return int_io_diff;
}
return 0;
}
void calculate_io_diff(sigar_proc_cumulative_disk_io_t * proc_disk_io, sigar_cached_proc_disk_io_t *cached, sigar_uint64_t time_diff, int is_first_time) {
/*calculate avg diff /read/write/total per second*/
if (!is_first_time) {
cached->bytes_written_diff = get_io_diff(proc_disk_io->bytes_written, cached->bytes_written, time_diff);
cached->bytes_read_diff = get_io_diff(proc_disk_io->bytes_read, cached->bytes_read, time_diff);
cached->bytes_total_diff = get_io_diff(proc_disk_io->bytes_total, cached->bytes_total, time_diff);
}
else {
cached->bytes_total_diff = cached->bytes_read_diff = cached->bytes_written_diff = 0.0;
}
// now put in cache the current cumulative values
cached->bytes_written = proc_disk_io->bytes_written;
cached->bytes_read = proc_disk_io->bytes_read;
cached->bytes_total = proc_disk_io->bytes_total;
}
SIGAR_DECLARE(int) sigar_proc_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_disk_io_t *proc_disk_io)
{
sigar_cache_entry_t *entry;
sigar_cached_proc_disk_io_t *prev;
sigar_proc_cumulative_disk_io_t cumulative_proc_disk_io;
sigar_uint64_t time_now = sigar_time_now_millis();
sigar_uint64_t time_diff;
int status, is_first_time;
if (!sigar->proc_io) {
sigar->proc_io = sigar_expired_cache_new(128, PID_CACHE_CLEANUP_PERIOD, PID_CACHE_ENTRY_EXPIRE_PERIOD);
}
entry = sigar_cache_get(sigar->proc_io, pid);
if (entry->value) {
prev = (sigar_cached_proc_disk_io_t *)entry->value;
}
else {
prev = entry->value = malloc(sizeof(*prev));
SIGAR_ZERO(prev);
}
is_first_time = (prev->last_time == 0);
time_diff = time_now - prev->last_time;
if (time_diff < 1000) {
/* we were just called within < 1 second ago. */
copy_cached_disk_io_into_disk_io(prev, proc_disk_io);
if (time_diff < 0) {
// something is wrong at least from now on the time will be ok
prev->last_time = time_now;
}
return SIGAR_OK;
}
prev->last_time = time_now;
status =
sigar_proc_cumulative_disk_io_get(sigar, pid,
&cumulative_proc_disk_io);
if (status != SIGAR_OK) {
return status;
}
calculate_io_diff(&cumulative_proc_disk_io, prev, time_diff, is_first_time);
copy_cached_disk_io_into_disk_io(prev, proc_disk_io);
return SIGAR_OK;
}
void get_cache_info(sigar_cache_t * cache, char * name){
if (cache == NULL) {
return;
}
printf("******** %s *********\n", name);
sigar_cache_dump(cache);
}
SIGAR_DECLARE(int) sigar_dump_pid_cache_get(sigar_t *sigar, sigar_dump_pid_cache_t *info) {
get_cache_info(sigar->proc_cpu, "proc cpu cache");
get_cache_info(sigar->proc_io, "proc io cache");
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar,
sigar_proc_stat_t *procstat)

View File

@ -35,7 +35,7 @@ static void free_value(void *ptr)
free(ptr);
}
sigar_cache_t *sigar_cache_new(int size)
sigar_cache_t *sigar_expired_cache_new(int size, sigar_uint64_t cleanup_period_millis, sigar_uint64_t entry_expire_period)
{
sigar_cache_t *table = malloc(sizeof(*table));
table->count = 0;
@ -43,15 +43,26 @@ sigar_cache_t *sigar_cache_new(int size)
table->entries = malloc(ENTRIES_SIZE(size));
memset(table->entries, '\0', ENTRIES_SIZE(size));
table->free_value = free_value;
table->cleanup_period_millis = cleanup_period_millis;
table->last_cleanup_time = sigar_time_now_millis();
table->entry_expire_period = entry_expire_period;
return table;
}
#ifdef DEBUG_CACHE
sigar_cache_t *sigar_cache_new(int size)
{
return sigar_expired_cache_new(size, SIGAR_FIELD_NOTIMPL, SIGAR_FIELD_NOTIMPL);
}
/*#ifdef DEBUG_CACHE*/
/* see how well entries are distributed */
static void sigar_cache_dump(sigar_cache_t *table)
void sigar_cache_dump(sigar_cache_t *table)
{
int i;
sigar_cache_entry_t **entries = table->entries;
printf("table size %lu\n", (long)table->size);
printf("table count %lu\n", (long)table->count);
for (i=0; i<table->size; i++) {
sigar_cache_entry_t *entry = *entries++;
@ -68,12 +79,12 @@ static void sigar_cache_dump(sigar_cache_t *table)
printf("\n");
fflush(stdout);
}
#endif
/*#endif*/
static void sigar_cache_rehash(sigar_cache_t *table)
{
int i;
unsigned int new_size = table->size * 2 + 1;
unsigned int new_size = table->count * 2 + 1;
sigar_cache_entry_t **entries = table->entries;
sigar_cache_entry_t **new_entries =
malloc(ENTRIES_SIZE(new_size));
@ -101,16 +112,76 @@ static void sigar_cache_rehash(sigar_cache_t *table)
#define SIGAR_CACHE_IX(t, k) \
t->entries + (k % t->size)
void sigar_perform_cleanup_if_necessary(sigar_cache_t *table) {
sigar_uint64_t current_time;
int i;
sigar_cache_entry_t **entries;
if (table->cleanup_period_millis == SIGAR_FIELD_NOTIMPL) {
/* no cleanup for this cache) */
return;
}
current_time = sigar_time_now_millis();
if ((current_time - table->last_cleanup_time) < table->cleanup_period_millis) {
/* not enough time has passed since last cleanup */
return;
}
/* performing cleanup */
entries = table->entries;
table->last_cleanup_time = current_time;
for (i=0; i<table->size; i++) {
sigar_cache_entry_t *entry, *ptr, *entry_prev=NULL, **entry_in_table;
entry_in_table = entries;
entry = *entries++;
while (entry) {
sigar_uint64_t period_with_no_access = current_time - entry->last_access_time;
ptr = entry->next;
if (table->entry_expire_period < period_with_no_access) {
/* no one acess this entry for too long - we can delete it */
if (entry->value) {
table->free_value(entry->value);
}
free(entry);
table->count--;
if (entry_prev != NULL) {
entry_prev->next = ptr;
}
else {
/* removing first entry - head of list should point to next entry */
*entry_in_table = ptr;
}
}
else {
/* entry not expired - advance entry_prev to current entry*/
entry_prev = entry;
}
entry = ptr;
}
}
if (table->count < (table->size/4)) {
/* hash table (the array size) too big for the amount of values it contains perform rehash */
sigar_cache_rehash(table);
}
}
sigar_cache_entry_t *sigar_cache_find(sigar_cache_t *table,
sigar_uint64_t key)
{
sigar_cache_entry_t *entry, **ptr;
sigar_perform_cleanup_if_necessary(table);
for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr;
entry;
ptr = &entry->next, entry = *ptr)
{
if (entry->id == key) {
entry->last_access_time = sigar_time_now_millis();
return entry;
}
}
@ -123,17 +194,19 @@ sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table,
sigar_uint64_t key)
{
sigar_cache_entry_t *entry, **ptr;
sigar_perform_cleanup_if_necessary(table);
for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr;
entry;
ptr = &entry->next, entry = *ptr)
{
if (entry->id == key) {
entry->last_access_time = sigar_time_now_millis();
return entry;
}
}
if (table->count++ > table->size) {
if (++table->count > table->size) {
sigar_cache_rehash(table);
for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr;
@ -147,6 +220,7 @@ sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table,
entry->id = key;
entry->value = NULL;
entry->next = NULL;
entry->last_access_time = sigar_time_now_millis();
return entry;
}

View File

@ -1325,6 +1325,14 @@ static ptql_lookup_t PTQL_Cpu[] = {
{ NULL }
};
static ptql_lookup_t PTQL_Disk_IO[] = {
{ "BytesRead", PTQL_LOOKUP_ENTRY(proc_disk_io, bytes_read, UI64) },
{ "BytesWritten", PTQL_LOOKUP_ENTRY(proc_disk_io, bytes_written, UI64) },
{ "BytesTotal", PTQL_LOOKUP_ENTRY(proc_disk_io, bytes_total, UI64) },
{ NULL }
};
static ptql_lookup_t PTQL_CredName[] = {
{ "User", PTQL_LOOKUP_ENTRY(proc_cred_name, user, STR) },
{ "Group", PTQL_LOOKUP_ENTRY(proc_cred_name, group, STR) },
@ -1411,6 +1419,7 @@ static ptql_entry_t ptql_map[] = {
{ "Port", PTQL_Port },
{ "Pid", PTQL_Pid },
{ "Service", PTQL_Service },
{ "Disk_IO", PTQL_Disk_IO },
{ NULL }
};