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
}
);
'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;
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);
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 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;
}
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;
}
* 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 */
* <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
