![]() |
|
|
Generated: 8 Jan 2009 |
00001 // $Header: /tmp/svngaudi/tmp.jEpFh25751/Gaudi/GaudiKernel/src/Lib/ProcessDescriptor.cpp,v 1.16 2007/11/21 13:04:53 marcocle Exp $ 00002 //==================================================================== 00003 // ProcStat.cpp 00004 //-------------------------------------------------------------------- 00005 // 00006 // Package : System (The LHCb System service) 00007 // 00008 // Description: Invoke interactively the ProcStat from a 00009 // running application 00010 // 00011 // Author : M.Frank 00012 // Created : 13/11/00 00013 // Changes : 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, // Note: this is kernel mode only 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 //__declspec(dllimport) long __stdcall NtQueryInformationProcess( 00059 // typedef __declspec(dllimport) long __stdcall (*__NtQueryInformationProcess)( 00060 // extern "C" long __cdecl NtQueryInformationProcess( 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; // %d 00096 char comm[400]; // %s 00097 char state; // %c 00098 int ppid; // %d 00099 int pgrp; // %d 00100 int session; // %d 00101 int tty; // %d 00102 int tpgid; // %d 00103 unsigned int flags; // %u 00104 unsigned int minflt; // %u 00105 unsigned int cminflt; // %u 00106 unsigned int majflt; // %u 00107 unsigned int cmajflt; // %u 00108 int utime; // %d 00109 int stime; // %d 00110 int cutime; // %d 00111 int cstime; // %d 00112 int counter; // %d 00113 int priority; // %d 00114 unsigned int timeout; // %u 00115 unsigned int itrealvalue; // %u 00116 int starttime; // %d 00117 unsigned int vsize; // %u 00118 unsigned int rss; // %u 00119 unsigned int rlim; // %u 00120 unsigned long startcode; // %u 00121 unsigned long endcode; // %u 00122 unsigned int startstack; // %u 00123 unsigned int kstkesp; // %u 00124 unsigned int kstkeip; // %u 00125 int signal; // %d 00126 int blocked; // %d 00127 int sigignore; // %d 00128 int sigcatch; // %d 00129 unsigned int wchan; // %u 00130 }; 00131 00132 #ifdef __APPLE__ 00133 // static long pg_size = 0; 00134 #else 00135 static long pg_size = sysconf(_SC_PAGESIZE); // getpagesize(); 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, // %d 00162 pinfo.comm, // %s 00163 &pinfo.state, // %c 00164 &pinfo.ppid, // %d 00165 &pinfo.pgrp, // %d 00166 &pinfo.session, // %d 00167 &pinfo.tty, // %d 00168 &pinfo.tpgid, // %d 00169 &pinfo.flags, // %u 00170 &pinfo.minflt, // %u 00171 &pinfo.cminflt, // %u 00172 &pinfo.majflt, // %u 00173 &pinfo.cmajflt, // %u 00174 &pinfo.utime, // %d 00175 &pinfo.stime, // %d 00176 &pinfo.cutime, // %d 00177 &pinfo.cstime, // %d 00178 &pinfo.counter, // %d 00179 &pinfo.priority, // %d 00180 &pinfo.timeout, // %u 00181 &pinfo.itrealvalue, // %u 00182 &pinfo.starttime, // %d 00183 &pinfo.vsize, // %u 00184 &pinfo.rss, // %u 00185 &pinfo.rlim, // %u 00186 &pinfo.startcode, // %l 00187 &pinfo.endcode, // %l 00188 &pinfo.startstack, // %u 00189 &pinfo.kstkesp, // %u 00190 &pinfo.kstkeip, // %u 00191 &pinfo.signal, // %d 00192 &pinfo.blocked, // %d 00193 &pinfo.sigignore, // %d 00194 &pinfo.sigcatch, // %d 00195 &pinfo.wchan // %u 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 // Framework include files 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 //rusage usage; 00313 //getrusage(RUSAGE_SELF, &usage); 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 // Not applicable 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;// drs = data/stack size 00404 vb->QuotaPeakNonPagedPoolUsage = (trs+drs)* pg_size;// trs = VmExe 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 // On linux all this stuff typically is not set 00433 // (ie. rlim_max=RLIM_INFINITY...) 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 // std::cout << "Base Priority=" << vb->BasePriority << "|" 00485 // << prc.priority << std::endl; 00486 vb->AffinityMask = prc.flags; 00487 // std::cout << "Flags =" << vb->AffinityMask << "|" 00488 // << prc.flags << std::endl; 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 // prc.startup is in ticks since system start : 00515 // need to offset for absolute time 00516 tms tmsb; 00517 static longlong prc_start = 0; 00518 // static longlong offset = 100*longlong(time(0)) - longlong(times(0)); 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 // FIXME (MCl): Make an alternative function get timing on OSX 00554 // times() seems to cause a segmentation fault 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 }