00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #define GAUDIKERNEL_PROCSTAT_CPP
00017
00018 static const long TICK_TO_100NSEC = 100000;
00019
00020 namespace System {
00021 enum ProcessInfoCommand {
00022 ProcessBasicInformation,
00023 ProcessQuotaLimits,
00024 ProcessIoCounters,
00025 ProcessVmCounters,
00026 ProcessTimes,
00027 ProcessBasePriority,
00028 ProcessRaisePriority,
00029 ProcessDebugPort,
00030 ProcessExceptionPort,
00031 ProcessAccessToken,
00032 ProcessLdtInformation,
00033 ProcessLdtSize,
00034 ProcessDefaultHardErrorMode,
00035 ProcessIoPortHandlers,
00036 ProcessPooledUsageAndLimits,
00037 ProcessWorkingSetWatch,
00038 ProcessUserModeIOPL,
00039 ProcessEnableAlignmentFaultFixup,
00040 ProcessPriorityClass,
00041 ProcessWx86Information,
00042 ProcessHandleCount,
00043 ProcessAffinityMask,
00044 ProcessPriorityBoost,
00045 MaxProcessInfoClass,
00046 ProcessEllapsedTime
00047 };
00048 }
00049 #ifdef _WIN32
00050 # define strcasecmp _stricmp
00051 # define strncasecmp _strnicmp
00052 #define NOMSG
00053 #define NOGDI
00054 #include "process.h"
00055 #include "windows.h"
00056 #define getpid _getpid
00057 namespace NtApi {
00058
00059
00060
00061
00062 typedef long (WINAPI *__NtQueryInformationProcess)(
00063
00064 void* ProcessHandle,
00065 long ProcessInformationClass,
00066 void* ProcessInformation,
00067 unsigned long ProcessInformationLength,
00068 unsigned long* ReturnLength
00069 );
00070 __NtQueryInformationProcess NtQueryInformationProcess;
00071 };
00072 #else // UNIX...: first the EGCS stuff, then the OS dependent includes
00073 #define WINVER 0
00074 #include <errno.h>
00075 #include <string>
00076 #include "unistd.h"
00077 #include "libgen.h"
00078 #include <cstdio>
00079 #include <unistd.h>
00080 #include <sstream>
00081 #include <iostream>
00082 #include <fcntl.h>
00083 #include "sys/times.h"
00084 #include <sys/types.h>
00085 #include <sys/signal.h>
00086 #include <sys/syscall.h>
00087 #ifndef __APPLE__
00088 #include <sys/procfs.h>
00089 #endif
00090 #include <sys/time.h>
00091 #include <sys/resource.h>
00092 #include <cstdio>
00093
00094 struct linux_proc {
00095 int pid;
00096 char comm[400];
00097 char state;
00098 int ppid;
00099 int pgrp;
00100 int session;
00101 int tty;
00102 int tpgid;
00103 unsigned int flags;
00104 unsigned int minflt;
00105 unsigned int cminflt;
00106 unsigned int majflt;
00107 unsigned int cmajflt;
00108 int utime;
00109 int stime;
00110 int cutime;
00111 int cstime;
00112 int counter;
00113 int priority;
00114 unsigned int timeout;
00115 unsigned int itrealvalue;
00116 int starttime;
00117 unsigned int vsize;
00118 unsigned int rss;
00119 unsigned int rlim;
00120 unsigned long startcode;
00121 unsigned long endcode;
00122 unsigned int startstack;
00123 unsigned int kstkesp;
00124 unsigned int kstkeip;
00125 int signal;
00126 int blocked;
00127 int sigignore;
00128 int sigcatch;
00129 unsigned int wchan;
00130 };
00131
00132 #ifdef __APPLE__
00133
00134 #else
00135 static long pg_size = sysconf(_SC_PAGESIZE);
00136 #endif
00137 void readProcStat(long pid, linux_proc& pinfo) {
00138
00139 int cnt, fd;
00140 char buf[512];
00141
00142 std::ostringstream ost;
00143
00144 ost << "/proc/" << pid << "/stat";
00145 std::string fname = ost.str();
00146 if((fd=open(fname.c_str(),O_RDONLY))<0) {
00147 std::cerr << "Failed to open " << ost.str() << std::endl;
00148 return;
00149 }
00150
00151 lseek(fd,0,SEEK_SET);
00152 if((cnt=read(fd,buf,sizeof(buf)))<0) {
00153 std::cout << "LINUX Read of Proc file failed:" << std::endl;
00154 return;
00155 }
00156
00157 if(cnt>0) {
00158 buf[cnt]='\0';
00159 sscanf(buf,
00160 "%d %s %c %d %d %d %d %d %u %u %u %u %u %d %d %d %d %d %d %u %u %d %u %u %u %lu %lu %u %u %u %d %d %d %d %u",
00161 &pinfo.pid,
00162 pinfo.comm,
00163 &pinfo.state,
00164 &pinfo.ppid,
00165 &pinfo.pgrp,
00166 &pinfo.session,
00167 &pinfo.tty,
00168 &pinfo.tpgid,
00169 &pinfo.flags,
00170 &pinfo.minflt,
00171 &pinfo.cminflt,
00172 &pinfo.majflt,
00173 &pinfo.cmajflt,
00174 &pinfo.utime,
00175 &pinfo.stime,
00176 &pinfo.cutime,
00177 &pinfo.cstime,
00178 &pinfo.counter,
00179 &pinfo.priority,
00180 &pinfo.timeout,
00181 &pinfo.itrealvalue,
00182 &pinfo.starttime,
00183 &pinfo.vsize,
00184 &pinfo.rss,
00185 &pinfo.rlim,
00186 &pinfo.startcode,
00187 &pinfo.endcode,
00188 &pinfo.startstack,
00189 &pinfo.kstkesp,
00190 &pinfo.kstkeip,
00191 &pinfo.signal,
00192 &pinfo.blocked,
00193 &pinfo.sigignore,
00194 &pinfo.sigcatch,
00195 &pinfo.wchan
00196 );
00197 }
00198 close(fd);
00199 }
00200 #endif
00201
00202 static long s_myPid = ::getpid();
00203 static inline long processID(long pid) {
00204 long thePid = (pid>0) ? pid : s_myPid;
00205 return thePid;
00206 }
00207
00208
00209 #include "ProcessDescriptor.h"
00210 #include "GaudiKernel/ModuleInfo.h"
00211 #include "GaudiKernel/System.h"
00212
00213 System::ProcessDescriptor* System::getProcess() {
00214 static ProcessDescriptor p;
00215 #ifdef _WIN32
00216 static bool first = true;
00217 if ( first ) {
00218 first = false;
00219 void* mh = ::LoadLibrary("NTDll.dll");
00220 if ( mh ) {
00221 NtApi::NtQueryInformationProcess = (NtApi::__NtQueryInformationProcess)
00222 ::GetProcAddress((HINSTANCE)mh, "NtQueryInformationProcess");
00223 }
00224 }
00225 #endif
00226 return &p;
00227 }
00228
00229 System::ProcessDescriptor::ProcessHandle::ProcessHandle(long pid) {
00230 if ( pid > 0 ) {
00231 if ( pid != s_myPid ) {
00232 #ifdef _WIN32
00233 m_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,
00234 pid);
00235 #else
00236 m_handle = (void*)s_myPid;
00237 #endif
00238 m_needRelease = true;
00239 return;
00240 }
00241 }
00242 m_handle = processHandle();
00243 m_needRelease = false;
00244 }
00245
00246 System::ProcessDescriptor::ProcessHandle::~ProcessHandle() {
00247 if ( m_needRelease ) {
00248 #ifdef _WIN32
00249 ::CloseHandle(m_handle);
00250 #else
00251 m_handle = 0;
00252 #endif
00253 }
00254 }
00255
00256 System::ProcessDescriptor::ProcessDescriptor()
00257 {
00258 }
00259
00260 System::ProcessDescriptor::~ProcessDescriptor() {
00261 }
00262
00263 long System::ProcessDescriptor::query(long pid,
00264 InfoType fetch,
00265 IO_COUNTERS* info) {
00266 long status = 1;
00267 ProcessHandle h(pid);
00268 IO_COUNTERS* vb = &m_IO_COUNTERS[h.item()];
00269 if ( fetch == IO ) {
00270 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00271 status = NtApi::NtQueryInformationProcess(h.handle(),
00272 ProcessIoCounters,
00273 vb,
00274 sizeof(IO_COUNTERS),
00275 0);
00276 status = (status==0) ? 1 : 0;
00277 #elif defined(_WIN32) // Windows 95,98...
00278 #elif defined(linux)
00279 linux_proc prc;
00280 readProcStat(processID(pid), prc);
00281 rusage usage;
00282 getrusage(RUSAGE_SELF, &usage);
00283 vb->ReadOperationCount = usage.ru_inblock;
00284 vb->WriteOperationCount = usage.ru_oublock;
00285 vb->OtherOperationCount = 0;
00286 vb->ReadTransferCount = usage.ru_inblock;
00287 vb->WriteTransferCount = usage.ru_oublock;
00288 vb->OtherTransferCount = 0;
00289 #else // All Other
00290 #endif // End ALL OS
00291 }
00292 if ( info ) *info = *vb;
00293 return status;
00294 }
00295
00296 long System::ProcessDescriptor::query(long pid,
00297 InfoType fetch,
00298 POOLED_USAGE_AND_LIMITS* info) {
00299 long status = 1;
00300 ProcessHandle h(pid);
00301 POOLED_USAGE_AND_LIMITS* vb = &m_POOLED_USAGE_AND_LIMITS[h.item()];
00302 if ( fetch == Quota ) {
00303 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00304 status = NtApi::NtQueryInformationProcess(h.handle(),
00305 ProcessPooledUsageAndLimits,
00306 vb,
00307 sizeof(POOLED_USAGE_AND_LIMITS),
00308 0);
00309 status = (status==0) ? 1 : 0;
00310 #elif defined(_WIN32) // Windows 95,98...
00311 #elif defined(linux) // Linux
00312
00313
00314 rlimit lim;
00315
00316 getrlimit(RLIMIT_DATA, &lim);
00317 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00318 vb->PeakPagedPoolUsage = lim.rlim_cur;
00319 vb->PagedPoolUsage = lim.rlim_cur;
00320 vb->PagedPoolLimit = lim.rlim_max;
00321
00322 getrlimit(RLIMIT_STACK, &lim);
00323 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00324 vb->PeakNonPagedPoolUsage = lim.rlim_cur;
00325 vb->NonPagedPoolUsage = lim.rlim_cur;
00326 vb->NonPagedPoolLimit = lim.rlim_max;
00327
00328 linux_proc prc;
00329 readProcStat(processID(pid), prc);
00330 vb->PeakPagefileUsage = prc.rss * pg_size;
00331 vb->PagefileUsage = prc.rss * pg_size;
00332 vb->PagefileLimit = 0xFFFFFFFF;
00333 #elif defined(__APPLE__)
00334 #else // All Other
00335 #endif // End ALL OS
00336 }
00337 if ( info ) *info = *vb;
00338 return status;
00339 }
00340
00341 long System::ProcessDescriptor::query(long pid, InfoType fetch, long* info) {
00342 long status = 1, *vb = &status;
00343 ProcessHandle h(pid);
00344 vb = &m_PRIORITYBOOST[h.item()];
00345 *vb = 0;
00346 switch ( fetch ) {
00347 case PriorityBoost:
00348 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00349 status = NtApi::NtQueryInformationProcess(h.handle(),
00350 ProcessPriorityBoost,
00351 vb,
00352 sizeof(long),
00353 0);
00354 #elif defined(_WIN32) // Windows 95,98...
00355 #else
00356
00357 status = 0;
00358 *vb = 0;
00359 #endif // End ALL OS
00360 status = (status==0) ? 1 : 0;
00361 break;
00362 default:
00363 status = -1;
00364 vb = &status;
00365 break;
00366 }
00367 if ( info ) *info = *vb;
00368 return status;
00369 }
00370
00371 long System::ProcessDescriptor::query(long pid,
00372 InfoType fetch,
00373 VM_COUNTERS* info) {
00374 long status = 1;
00375 ProcessHandle h(pid);
00376 VM_COUNTERS* vb = &m_VM_COUNTERS[h.item()];
00377 if ( fetch == Memory ) {
00378 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00379 status = NtApi::NtQueryInformationProcess(h.handle(),
00380 ProcessVmCounters,
00381 vb,
00382 sizeof(VM_COUNTERS),
00383 0);
00384 status = (status==0) ? 1 : 0;
00385 #elif defined(_WIN32) // Windows 95,98...
00386 #elif defined(linux) // Linux
00387 const ssize_t bufsize = 1024;
00388 char buf[bufsize];
00389 sprintf(buf,"/proc/%ld/statm", processID(pid));
00390 long size, resident, share, trs, lrs, drs, dt;
00391 int fd = open(buf,O_RDONLY);
00392 ssize_t nread = read(fd, buf, bufsize);
00393 close(fd);
00394 if ( nread < bufsize && nread >= 0 )
00395 buf[nread]='\0';
00396 fd = sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld",
00397 &size, &resident, &share, &trs, &drs, &lrs, &dt);
00398 linux_proc prc;
00399 readProcStat( processID(pid), prc);
00400 vb->PeakVirtualSize = prc.vsize;
00401 vb->VirtualSize = prc.vsize;
00402 vb->PeakWorkingSetSize = resident * pg_size;
00403 vb->WorkingSetSize = resident * pg_size;
00404 vb->QuotaPeakPagedPoolUsage = share * pg_size;
00405 vb->QuotaPagedPoolUsage = share * pg_size;
00406 vb->QuotaNonPagedPoolUsage = (trs+drs)* pg_size;
00407 vb->QuotaPeakNonPagedPoolUsage = (trs+drs)* pg_size;
00408 vb->PageFaultCount = prc.majflt + prc.minflt;
00409 vb->PagefileUsage = prc.vsize-resident*pg_size;
00410 vb->PeakPagefileUsage = prc.vsize-resident*pg_size;
00411 #elif defined(__APPLE__)
00412 #else // All Other
00413 #endif // End ALL OS
00414 }
00415 if ( info ) *info = *vb;
00416 return status;
00417 }
00418
00419 long System::ProcessDescriptor::query(long pid,
00420 InfoType fetch,
00421 QUOTA_LIMITS* info) {
00422 long status = 1;
00423 ProcessHandle h(pid);
00424 QUOTA_LIMITS* vb = &m_QUOTA_LIMITS[h.item()];
00425 if ( fetch == Quota ) {
00426 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00427 status = NtApi::NtQueryInformationProcess(h.handle(),
00428 ProcessQuotaLimits,
00429 vb,
00430 sizeof(QUOTA_LIMITS),
00431 0);
00432 status = (status==0) ? 1 : 0;
00433 #elif defined(_WIN32) // Windows 95,98...
00434 #elif defined(linux) // Linux
00435
00436
00437 rlimit lim;
00438 getrlimit(RLIMIT_DATA, &lim);
00439 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00440 vb->PagedPoolLimit = lim.rlim_max;
00441
00442 getrlimit(RLIMIT_STACK, &lim);
00443 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00444 vb->NonPagedPoolLimit = lim.rlim_max;
00445 vb->MinimumWorkingSetSize = 0;
00446
00447 getrlimit(RLIMIT_RSS, &lim);
00448 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00449 vb->MaximumWorkingSetSize = lim.rlim_max;
00450
00451 getrlimit(RLIMIT_AS, &lim);
00452 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00453 vb->PagefileLimit = lim.rlim_max;
00454
00455 getrlimit(RLIMIT_CPU, &lim);
00456 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00457 vb->TimeLimit = lim.rlim_max;
00458 #elif defined(__APPLE__)
00459 #else // All Other
00460 #endif // End ALL OS
00461 }
00462 if ( info ) *info = *vb;
00463 return status;
00464 }
00465
00466 long System::ProcessDescriptor::query(long pid,
00467 InfoType fetch,
00468 PROCESS_BASIC_INFORMATION* info) {
00469 long status = 1;
00470 ProcessHandle h(pid);
00471 PROCESS_BASIC_INFORMATION* vb = &m_PROCESS_BASIC_INFORMATION[h.item()];
00472 if ( fetch == ProcessBasics ) {
00473 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00474 status = NtApi::NtQueryInformationProcess(h.handle(),
00475 ProcessBasicInformation,
00476 vb,
00477 sizeof(PROCESS_BASIC_INFORMATION),
00478 0);
00479 status = (status==0) ? 1 : 0;
00480 #elif defined(_WIN32) // Windows 95,98...
00481 #elif defined(linux) // Linux
00482 linux_proc prc;
00483 readProcStat( processID(pid), prc);
00484 vb->ExitStatus = 0;
00485 vb->PebBaseAddress = (PPEB)prc.startcode;
00486 vb->BasePriority = 2*15-prc.priority;
00487
00488
00489 vb->AffinityMask = prc.flags;
00490
00491
00492 vb->UniqueProcessId = processID(pid);
00493 vb->InheritedFromUniqueProcessId = prc.ppid;
00494 #else // All Other
00495 #endif // End ALL OS
00496 }
00497 if ( info ) *info = *vb;
00498 return status;
00499 }
00500
00501 long System::ProcessDescriptor::query(long pid,
00502 InfoType fetch,
00503 KERNEL_USER_TIMES* info) {
00504 long status = 1;
00505 ProcessHandle h(pid);
00506 KERNEL_USER_TIMES* tb = &m_KERNEL_USER_TIMES[h.item()];;
00507 if ( fetch == Times ) {
00508 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00509 status = NtApi::NtQueryInformationProcess(h.handle(),
00510 ProcessTimes,
00511 tb,
00512 sizeof(KERNEL_USER_TIMES),
00513 0);
00514 status = (status==0) ? 1 : 0;
00515 #elif defined(_WIN32) // Windows 95,98...
00516 #elif defined(linux) // Linux
00517
00518
00519 tms tmsb;
00520 static longlong prc_start = 0;
00521
00522 static longlong offset = 100*longlong(time(0)) - longlong(times(&tmsb));
00523 if ( processID(pid) == s_myPid && prc_start == 0 ) {
00524 linux_proc prc;
00525 readProcStat( processID(pid), prc);
00526 prc_start = prc.starttime+offset;
00527 }
00528
00529 if ( processID(pid) == s_myPid ) {
00530 struct rusage r;
00531 getrusage( RUSAGE_SELF, &r );
00532 const double utime = static_cast<double>(r.ru_utime.tv_sec )*1e6 +
00533 static_cast<double>(r.ru_utime.tv_usec);
00534 const double stime = static_cast<double>(r.ru_stime.tv_sec )*1e6 +
00535 static_cast<double>(r.ru_stime.tv_usec);
00536 tb->UserTime = static_cast<longlong>( utime * 10. );
00537 tb->KernelTime = static_cast<longlong>( stime * 10. );
00538 tb->CreateTime = prc_start;
00539 }
00540 else {
00541 linux_proc prc;
00542 readProcStat( processID(pid), prc );
00543
00544 tms t;
00545 times(&t);
00546 tb->UserTime = t.tms_utime * TICK_TO_100NSEC;
00547 tb->KernelTime = t.tms_stime * TICK_TO_100NSEC;
00548 tb->CreateTime = (prc.starttime+offset);
00549 }
00550 tb->CreateTime *= TICK_TO_100NSEC;
00551 tb->ExitTime = 0;
00552
00553 status = 1;
00554
00555 #elif defined(__APPLE__)
00556
00557
00558 #else // no /proc file system: assume sys_start for the first call
00559 tms tmsb;
00560 static clock_t sys_start = times(0);
00561 static longlong offset = 100*longlong(time(0)) - sys_start;
00562 clock_t now = times(&tmsb);
00563 tb->CreateTime = offset + now;
00564 tb->UserTime = tmsb.tms_utime;
00565 tb->KernelTime = tmsb.tms_stime;
00566 tb->CreateTime *= TICK_TO_100NSEC;
00567 tb->UserTime *= TICK_TO_100NSEC;
00568 tb->KernelTime *= TICK_TO_100NSEC;
00569 tb->ExitTime = 0;
00570 status = 1;
00571 #endif
00572 }
00573 if ( info ) *info = *tb;
00574 return status;
00575 }