|
@@ -1178,93 +1178,116 @@ bool getPacketStats(unsigned & tx, unsigned & rx)
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
|
-struct CProcInfo: extends CInterface
|
|
|
+struct UserStatusInfo
|
|
|
{
|
|
|
- IMPLEMENT_IINTERFACE;
|
|
|
- int pid;
|
|
|
- char cmd[16];
|
|
|
- unsigned tot_utime;
|
|
|
- unsigned tot_stime;
|
|
|
- unsigned utime;
|
|
|
- unsigned stime;
|
|
|
- bool active;
|
|
|
- bool first;
|
|
|
-
|
|
|
- CProcInfo(int _pid)
|
|
|
+public:
|
|
|
+ UserStatusInfo(int _pid)
|
|
|
{
|
|
|
pid = _pid;
|
|
|
- tot_utime = 0;
|
|
|
- tot_stime = 0;
|
|
|
- utime = 0;
|
|
|
- stime = 0;
|
|
|
- active = false;
|
|
|
- first = true;
|
|
|
- }
|
|
|
-
|
|
|
- char *skipnumfld(char *s, const char *&num)
|
|
|
- {
|
|
|
- while (*s&&isspace(*s))
|
|
|
- s++;
|
|
|
- num = s;
|
|
|
- if ((*s=='-')||(*s=='+'))
|
|
|
- s++;
|
|
|
- while (*s&&isdigit(*s))
|
|
|
- s++;
|
|
|
- if (*s==' ')
|
|
|
- *(s++)= 0; // terminate num
|
|
|
- while (*s&&isspace(*s))
|
|
|
- s++;
|
|
|
- return s;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- bool load()
|
|
|
+ bool update()
|
|
|
{
|
|
|
StringBuffer fn;
|
|
|
fn.appendf("/proc/%d/stat", pid);
|
|
|
char buf[800]; /* about 40 fields, 64-bit decimal is about 20 chars */
|
|
|
int fd = open(fn.str(), O_RDONLY, 0);
|
|
|
- if (fd==-1)
|
|
|
+ if (fd==-1)
|
|
|
return false;
|
|
|
int rd = read(fd, buf, sizeof(buf)-1);
|
|
|
close(fd);
|
|
|
- if (rd<80)
|
|
|
+ if (rd<80)
|
|
|
return false;
|
|
|
buf[rd] = 0;
|
|
|
+
|
|
|
char *s = strchr(buf,'(');
|
|
|
- if (!s)
|
|
|
+ if (!s)
|
|
|
return false;
|
|
|
s++;
|
|
|
unsigned i = 0;
|
|
|
while (*s&&(*s!=')')&&(i<15))
|
|
|
cmd[i++] = *(s++);
|
|
|
- if (!*s)
|
|
|
+ if (!*s)
|
|
|
return false;
|
|
|
cmd[i] = 0;
|
|
|
s+=2;
|
|
|
+
|
|
|
char state = *(s++);
|
|
|
- //printf("**'%s'\n",s);
|
|
|
+
|
|
|
+ //The PID of the parent process
|
|
|
const char *num;
|
|
|
s = skipnumfld(s,num);
|
|
|
int ppid = atoi(num);
|
|
|
+
|
|
|
// skip pgrp, session, tty_num, tpgid, flags, min_flt, cmin_flt, maj_flt, cmaj_flt
|
|
|
for (i=0;i<9;i++)
|
|
|
s = skipnumfld(s,num);
|
|
|
- unsigned prev_utime = tot_utime;
|
|
|
- unsigned prev_stime = tot_stime;
|
|
|
+
|
|
|
+ //utime - user mode time in clock ticks.
|
|
|
s = skipnumfld(s,num);
|
|
|
//printf("**N'%s'\n",num);
|
|
|
- tot_utime = (unsigned)atoi64_l(num,strlen(num));
|
|
|
+ time.user = (unsigned)atoi64_l(num,strlen(num));
|
|
|
+
|
|
|
+ //stime - amount of tme scheduled in kernel mode in clock ticks
|
|
|
s = skipnumfld(s,num);
|
|
|
//printf("**N'%s'\n",num);
|
|
|
- tot_stime = (unsigned)atoi64_l(num,strlen(num));
|
|
|
+ time.system = (unsigned)atoi64_l(num,strlen(num));
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+public:
|
|
|
+ int pid;
|
|
|
+ char cmd[16];
|
|
|
+ UserSystemTime_t time;
|
|
|
+
|
|
|
+private:
|
|
|
+ char *skipnumfld(char *s, const char *&num)
|
|
|
+ {
|
|
|
+ while (*s&&isspace(*s))
|
|
|
+ s++;
|
|
|
+ num = s;
|
|
|
+ if ((*s=='-')||(*s=='+'))
|
|
|
+ s++;
|
|
|
+ while (*s&&isdigit(*s))
|
|
|
+ s++;
|
|
|
+ if (*s==' ')
|
|
|
+ *(s++)= 0; // terminate num
|
|
|
+ while (*s&&isspace(*s))
|
|
|
+ s++;
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+struct CProcInfo: extends CInterface
|
|
|
+{
|
|
|
+ IMPLEMENT_IINTERFACE;
|
|
|
+
|
|
|
+ UserStatusInfo info;
|
|
|
+ UserSystemTime_t delta;
|
|
|
+ bool active;
|
|
|
+ bool first;
|
|
|
+
|
|
|
+ CProcInfo(int _pid) : info(_pid)
|
|
|
+ {
|
|
|
+ active = false;
|
|
|
+ first = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ inline int pid() const { return info.pid; }
|
|
|
+
|
|
|
+ bool load()
|
|
|
+ {
|
|
|
+ UserSystemTime_t prev = info.time;
|
|
|
+ if (!info.update())
|
|
|
+ return false;
|
|
|
+
|
|
|
if (first)
|
|
|
first = false;
|
|
|
else {
|
|
|
- stime = tot_stime-prev_stime;
|
|
|
- utime = tot_utime-prev_utime;
|
|
|
+ delta.system = info.time.system-prev.system;
|
|
|
+ delta.user = info.time.user-prev.user;
|
|
|
}
|
|
|
- active = true;
|
|
|
return true;
|
|
|
}
|
|
|
};
|
|
@@ -1280,7 +1303,7 @@ class CProcessMonitor
|
|
|
{
|
|
|
CProcInfo *pi1 = QUERYINTERFACE(*i1,CProcInfo);
|
|
|
CProcInfo *pi2 = QUERYINTERFACE(*i2,CProcInfo);
|
|
|
- return pi2->stime+pi2->utime-pi1->stime-pi1->utime;
|
|
|
+ return pi2->delta.system+pi2->delta.user-pi1->delta.system-pi1->delta.user;
|
|
|
}
|
|
|
public:
|
|
|
CProcessMonitor()
|
|
@@ -1305,7 +1328,7 @@ public:
|
|
|
if (pid) {
|
|
|
CProcInfo *pi = NULL;
|
|
|
ForEachItemIn(i2,processes) {
|
|
|
- if (processes.item(i2).pid == pid) {
|
|
|
+ if (processes.item(i2).pid() == pid) {
|
|
|
pi = &processes.item(i2);
|
|
|
break;
|
|
|
}
|
|
@@ -1323,7 +1346,7 @@ public:
|
|
|
ForEachItemInRev(i3,processes) {
|
|
|
CProcInfo &pi = processes.item(i3);
|
|
|
if (pi.active)
|
|
|
- tot_time += pi.stime+pi.utime;
|
|
|
+ tot_time += pi.delta.system+pi.delta.user;
|
|
|
else
|
|
|
processes.remove(i3);
|
|
|
}
|
|
@@ -1341,10 +1364,11 @@ public:
|
|
|
StringBuffer name;
|
|
|
ForEachItemIn(i1,processes) {
|
|
|
CProcInfo &pi = processes.item(i1);
|
|
|
- if ((pi.stime==0)&&(pi.utime==0))
|
|
|
+ if ((pi.delta.system==0)&&(pi.delta.user==0))
|
|
|
break;
|
|
|
- getThreadName(pi.pid,0,name.clear());
|
|
|
- str.appendf("\n TT: PI=%d PN=%s PC=%d ST=%d UT=%d%s%s",pi.pid,pi.cmd,(pi.stime+pi.utime)*100/tot_time,pi.stime,pi.utime,name.length()?" TN=":"",name.str());
|
|
|
+ getThreadName(pi.pid(),0,name.clear());
|
|
|
+ str.appendf("\n TT: PI=%d PN=%s PC=%d ST=%d UT=%d%s%s",
|
|
|
+ pi.pid(),pi.info.cmd,(pi.delta.system+pi.delta.user)*100/tot_time,pi.delta.system,pi.delta.user,name.length()?" TN=":"",name.str());
|
|
|
if (--n==0)
|
|
|
break;
|
|
|
}
|
|
@@ -1886,6 +1910,36 @@ public:
|
|
|
|
|
|
#endif
|
|
|
|
|
|
+#ifdef _WIN32
|
|
|
+static struct CNtKernelInformation
|
|
|
+{
|
|
|
+ CNtKernelInformation()
|
|
|
+ {
|
|
|
+ NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(
|
|
|
+ GetModuleHandle("ntdll"),
|
|
|
+ "NtQuerySystemInformation"
|
|
|
+ );
|
|
|
+ NtQueryInformationProcess = (PROCNTQIP)GetProcAddress(
|
|
|
+ GetModuleHandle("ntdll"),
|
|
|
+ "NtQueryInformationProcess"
|
|
|
+ );
|
|
|
+ // GetSystemTimes not available on earlier versions of Windows - NtQuerySystemInformation not consistent on later ones. So use GetSystemTimes if available
|
|
|
+ pGetSystemTimes = (PROCNTGST)GetProcAddress(
|
|
|
+ GetModuleHandle("kernel32"),
|
|
|
+ "GetSystemTimes"
|
|
|
+ );
|
|
|
+ NtQuerySystemInformation(SystemBasicInformation,&SysBaseInfo,sizeof(SysBaseInfo),NULL);
|
|
|
+ }
|
|
|
+
|
|
|
+ PROCNTQSI NtQuerySystemInformation;
|
|
|
+ PROCNTQIP NtQueryInformationProcess;
|
|
|
+
|
|
|
+ PROCNTGST pGetSystemTimes;
|
|
|
+ SYSTEM_BASIC_INFORMATION SysBaseInfo;
|
|
|
+
|
|
|
+} NtKernelFunctions;
|
|
|
+#endif
|
|
|
+
|
|
|
|
|
|
static class CMemoryUsageReporter: public Thread
|
|
|
{
|
|
@@ -1898,22 +1952,18 @@ static class CMemoryUsageReporter: public Thread
|
|
|
double dbIdleTime;
|
|
|
double dbSystemTime;
|
|
|
#ifdef _WIN32
|
|
|
- PROCNTQSI NtQuerySystemInformation;
|
|
|
- PROCNTQIP NtQueryInformationProcess;
|
|
|
- PROCNTGST pGetSystemTimes;
|
|
|
- SYSTEM_BASIC_INFORMATION SysBaseInfo;
|
|
|
LONG status;
|
|
|
LARGE_INTEGER liOldIdleTime;
|
|
|
LARGE_INTEGER liOldSystemTime;
|
|
|
#else
|
|
|
double OldIdleTime;
|
|
|
- double OldSystemTime;
|
|
|
+ double OldSystemTime;
|
|
|
CProcessMonitor procmon;
|
|
|
CExtendedStats extstats;
|
|
|
#endif
|
|
|
StringBuffer primaryfs;
|
|
|
StringBuffer secondaryfs;
|
|
|
- CriticalSection sect; // for getSystemTraceInfo
|
|
|
+ CriticalSection sect; // for getSystemTraceInfo
|
|
|
|
|
|
|
|
|
public:
|
|
@@ -1928,23 +1978,9 @@ public:
|
|
|
hook = _hook;
|
|
|
term = false;
|
|
|
latestCPU = 0;
|
|
|
-#ifdef _WIN32
|
|
|
+#ifdef _WIN32
|
|
|
memset(&liOldIdleTime,0,sizeof(liOldIdleTime));
|
|
|
memset(&liOldSystemTime,0,sizeof(liOldSystemTime));
|
|
|
- NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(
|
|
|
- GetModuleHandle("ntdll"),
|
|
|
- "NtQuerySystemInformation"
|
|
|
- );
|
|
|
- NtQueryInformationProcess = (PROCNTQIP)GetProcAddress(
|
|
|
- GetModuleHandle("ntdll"),
|
|
|
- "NtQueryInformationProcess"
|
|
|
- );
|
|
|
- // GetSystemTimes not available on earlier versions of Windows - NtQuerySystemInformation not consistent on later ones. So use GetSystemTimes if available
|
|
|
- pGetSystemTimes = (PROCNTGST)GetProcAddress(
|
|
|
- GetModuleHandle("kernel32"),
|
|
|
- "GetSystemTimes"
|
|
|
- );
|
|
|
- NtQuerySystemInformation(SystemBasicInformation,&SysBaseInfo,sizeof(SysBaseInfo),NULL);
|
|
|
dbIdleTime = 0;
|
|
|
primaryfs.append("C:");
|
|
|
#else
|
|
@@ -1979,9 +2015,9 @@ public:
|
|
|
{
|
|
|
CriticalBlock block(sect);
|
|
|
#ifdef _WIN32
|
|
|
- if (pGetSystemTimes) {
|
|
|
+ if (NtKernelFunctions.pGetSystemTimes) {
|
|
|
LARGE_INTEGER idle, kernel, user;
|
|
|
- pGetSystemTimes(&idle, &kernel, &user);
|
|
|
+ NtKernelFunctions.pGetSystemTimes(&idle, &kernel, &user);
|
|
|
// note - kernel time seems to include idle time
|
|
|
|
|
|
if(liOldIdleTime.QuadPart != 0) {
|
|
@@ -1998,8 +2034,8 @@ public:
|
|
|
} else {
|
|
|
SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
|
|
|
SYSTEM_TIME_INFORMATION SysTimeInfo;
|
|
|
- NtQuerySystemInformation(SystemTimeInformation,&SysTimeInfo,sizeof(SysTimeInfo),0);
|
|
|
- NtQuerySystemInformation(SystemPerformanceInformation,&SysPerfInfo,sizeof(SysPerfInfo),NULL);
|
|
|
+ NtKernelFunctions.NtQuerySystemInformation(SystemTimeInformation,&SysTimeInfo,sizeof(SysTimeInfo),0);
|
|
|
+ NtKernelFunctions.NtQuerySystemInformation(SystemPerformanceInformation,&SysPerfInfo,sizeof(SysPerfInfo),NULL);
|
|
|
|
|
|
if(liOldIdleTime.QuadPart != 0) {
|
|
|
// CurrentValue = NewValue - OldValue
|
|
@@ -2008,7 +2044,7 @@ public:
|
|
|
// CurrentCpuIdle = IdleTime / SystemTime
|
|
|
dbIdleTime = dbIdleTime / dbSystemTime;
|
|
|
// CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors
|
|
|
- latestCPU = (unsigned) (100.0 - dbIdleTime * 100.0 / (double)SysBaseInfo.bKeNumberProcessors + 0.5);
|
|
|
+ latestCPU = (unsigned) (100.0 - dbIdleTime * 100.0 / (double)NtKernelFunctions.SysBaseInfo.bKeNumberProcessors + 0.5);
|
|
|
}
|
|
|
liOldIdleTime = SysPerfInfo.liIdleTime;
|
|
|
liOldSystemTime = SysTimeInfo.liKeSystemTime;
|
|
@@ -2058,7 +2094,7 @@ public:
|
|
|
#if 0
|
|
|
VM_COUNTERS vmc;
|
|
|
DWORD dwSize = 0;
|
|
|
- NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), &dwSize);
|
|
|
+ NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), &dwSize);
|
|
|
str.appendf(" MU=%3u%%",(unsigned)((__int64)vmc.WorkingSetSize*100/(__int64)vmTotal));
|
|
|
#else
|
|
|
str.appendf(" MU=%3u%%",(unsigned)((__int64)vmInUse*100/(__int64)vmTotal));
|
|
@@ -2066,7 +2102,7 @@ public:
|
|
|
if (hook)
|
|
|
hook->extraLogging(str);
|
|
|
#ifdef _USE_MALLOC_HOOK
|
|
|
- if (totalMem)
|
|
|
+ if (totalMem)
|
|
|
str.appendf(" TM=%"I64F"d",totalMem);
|
|
|
#endif
|
|
|
|
|
@@ -2095,17 +2131,17 @@ public:
|
|
|
DWORD dwHandles;
|
|
|
|
|
|
dwSize = 0;
|
|
|
- NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), &dwSize);
|
|
|
+ NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), &dwSize);
|
|
|
dwHandles = 0;
|
|
|
dwSize = 0;
|
|
|
- NtQueryInformationProcess(GetCurrentProcess(), ProcessHandleCount, &dwHandles, sizeof(dwHandles), &dwSize);
|
|
|
+ NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessHandleCount, &dwHandles, sizeof(dwHandles), &dwSize);
|
|
|
dwSize = 0;
|
|
|
- NtQueryInformationProcess(GetCurrentProcess(), ProcessIoCounters, &ioc, sizeof(ioc), &dwSize);
|
|
|
+ NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessIoCounters, &ioc, sizeof(ioc), &dwSize);
|
|
|
dwSize = 0;
|
|
|
- NtQueryInformationProcess(GetCurrentProcess(), ProcessTimes, &kut, sizeof(kut), &dwSize);
|
|
|
+ NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessTimes, &kut, sizeof(kut), &dwSize);
|
|
|
dwSize = 0;
|
|
|
- NtQueryInformationProcess(GetCurrentProcess(), ProcessPooledUsageAndLimits, &put, sizeof(put), &dwSize);
|
|
|
-
|
|
|
+ NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessPooledUsageAndLimits, &put, sizeof(put), &dwSize);
|
|
|
+
|
|
|
str.appendf(" WS=%10u ",vmc.WorkingSetSize);
|
|
|
str.appendf("PP=%10u ",put.PagedPoolUsage);
|
|
|
str.appendf("NP=%10u ",put.NonPagedPoolUsage);
|
|
@@ -2140,7 +2176,7 @@ public:
|
|
|
latestCPU = 0;
|
|
|
}
|
|
|
#endif
|
|
|
-
|
|
|
+
|
|
|
|
|
|
unsigned __int64 primaryfsTotal = 0;
|
|
|
unsigned __int64 primaryfsInUse = 0;
|
|
@@ -2176,10 +2212,10 @@ public:
|
|
|
getMemUsage(mu,ma,mt,st,su);
|
|
|
memused = mu+su;
|
|
|
memtot = mt+st;
|
|
|
- }
|
|
|
+ }
|
|
|
hook->processPerfStats(latestCPU, memused, memtot, primaryfsInUse, primaryfsTotal, secondaryfsInUse, secondaryfsTotal, getThreadCount());
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if(mode & PerfMonPackets)
|
|
|
{
|
|
|
unsigned tx, rx;
|
|
@@ -2246,6 +2282,31 @@ public:
|
|
|
}
|
|
|
} *MemoryUsageReporter=NULL;
|
|
|
|
|
|
+
|
|
|
+static inline unsigned scaleFileTimeToMilli(unsigned __int64 nano100)
|
|
|
+{
|
|
|
+ return (unsigned)(nano100 / 10000);
|
|
|
+}
|
|
|
+
|
|
|
+void getProcessTime(UserSystemTime_t & result)
|
|
|
+{
|
|
|
+#ifdef _WIN32
|
|
|
+ LARGE_INTEGER startTime, exitTime, kernelTime, userTime;
|
|
|
+ if (GetProcessTimes(GetCurrentProcess(), (FILETIME *)&startTime, (FILETIME *)&exitTime, (FILETIME *)&kernelTime, (FILETIME *)&userTime))
|
|
|
+ {
|
|
|
+ result.user = scaleFileTimeToMilli(userTime.QuadPart);
|
|
|
+ result.system = scaleFileTimeToMilli(kernelTime.QuadPart);
|
|
|
+ }
|
|
|
+#else
|
|
|
+ UserStatusInfo info(GetCurrentProcessId());
|
|
|
+ if (info.update())
|
|
|
+ result = info.time;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
void getSystemTraceInfo(StringBuffer &str, PerfMonMode mode)
|
|
|
{
|
|
|
if (!MemoryUsageReporter)
|