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_CHILDRENare 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_usecmember ofstruct timevalis nottime_tbutsuseconds_t. Assigning.tv_usecto a variable of typetime_tmight overflow it, in principle.Next, your
_secand_microsecvariables are of typetime_t, but you print them with the%dformat specifier toprintf(), which is intended forint. Iftime_tis 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_microsecvariables to be of the correct typesuseconds_t.Now we don't necessarily know much about the types of
time_tandsuseconds_t. POSIX says only thattime_tcan be either an integer or floating-point type, and thatsuseconds_tis a signed integer type that can represent numbers from 0 to 1000000.On all Linux platforms, as far as I know,
time_tis 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
0777is a bad practice, even for testing.