I am trying how to use getrusage function in c in linux environment and was wondering if I am on a right track.
I wrote a small program to make sure I understand how getrusage works before applying to my project. I want to get the user/kernel times for both parent and child processes separately.
void stupidFunction();
void childSort();
int main(void)
{
pid_t parent_pid=getpid();
struct rusage parent_before_function_usage;
getrusage(RUSAGE_SELF,&parent_before_function_usage);
time_t parent_before_function_user_usage_sec=parent_before_function_usage.ru_utime.tv_sec;
time_t parent_before_function_user_usage_microsec=parent_before_function_usage.ru_utime.tv_usec;
time_t parent_before_function_cpu_usage_sec =parent_before_function_usage.ru_stime.tv_sec;
time_t parent_before_function_cpu_usage_microsecsec =parent_before_function_usage.ru_stime.tv_usec;
stupidFunction();
pid_t pid;
if((pid = fork()) <0)
{
fprintf(stderr,"Failed to create a fork process\n");
}
else if (pid == 0)
{
childSort();
}
int status;
waitpid(-1,&status,0);
printf("in parent\n");
struct rusage parent_after_function_usage;
getrusage(RUSAGE_SELF,&parent_after_function_usage);
time_t parent_after_function_user_usage_sec=parent_after_function_usage.ru_utime.tv_sec;
time_t parent_after_function_user_usage_microsec=parent_after_function_usage.ru_utime.tv_usec;
time_t parent_after_function_cpu_usage_sec =parent_after_function_usage.ru_stime.tv_sec;
time_t parent_after_function_cpu_usage_microsecsec =parent_after_function_usage.ru_stime.tv_usec;
time_t parent_real_user_usage_sec=parent_after_function_user_usage_sec - parent_before_function_user_usage_sec;
time_t parent_real_user_usage_microsec= parent_after_function_user_usage_microsec - parent_before_function_user_usage_microsec;
time_t parent_real_cpu_usage_sec=parent_after_function_cpu_usage_sec - parent_before_function_cpu_usage_sec;
time_t parent_real_cpu_usage_microsec = parent_after_function_cpu_usage_microsecsec - parent_before_function_cpu_usage_microsecsec;
printf("User mode CPU time for parent: %d seconds, %d microseconds\n",parent_real_user_usage_sec,parent_real_user_usage_microsec);
printf("Kern mode CPU time for parent: %d seconds, %d microseconds\n",parent_real_cpu_usage_sec,parent_real_cpu_usage_microsec);
struct rusage child_function_usage;
getrusage(RUSAGE_CHILDREN,&child_function_usage);
time_t all_children_user_usage_sec=child_function_usage.ru_utime.tv_sec;
time_t all_children_user_usage_microsec=child_function_usage.ru_utime.tv_usec;
time_t all_children_cpu_usage_sec =child_function_usage.ru_stime.tv_sec;
time_t all_children_cpu_usage_microsec =child_function_usage.ru_stime.tv_usec;
printf("User mode CPU time for all children: %d seconds, %d microseconds\n",all_children_user_usage_sec,all_children_user_usage_microsec);
printf("Kern mode CPU time for all children: %d seconds, %d microseconds\n",all_children_cpu_usage_sec,all_children_cpu_usage_microsec);
return 0;
}
void stupidFunction()
{
int i=0;
while(i<900000000)
{
// printf("%d\n",i);
i+=1;
}
}
void childSort()
{
printf("in childSort\n");
int fd[2];
fd[0]=open("file1", O_RDONLY,0777);
fd[1]=open("file2", O_WRONLY,0777);
dup2(fd[0],0);
dup2(fd[1],1);
char* execArgs[2];
execArgs[0]="sort";
execArgs[1]=NULL;
execvp(execArgs[0],execArgs);
}
Please provide some feedback about the correctness of the code and also, if instead of one children, I have many, will this code return the usage for all children combined ?
The semantics
RUSAGE_CHILDREN
are pretty clearly explained in the man page:Since your child process has terminated and you have waited for it, its statistics should be included in the data from your
getrusage(RUSAGE_CHILDREN, ...)
call. If you put the call before thewaitpid
, they wouldn't be included.Note it says clearly that this includes all children, even if there is more than one, and further descendants, provided they have terminated and been waited for.
I do see some bugs in your program that could explain any odd behavior you might be seeing.
First, the type of the
tv_usec
member ofstruct timeval
is nottime_t
butsuseconds_t
. Assigning.tv_usec
to a variable of typetime_t
might overflow it, in principle.Next, your
_sec
and_microsec
variables are of typetime_t
, but you print them with the%d
format specifier toprintf()
, which is intended forint
. Iftime_t
is of a type larger thanint
(which is the case on 64-bit Linux systems) then this will not work. The same goes when you change your_microsec
variables to be of the correct typesuseconds_t
.Now we don't necessarily know much about the types of
time_t
andsuseconds_t
. POSIX says only thattime_t
can be either an integer or floating-point type, and thatsuseconds_t
is a signed integer type that can represent numbers from 0 to 1000000.On all Linux platforms, as far as I know,
time_t
is a signed integer type, so I believe we could safely doThis won't necessarily be portable to all Unix systems, but I think it will work on most of them.
Also, opening files with mode
0777
is a bad practice, even for testing.