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 _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 _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 _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 _WIN32 // Windows 95,98...
00386 #elif defined(linux) // Linux
00387 char buf[1024];
00388 sprintf(buf,"/proc/%ld/statm", processID(pid));
00389 long size, resident, share, trs, lrs, drs, dt;
00390 int fd = open(buf,O_RDONLY);
00391 read(fd, buf, sizeof(buf));
00392 close(fd);
00393 fd = sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld",
00394 &size, &resident, &share, &trs, &drs, &lrs, &dt);
00395 linux_proc prc;
00396 readProcStat( processID(pid), prc);
00397 vb->PeakVirtualSize = prc.vsize;
00398 vb->VirtualSize = prc.vsize;
00399 vb->PeakWorkingSetSize = resident * pg_size;
00400 vb->WorkingSetSize = resident * pg_size;
00401 vb->QuotaPeakPagedPoolUsage = share * pg_size;
00402 vb->QuotaPagedPoolUsage = share * pg_size;
00403 vb->QuotaNonPagedPoolUsage = (trs+drs)* pg_size;
00404 vb->QuotaPeakNonPagedPoolUsage = (trs+drs)* pg_size;
00405 vb->PageFaultCount = prc.majflt + prc.minflt;
00406 vb->PagefileUsage = prc.vsize-resident*pg_size;
00407 vb->PeakPagefileUsage = prc.vsize-resident*pg_size;
00408 #elif defined(__APPLE__)
00409 #else // All Other
00410 #endif // End ALL OS
00411 }
00412 if ( info ) *info = *vb;
00413 return status;
00414 }
00415
00416 long System::ProcessDescriptor::query(long pid,
00417 InfoType fetch,
00418 QUOTA_LIMITS* info) {
00419 long status = 1;
00420 ProcessHandle h(pid);
00421 QUOTA_LIMITS* vb = &m_QUOTA_LIMITS[h.item()];
00422 if ( fetch == Quota ) {
00423 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00424 status = NtApi::NtQueryInformationProcess(h.handle(),
00425 ProcessQuotaLimits,
00426 vb,
00427 sizeof(QUOTA_LIMITS),
00428 0);
00429 status = (status==0) ? 1 : 0;
00430 #elif _WIN32 // Windows 95,98...
00431 #elif defined(linux) // Linux
00432
00433
00434 rlimit lim;
00435 getrlimit(RLIMIT_DATA, &lim);
00436 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00437 vb->PagedPoolLimit = lim.rlim_max;
00438
00439 getrlimit(RLIMIT_STACK, &lim);
00440 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00441 vb->NonPagedPoolLimit = lim.rlim_max;
00442 vb->MinimumWorkingSetSize = 0;
00443
00444 getrlimit(RLIMIT_RSS, &lim);
00445 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00446 vb->MaximumWorkingSetSize = lim.rlim_max;
00447
00448 getrlimit(RLIMIT_AS, &lim);
00449 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00450 vb->PagefileLimit = lim.rlim_max;
00451
00452 getrlimit(RLIMIT_CPU, &lim);
00453 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00454 vb->TimeLimit = lim.rlim_max;
00455 #elif defined(__APPLE__)
00456 #else // All Other
00457 #endif // End ALL OS
00458 }
00459 if ( info ) *info = *vb;
00460 return status;
00461 }
00462
00463 long System::ProcessDescriptor::query(long pid,
00464 InfoType fetch,
00465 PROCESS_BASIC_INFORMATION* info) {
00466 long status = 1;
00467 ProcessHandle h(pid);
00468 PROCESS_BASIC_INFORMATION* vb = &m_PROCESS_BASIC_INFORMATION[h.item()];
00469 if ( fetch == ProcessBasics ) {
00470 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00471 status = NtApi::NtQueryInformationProcess(h.handle(),
00472 ProcessBasicInformation,
00473 vb,
00474 sizeof(PROCESS_BASIC_INFORMATION),
00475 0);
00476 status = (status==0) ? 1 : 0;
00477 #elif _WIN32 // Windows 95,98...
00478 #elif defined(linux) // Linux
00479 linux_proc prc;
00480 readProcStat( processID(pid), prc);
00481 vb->ExitStatus = 0;
00482 vb->PebBaseAddress = (PPEB)prc.startcode;
00483 vb->BasePriority = 2*15-prc.priority;
00484
00485
00486 vb->AffinityMask = prc.flags;
00487
00488
00489 vb->UniqueProcessId = processID(pid);
00490 vb->InheritedFromUniqueProcessId = prc.ppid;
00491 #else // All Other
00492 #endif // End ALL OS
00493 }
00494 if ( info ) *info = *vb;
00495 return status;
00496 }
00497
00498 long System::ProcessDescriptor::query(long pid,
00499 InfoType fetch,
00500 KERNEL_USER_TIMES* info) {
00501 long status = 1;
00502 ProcessHandle h(pid);
00503 KERNEL_USER_TIMES* tb = &m_KERNEL_USER_TIMES[h.item()];;
00504 if ( fetch == Times ) {
00505 #if defined(_WIN32) && WINVER>=0x0400 // Windows NT
00506 status = NtApi::NtQueryInformationProcess(h.handle(),
00507 ProcessTimes,
00508 tb,
00509 sizeof(KERNEL_USER_TIMES),
00510 0);
00511 status = (status==0) ? 1 : 0;
00512 #elif defined(_WIN32) // Windows 95,98...
00513 #elif defined(linux) // Linux
00514
00515
00516 tms tmsb;
00517 static longlong prc_start = 0;
00518
00519 static longlong offset = 100*longlong(time(0)) - longlong(times(&tmsb));
00520 if ( processID(pid) == s_myPid && prc_start == 0 ) {
00521 linux_proc prc;
00522 readProcStat( processID(pid), prc);
00523 prc_start = prc.starttime+offset;
00524 }
00525
00526 if ( processID(pid) == s_myPid ) {
00527 struct rusage r;
00528 getrusage( RUSAGE_SELF, &r );
00529 const double utime = static_cast<double>(r.ru_utime.tv_sec )*1e6 +
00530 static_cast<double>(r.ru_utime.tv_usec);
00531 const double stime = static_cast<double>(r.ru_stime.tv_sec )*1e6 +
00532 static_cast<double>(r.ru_stime.tv_usec);
00533 tb->UserTime = static_cast<longlong>( utime * 10. );
00534 tb->KernelTime = static_cast<longlong>( stime * 10. );
00535 tb->CreateTime = prc_start;
00536 }
00537 else {
00538 linux_proc prc;
00539 readProcStat( processID(pid), prc );
00540
00541 tms t;
00542 times(&t);
00543 tb->UserTime = t.tms_utime * TICK_TO_100NSEC;
00544 tb->KernelTime = t.tms_stime * TICK_TO_100NSEC;
00545 tb->CreateTime = (prc.starttime+offset);
00546 }
00547 tb->CreateTime *= TICK_TO_100NSEC;
00548 tb->ExitTime = 0;
00549
00550 status = 1;
00551
00552 #elif defined(__APPLE__)
00553
00554
00555 #else // no /proc file system: assume sys_start for the first call
00556 tms tmsb;
00557 static clock_t sys_start = times(0);
00558 static longlong offset = 100*longlong(time(0)) - sys_start;
00559 clock_t now = times(&tmsb);
00560 tb->CreateTime = offset + now;
00561 tb->UserTime = tmsb.tms_utime;
00562 tb->KernelTime = tmsb.tms_stime;
00563 tb->CreateTime *= TICK_TO_100NSEC;
00564 tb->UserTime *= TICK_TO_100NSEC;
00565 tb->KernelTime *= TICK_TO_100NSEC;
00566 tb->ExitTime = 0;
00567 status = 1;
00568 #endif
00569 }
00570 if ( info ) *info = *tb;
00571 return status;
00572 }