Skip Menu |
 

This queue is for tickets about the Win32-Job CPAN distribution.

Report information
The Basics
Id: 21254
Status: new
Priority: 0/
Queue: Win32-Job

People
Owner: Nobody in particular
Requestors: louis.lecaroz [...] le-resistant.com
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: Retrieving all job statistics in Win32::Jobs
Download (untitled) / with headers
text/plain 8.2k
As requested by Jan, I am forwarding my enhancement request here. I modified job.c to enhance this great class : 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. This is really cheap in term of development & cpu usage because it needs only to other calls two times a Win32 api (QueryInformationJobObject). I tested it on more than 10000 process loading when the job was finished by calling stats() & it appears to work correctly. But I did not try to call the stats() method when the job was not finished to retreive statistics based on a scheduled time when the job runs ;). thx in advance, Louis here is now an example of the result stat returned from Job->Stats() after having added my modification : %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 */ } }
Subject: Job.c
Download Job.c
text/x-csrc 23.5k

Message body is not shown because it is too large.



This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

Please report any issues with rt.cpan.org to rt-cpan-admin@bestpractical.com.