Gaudi Framework, version v22r1

Home   Generated: Mon Feb 28 2011

ProcessDescriptor.cpp

Go to the documentation of this file.
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 // In order to properly support e.g. fork() calls, we cannot keep a copy of the pid!
00204 #define s_myPid (::getpid())
00205 static inline long processID(long pid) {
00206   long thePid = (pid>0) ? pid : s_myPid;
00207   return thePid;
00208 }
00209 
00210 // Framework include files
00211 #include "ProcessDescriptor.h"
00212 #include "GaudiKernel/ModuleInfo.h"
00213 #include "GaudiKernel/System.h"
00214 
00215 System::ProcessDescriptor* System::getProcess()   {
00216   static ProcessDescriptor p;
00217 #ifdef _WIN32
00218   static bool first = true;
00219   if ( first )    {
00220     first = false;
00221     void* mh = ::LoadLibrary("NTDll.dll");
00222     if ( mh )  {
00223       NtApi::NtQueryInformationProcess = (NtApi::__NtQueryInformationProcess)
00224         ::GetProcAddress((HINSTANCE)mh, "NtQueryInformationProcess");
00225     }
00226   }
00227 #endif
00228   return &p;
00229 }
00230 
00231 System::ProcessDescriptor::ProcessHandle::ProcessHandle(long pid)   {
00232   if ( pid > 0 )    {
00233     if ( pid != s_myPid )    {
00234 #ifdef _WIN32
00235       m_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,
00236                                pid);
00237 #else
00238       m_handle = (void*)s_myPid;
00239 #endif
00240       m_needRelease = true;
00241       return;
00242     }
00243   }
00244   m_handle = processHandle();
00245   m_needRelease = false;
00246 }
00247 
00248 System::ProcessDescriptor::ProcessHandle::~ProcessHandle()   {
00249   if ( m_needRelease )    {
00250 #ifdef _WIN32
00251     ::CloseHandle(m_handle);
00252 #else
00253       m_handle = 0;
00254 #endif
00255   }
00256 }
00257 
00258 System::ProcessDescriptor::ProcessDescriptor()
00259 {
00260 }
00261 
00262 System::ProcessDescriptor::~ProcessDescriptor()   {
00263 }
00264 
00265 long System::ProcessDescriptor::query(long pid,
00266                                       InfoType fetch,
00267                                       IO_COUNTERS* info) {
00268   long status = 1;
00269   ProcessHandle h(pid);
00270   IO_COUNTERS* vb = &m_IO_COUNTERS[h.item()];
00271   if ( fetch == IO )   {
00272 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
00273     status = NtApi::NtQueryInformationProcess(h.handle(),
00274                                               ProcessIoCounters,
00275                                               vb,
00276                                               sizeof(IO_COUNTERS),
00277                                               0);
00278     status = (status==0) ? 1 : 0;
00279 #elif defined(_WIN32)                     // Windows 95,98...
00280 #elif defined(linux)
00281     linux_proc prc;
00282     readProcStat(processID(pid), prc);
00283     rusage usage;
00284     getrusage(RUSAGE_SELF, &usage);
00285     vb->ReadOperationCount    = usage.ru_inblock;
00286     vb->WriteOperationCount   = usage.ru_oublock;
00287     vb->OtherOperationCount   = 0;
00288     vb->ReadTransferCount     = usage.ru_inblock;
00289     vb->WriteTransferCount    = usage.ru_oublock;
00290     vb->OtherTransferCount    = 0;
00291 #else                                     // All Other
00292 #endif                                    // End ALL OS
00293   }
00294   if ( info ) *info = *vb;
00295   return status;
00296 }
00297 
00298 long System::ProcessDescriptor::query(long pid,
00299                                       InfoType fetch,
00300                                       POOLED_USAGE_AND_LIMITS* info)    {
00301   long status = 1;
00302   ProcessHandle h(pid);
00303   POOLED_USAGE_AND_LIMITS* vb = &m_POOLED_USAGE_AND_LIMITS[h.item()];
00304   if ( fetch == Quota )   {
00305 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
00306     status = NtApi::NtQueryInformationProcess(h.handle(),
00307                                               ProcessPooledUsageAndLimits,
00308                                               vb,
00309                                               sizeof(POOLED_USAGE_AND_LIMITS),
00310                                               0);
00311     status = (status==0) ? 1 : 0;
00312 #elif defined(_WIN32)                     // Windows 95,98...
00313 #elif defined(linux)                      // Linux
00314     //rusage usage;
00315     //getrusage(RUSAGE_SELF, &usage);
00316     rlimit lim;
00317 
00318     getrlimit(RLIMIT_DATA, &lim);
00319     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00320     vb->PeakPagedPoolUsage = lim.rlim_cur;
00321     vb->PagedPoolUsage     = lim.rlim_cur;
00322     vb->PagedPoolLimit     = lim.rlim_max;
00323 
00324     getrlimit(RLIMIT_STACK, &lim);
00325     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00326     vb->PeakNonPagedPoolUsage = lim.rlim_cur;
00327     vb->NonPagedPoolUsage     = lim.rlim_cur;
00328     vb->NonPagedPoolLimit     = lim.rlim_max;
00329 
00330     linux_proc prc;
00331     readProcStat(processID(pid), prc);
00332     vb->PeakPagefileUsage     = prc.rss * pg_size;
00333     vb->PagefileUsage         = prc.rss * pg_size;
00334     vb->PagefileLimit         = 0xFFFFFFFF;
00335 #elif defined(__APPLE__)
00336 #else                                     // All Other
00337 #endif                                    // End ALL OS
00338   }
00339   if ( info ) *info = *vb;
00340   return status;
00341 }
00342 
00343 long System::ProcessDescriptor::query(long pid, InfoType fetch, long* info)    {
00344   long status = 1, *vb = &status;
00345   ProcessHandle h(pid);
00346   vb = &m_PRIORITYBOOST[h.item()];
00347   *vb = 0;
00348   switch ( fetch )    {
00349   case PriorityBoost:
00350 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
00351     status = NtApi::NtQueryInformationProcess(h.handle(),
00352                                               ProcessPriorityBoost,
00353                                               vb,
00354                                               sizeof(long),
00355                                               0);
00356 #elif defined(_WIN32)                     // Windows 95,98...
00357 #else
00358     // Not applicable
00359     status = 0;
00360     *vb = 0;
00361 #endif                                    // End ALL OS
00362     status = (status==0) ? 1 : 0;
00363     break;
00364   default:
00365     status = -1;
00366     vb = &status;
00367     break;
00368   }
00369   if ( info ) *info = *vb;
00370   return status;
00371 }
00372 
00373 long System::ProcessDescriptor::query(long pid,
00374                                       InfoType fetch,
00375                                       VM_COUNTERS* info)    {
00376   long status = 1;
00377   ProcessHandle h(pid);
00378   VM_COUNTERS* vb = &m_VM_COUNTERS[h.item()];
00379   if ( fetch == Memory )   {
00380 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
00381     status = NtApi::NtQueryInformationProcess(h.handle(),
00382                                               ProcessVmCounters,
00383                                               vb,
00384                                               sizeof(VM_COUNTERS),
00385                                               0);
00386     status = (status==0) ? 1 : 0;
00387 #elif defined(_WIN32)                     // Windows 95,98...
00388 #elif defined(linux)                      // Linux
00389     const ssize_t bufsize = 1024;
00390     char buf[bufsize];
00391     sprintf(buf,"/proc/%ld/statm", processID(pid));
00392     long size, resident, share, trs, lrs, drs, dt;
00393     int fd = open(buf,O_RDONLY);
00394     ssize_t nread = read(fd, buf, bufsize);
00395     close(fd);
00396     if ( nread < bufsize && nread >= 0 )
00397       buf[nread]='\0';
00398     fd = sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld",
00399                      &size, &resident, &share, &trs, &drs, &lrs, &dt);
00400     linux_proc prc;
00401     readProcStat( processID(pid), prc);
00402     vb->PeakVirtualSize            = prc.vsize;
00403     vb->VirtualSize                = prc.vsize;
00404     vb->PeakWorkingSetSize         = resident * pg_size;
00405     vb->WorkingSetSize             = resident * pg_size;
00406     vb->QuotaPeakPagedPoolUsage    = share    * pg_size;
00407     vb->QuotaPagedPoolUsage        = share    * pg_size;
00408     vb->QuotaNonPagedPoolUsage     = (trs+drs)* pg_size;// drs = data/stack size
00409     vb->QuotaPeakNonPagedPoolUsage = (trs+drs)* pg_size;// trs = VmExe size
00410     vb->PageFaultCount             = prc.majflt + prc.minflt;
00411     vb->PagefileUsage              = prc.vsize-resident*pg_size;
00412     vb->PeakPagefileUsage          = prc.vsize-resident*pg_size;
00413 #elif defined(__APPLE__)
00414 #else                                     // All Other
00415 #endif                                    // End ALL OS
00416   }
00417   if ( info ) *info = *vb;
00418   return status;
00419 }
00420 
00421 long System::ProcessDescriptor::query(long pid,
00422                                       InfoType fetch,
00423                                       QUOTA_LIMITS* info)    {
00424   long status = 1;
00425   ProcessHandle h(pid);
00426   QUOTA_LIMITS* vb = &m_QUOTA_LIMITS[h.item()];
00427   if ( fetch == Quota )   {
00428 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
00429     status = NtApi::NtQueryInformationProcess(h.handle(),
00430                                               ProcessQuotaLimits,
00431                                               vb,
00432                                               sizeof(QUOTA_LIMITS),
00433                                               0);
00434     status = (status==0) ? 1 : 0;
00435 #elif defined(_WIN32)                     // Windows 95,98...
00436 #elif defined(linux)                      // Linux
00437     // On linux all this stuff typically is not set
00438     // (ie. rlim_max=RLIM_INFINITY...)
00439     rlimit lim;
00440     getrlimit(RLIMIT_DATA, &lim);
00441     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00442     vb->PagedPoolLimit        = lim.rlim_max;
00443 
00444     getrlimit(RLIMIT_STACK, &lim);
00445     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00446     vb->NonPagedPoolLimit     = lim.rlim_max;
00447     vb->MinimumWorkingSetSize = 0;
00448 
00449     getrlimit(RLIMIT_RSS, &lim);
00450     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00451     vb->MaximumWorkingSetSize = lim.rlim_max;
00452 
00453     getrlimit(RLIMIT_AS, &lim);
00454     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00455     vb->PagefileLimit         = lim.rlim_max;
00456 
00457     getrlimit(RLIMIT_CPU, &lim);
00458     if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
00459     vb->TimeLimit             = lim.rlim_max;
00460 #elif defined(__APPLE__)
00461 #else                                     // All Other
00462 #endif                                    // End ALL OS
00463   }
00464   if ( info ) *info = *vb;
00465   return status;
00466 }
00467 
00468 long System::ProcessDescriptor::query(long pid,
00469                                       InfoType fetch,
00470                                       PROCESS_BASIC_INFORMATION* info)    {
00471   long status = 1;
00472   ProcessHandle h(pid);
00473   PROCESS_BASIC_INFORMATION* vb = &m_PROCESS_BASIC_INFORMATION[h.item()];
00474   if ( fetch == ProcessBasics )   {
00475 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
00476     status = NtApi::NtQueryInformationProcess(h.handle(),
00477                                               ProcessBasicInformation,
00478                                               vb,
00479                                               sizeof(PROCESS_BASIC_INFORMATION),
00480                                               0);
00481     status = (status==0) ? 1 : 0;
00482 #elif defined(_WIN32)                     // Windows 95,98...
00483 #elif defined(linux)                      // Linux
00484     linux_proc prc;
00485     readProcStat( processID(pid), prc);
00486     vb->ExitStatus                   = 0;
00487     vb->PebBaseAddress               = (PPEB)prc.startcode;
00488     vb->BasePriority                 = 2*15-prc.priority;
00489     // std::cout << "Base Priority=" << vb->BasePriority << "|"
00490     // << prc.priority << std::endl;
00491     vb->AffinityMask                 = prc.flags;
00492     // std::cout << "Flags        =" << vb->AffinityMask << "|"
00493     // << prc.flags << std::endl;
00494     vb->UniqueProcessId              = processID(pid);
00495     vb->InheritedFromUniqueProcessId = prc.ppid;
00496 #else                                     // All Other
00497 #endif                                    // End ALL OS
00498   }
00499   if ( info ) *info = *vb;
00500   return status;
00501 }
00502 
00503 long System::ProcessDescriptor::query(long pid,
00504                                       InfoType fetch,
00505                                       KERNEL_USER_TIMES* info)   {
00506   long status = 1;
00507   ProcessHandle h(pid);
00508   KERNEL_USER_TIMES* tb = &m_KERNEL_USER_TIMES[h.item()];;
00509   if ( fetch == Times )   {
00510 #if defined(_WIN32) && WINVER>=0x0400     // Windows NT
00511     status = NtApi::NtQueryInformationProcess(h.handle(),
00512                                               ProcessTimes,
00513                                               tb,
00514                                               sizeof(KERNEL_USER_TIMES),
00515                                               0);
00516     status = (status==0) ? 1 : 0;
00517 #elif defined(_WIN32)                     // Windows 95,98...
00518 #elif defined(linux)                      // Linux
00519     // prc.startup is in ticks since system start :
00520     // need to offset for absolute time
00521     tms tmsb;
00522     static longlong prc_start = 0;
00523     //    static longlong offset = 100*longlong(time(0)) - longlong(times(0));
00524     static longlong offset = 100*longlong(time(0)) - longlong(times(&tmsb));
00525     if ( processID(pid) == s_myPid && prc_start == 0 ) {
00526       linux_proc prc;
00527       readProcStat( processID(pid), prc);
00528       prc_start = prc.starttime+offset;
00529     }
00530 
00531     if ( processID(pid) == s_myPid ) {
00532       struct rusage r;
00533       getrusage( RUSAGE_SELF, &r );
00534       tb->UserTime   = (static_cast<long long>(r.ru_utime.tv_sec) * 1000000 +
00535                         r.ru_utime.tv_usec) * 10;
00536       tb->KernelTime = (static_cast<long long>(r.ru_stime.tv_sec) * 1000000 +
00537                         r.ru_stime.tv_usec) * 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     // FIXME (MCl): Make an alternative function get timing on OSX
00557     // times() seems to cause a segmentation fault 
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Mon Feb 28 2011 18:27:14 for Gaudi Framework, version v22r1 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004