Hi dear Perlers,
 
For a project, I modified the Win32::Job for retreiving Job statistics. The Win32::Job is really a great Perl class mapping Win32 Job features.
But developers also use Win32 job features no to only start a process & its child to track them but also for retrieving global statistics on them.
But in the current version of Win32::Job, only some minor details are returned like ONLY parent process exitcode, memory/cpu time.
 
Because sometimes, you need global statistics on a parent process & ALL ITS childs, I modified it.
 
So my first question is :
according to other participants of my project, Do know where & how can I propose my enhancement to be taken in account in standard ActiveState Perl Distributions ?
 
Thx in advance,
Louis
 
 
For those who are interrested here is a a here is now an example of the result stat returned from Job->Stats() :
 
%stat = (
  'Job' => {
    'LimitInfo' => {
      'PeakJobMemoryUsed' => '21037056',
      'PeakProcessMemoryUsed' => '8572928'
    },
    'BasicInfo' => {
      'ThisPeriodTotalKernelTime' => '44.234375',
      'TotalKernelTime' => '44.234375',
      'ThisPeriodTotalUserTime' => '18.625',
      'TotalUserTime' => '18.625',
      'TotalPageFaultCount' => '655537',
      'ActiveProcesses' => '0',
      'TotalProcesses' => '606',
      'TotalTerminatedProcesses' => '0'
    },
    'IoInfo' => {
      'OtherTransferCount' => '29616278',
      'WriteTransferCount' => '793999762',
      'OtherOperationCount' => '745504',
      'ReadOperationCount' => '600463',
      'WriteOperationCount' => '583931',
      'ReadTransferCount' => '770897934'
    }
  },
  '3568' => {
    'time' => {
      'kernel' => '0',
      'user' => '0',
      'elapsed' => '332.4019952'
    },
    'exitcode' => 0
  }
);

& the modifed code for returining all these useful stats, (as you will see my modification is really minor because I only added some fiew lines in the get_status() method) :
 
static void
get_status(pTHX_ JOB_T self, int wait)
{
 I32 i, imax = AV_REAL_LEN(self->procs);
 if (imax)
  hv_clear(self->info);
 for (i = 0; i < imax; i++) {
  STRLEN l;
  SV *tmp     = *av_fetch(self->procs, i, 0);
  PROC_T inf  = (PROC_T)SvPV(tmp, l);
  HV *proc    = newHV();
  HV *htime   = newHV();
  SV *ent     = newSVuv(inf->dwProcessId);
  DWORD ecode;
  FILETIME   stime, etime, ktime, utime;
  double            te,    tk,    tu;
 
  /* Wait for the process to finish terminating */
  if (wait)
   WaitForSingleObject(inf->hProcess, INFINITE);
 
  /* Get information about the process (only care about user and
   * kernel times */
  GetExitCodeProcess(inf->hProcess, &ecode);
  GetProcessTimes(inf->hProcess, &stime, &etime, &ktime, &utime);
  {
      ULARGE_INTEGER user, kernel, start, end, elapsed;
 
      kernel.LowPart = ktime.dwLowDateTime;
      kernel.HighPart = ktime.dwHighDateTime;
      user.LowPart = utime.dwLowDateTime;
      user.HighPart = utime.dwHighDateTime;
      start.LowPart = stime.dwLowDateTime;
      start.HighPart = stime.dwHighDateTime;
      end.LowPart = etime.dwLowDateTime;
      end.HighPart = etime.dwHighDateTime;
      if (!end.QuadPart) { /* process is not finished yet */
   SYSTEMTIME now;
   GetSystemTime(&now);
   SystemTimeToFileTime(&now, &etime);
   end.LowPart = etime.dwLowDateTime;
   end.HighPart = etime.dwHighDateTime;
      }
 
      elapsed.QuadPart = end.QuadPart - start.QuadPart;
 
      /* We must cast to signed __int64 because MSVC++ can't
       * convert unsigned __int64 to double. It's probably okay;
       * if the process is running long enough to overflow a
       * signed 64-bit integer, it won't fit into a double
       * anyway. */
      tk = ((__int64) kernel.QuadPart) / 10000000.0;
      tu = ((__int64)   user.QuadPart) / 10000000.0;
      te = ((__int64)elapsed.QuadPart) / 10000000.0;
  }
 
  /* Create a tree structure like this:
   * <pid>:
   *    exitcode:  123
   *    time:
   *       user:    123
   *       kernel:  123
   *       elapsed: 123
   */
  hv_store(htime, "user",    4, newSVnv(tu), 0);
  hv_store(htime, "kernel",  6, newSVnv(tk), 0);
  hv_store(htime, "elapsed", 7, newSVnv(te), 0);
  hv_store(proc, "exitcode", 8, newSVuv(ecode), 0);
  hv_store(proc, "time",     4, newRV_noinc((SV*)htime), 0);
  hv_store_ent(self->info, ent, newRV_noinc((SV*)proc), 0);
  SvREFCNT_dec(ent); /* free */
 }
 if(self->hJob)
 {
  SV *ent     = newSVpv("Job",3);   
  HV *job     = newHV();
  
  {
   JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION jobBasicAndIOInfo;
   if(QueryInformationJobObject(self->hJob, JobObjectBasicAndIoAccountingInformation, &jobBasicAndIOInfo, sizeof(jobBasicAndIOInfo), NULL))
   {
    
    {
     HV *haccounting    = newHV();
     double            tk, tu, tkp, tup;
  
     tk = ((__int64) jobBasicAndIOInfo.BasicInfo.TotalKernelTime.QuadPart) / 10000000.0;
         tu = ((__int64) jobBasicAndIOInfo.BasicInfo.TotalUserTime.QuadPart) / 10000000.0;
     tkp = ((__int64) jobBasicAndIOInfo.BasicInfo.ThisPeriodTotalKernelTime.QuadPart) / 10000000.0;
         tup = ((__int64) jobBasicAndIOInfo.BasicInfo.ThisPeriodTotalUserTime.QuadPart) / 10000000.0;
  
     hv_store(haccounting, "TotalUserTime",    13, newSVnv(tu), 0);
     hv_store(haccounting, "TotalKernelTime",  15, newSVnv(tk), 0);
     hv_store(haccounting, "ThisPeriodTotalUserTime",    23, newSVnv(tup), 0);
     hv_store(haccounting, "ThisPeriodTotalKernelTime",  25, newSVnv(tkp), 0);
     hv_store(haccounting, "TotalPageFaultCount",  19, newSVnv(jobBasicAndIOInfo.BasicInfo.TotalPageFaultCount), 0);
     hv_store(haccounting, "TotalProcesses",  14, newSVnv(jobBasicAndIOInfo.BasicInfo.TotalProcesses), 0);
     hv_store(haccounting, "ActiveProcesses",  15, newSVnv(jobBasicAndIOInfo.BasicInfo.ActiveProcesses), 0);
     hv_store(haccounting, "TotalTerminatedProcesses",  24, newSVnv(jobBasicAndIOInfo.BasicInfo.TotalTerminatedProcesses), 0);
     
  
     hv_store(job, "BasicInfo",     9, newRV_noinc((SV*)haccounting), 0);
    }
    {
     HV *hio    = newHV();
     char szI64[32];
     
     sprintf(szI64,"%I64u",jobBasicAndIOInfo.IoInfo.ReadOperationCount);
     hv_store(hio, "ReadOperationCount", 18, newSVpv(szI64,strlen(szI64)), 0);
     sprintf(szI64,"%I64u",jobBasicAndIOInfo.IoInfo.WriteOperationCount);
     hv_store(hio, "WriteOperationCount", 19, newSVpv(szI64,strlen(szI64)), 0);
     sprintf(szI64,"%I64u",jobBasicAndIOInfo.IoInfo.OtherOperationCount);
     hv_store(hio, "OtherOperationCount", 19, newSVpv(szI64,strlen(szI64)), 0);
     sprintf(szI64,"%I64u",jobBasicAndIOInfo.IoInfo.ReadTransferCount);
     hv_store(hio, "ReadTransferCount", 17, newSVpv(szI64,strlen(szI64)), 0);
     sprintf(szI64,"%I64u",jobBasicAndIOInfo.IoInfo.WriteTransferCount);
     hv_store(hio, "WriteTransferCount", 18, newSVpv(szI64,strlen(szI64)), 0);
     sprintf(szI64,"%I64u",jobBasicAndIOInfo.IoInfo.OtherTransferCount);
     hv_store(hio, "OtherTransferCount", 18, newSVpv(szI64,strlen(szI64)), 0);
       
     hv_store(job, "IoInfo",     6, newRV_noinc((SV*)hio), 0);
    }
   }
  }
  {
   JOBOBJECT_EXTENDED_LIMIT_INFORMATION  jobExtendedLimitInfo;
   if(QueryInformationJobObject(self->hJob, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(jobExtendedLimitInfo), NULL))
   {
    
    {
     HV *hlimits    = newHV();
   
     if(jobExtendedLimitInfo.BasicLimitInformation.LimitFlags&JOB_OBJECT_LIMIT_JOB_MEMORY) hv_store(hlimits, "ProcessMemoryLimit",    18, newSVnv(jobExtendedLimitInfo.ProcessMemoryLimit), 0);
     if(jobExtendedLimitInfo.BasicLimitInformation.LimitFlags&JOB_OBJECT_LIMIT_JOB_MEMORY) hv_store(hlimits, "JobMemoryLimit",    14, newSVnv(jobExtendedLimitInfo.JobMemoryLimit), 0);
     hv_store(hlimits, "PeakProcessMemoryUsed",    21, newSVnv(jobExtendedLimitInfo.PeakProcessMemoryUsed), 0);
     hv_store(hlimits, "PeakJobMemoryUsed",  17, newSVnv(jobExtendedLimitInfo.PeakJobMemoryUsed), 0);     
  
     hv_store(job, "LimitInfo",     9, newRV_noinc((SV*)hlimits), 0);
    }
   }
  }
  hv_store_ent(self->info, ent, newRV_noinc((SV*)job), 0);
  SvREFCNT_dec(ent); /* free */
 
 }
}
 
 
 
_______________________________________________
ActivePerl mailing list
[email protected]
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs

Reply via email to