Linux process execution time

  • Post author:
  • Post last modified:August 23, 2023
  • Reading time:7 mins read

Execution time

A process has an execution time associated with it. The execution time comprises of two parts, the user time and the system time. The user time is the time spent by the CPU in executing instructions in user mode. The system time is the time spent by the CPU in executing instructions on behalf of a process in the kernel mode. The system time is when the kernel is executing system calls for the process and servicing interrupts.

times system call

The times system call gives the time spent by the CPU on a given process. There is a struct tms,

struct tms {  
    clock_t tms_utime;              /* User CPU time.  */    
    clock_t tms_stime;              /* System CPU time.  */   
    clock_t tms_cutime;             /* User CPU time of terminated children.  */  
    clock_t tms_cstime;             /* System CPU time of terminated children.  */    
};

clock_t is typically a long integer. The system call times is,

#include <sys/times.h> 

clock_t times (struct tms *buffer);

The user and system times are passed back in the buffer. times returns time since some arbitrary point back in time. However, the data returned in the buffer is of interest to us as it gives us the user and system time for the process and its children which have terminated and for which the parent has issued a wait system call.

The unit of clock_t here is clock ticks. The number of clock ticks per second can be found by the sysconf system call,

printf ("_SC_CLK_TCK = %ld\n", sysconf (_SC_CLK_TCK));

A typical value of clock ticks per second is 100. That is, in this case, there is a clock tick every 10 milliseconds or 0.01 second. To convert the clock_t values, returned by times, into seconds one has to divide by the number of clock ticks per second. An example program using the times and sysconf (_SC_CLK_TCK) system calls is,

#include <stdio.h> 
#include <string.h>   
#include <stdlib.h>   
#include <unistd.h>   
#include <time.h>     
#include <sys/times.h>   

main ()  
{    
    clock_t ct0, ct1;   
    struct tms tms0, tms1;     
    int i;         

    if ((ct0 = times (&tms0)) == -1)     
        perror ("times");   

    printf ("_SC_CLK_TCK = %ld\n", sysconf (_SC_CLK_TCK));   

    for (i = 0; i < 10000000; i++)  
        ;  

    if ((ct1 = times (&tms1)) == -1)   
        perror ("times");   

    printf ("ct0 = %ld, times: %ld %ld %ld %ld\n", ct0, tms0.tms_utime,  
        tms0.tms_cutime, tms0.tms_stime, tms0.tms_cstime);     
    printf ("ct1 = %ld, times: %ld %ld %ld %ld\n", ct1, tms1.tms_utime,     
        tms1.tms_cutime, tms1.tms_stime, tms1.tms_cstime);     
    printf ("ct1 - ct0 = %ld\n", ct1 - ct0);  
}

The above program gives the following output on my machine,

_SC_CLK_TCK = 100  
ct0 = 1740824767, times: 0 0 0 0      
ct1 = 1740824771, times: 3 0 0 0      
ct1 - ct0 = 4

As per the above output, the system has spent 30 ms in executing instructions between the first and the second call to call to times system call. Overall, the elapsed time between the first and the second calls is 40 ms.

getrusage system call

The get resource usage (getrusage) system call gives the process execution time in the struct timeval, with time in seconds and microseconds. With getrusage, it is possible to get execution time at the level of individual thread. The system call is,

#include <sys/time.h>  
#include <sys/resource.h>    

int getrusage (int who, struct rusage *usage);

The first parameter, who, specifies for whom the report is required. The value of who could be RUSAGE_SELF, RUSAGE_CHILDREN or RUSAGE_THREAD. If who is RUSAGE_SELF, the information for the calling process is returned. If who is RUSAGE_CHILDREN, then the information regarding all children of the calling process that have terminated and been waited for is returned. If who is RUSAGE_THREAD, the the information about the calling thread is returned. The second parameter is a pointer to struct rusage, which many other fields apart from the user and system times,

struct rusage {    
    struct timeval ru_utime; /* user CPU time used */    
    struct timeval ru_stime; /* system CPU time used */    
    long   ru_maxrss;        /* maximum resident set size */    
    long   ru_ixrss;         /* integral shared memory size */    
    long   ru_idrss;         /* integral unshared data size */    
    long   ru_isrss;         /* integral unshared stack size */    
    long   ru_minflt;        /* page reclaims (soft page faults) */    
    long   ru_majflt;        /* page faults (hard page faults) */    
    long   ru_nswap;          /* swaps */    
    long   ru_inblock;       /* block input operations */    
    long   ru_oublock;       /* block output operations */    
    long   ru_msgsnd;        /* IPC messages sent */     
    long   ru_msgrcv;        /* IPC messages received */    
    long   ru_nsignals;      /* signals received */    
    long   ru_nvcsw;         /* voluntary context switches */    
    long   ru_nivcsw;        /* involuntary context switches */    
};

The first two members give the user and system times respectively. Fields ru_ixrss, ru_idrss, ru_isrss, ru_nswap, ru_msgsnd, ru_msgrcv and ru_nsignals are not used in Linux and the kernel sets these values to zero. These fields are provided for compatibility with other systems and might get supported on Linux in future.

clock function

The standard library has a function clock,

#include <time.h>   

clock_t clock (void);

which returns the CPU time used by the calling process. Although the return type of clock is clock_t, the same as that of the times system call described above, the units of the returned value of clock are different from that of times. There is a constant CLOCKS_PER_SEC defined mostly as 1,000,000 clock ticks per second. The value returned by the clock function is in clock ticks. So, if CLOCKS_PER_SEC is 1,000,000, the value is in microseconds. To get the time in seconds one has to divide it by 1,000,000, or, to be more precise, divide it by the value defined by the constant, CLOCKS_PER_SEC. An example program using the clock function is,

#include <stdlib.h>      
#include <unistd.h>      
#include <time.h>      

main ()      
{      
    clock_t ct1, ct2;      
    int i;      

    if ((ct1 = clock ()) == -1)      
        perror ("clock");      

    printf ("CLOCKS_PER_SEC = %ld\n", CLOCKS_PER_SEC);      

    for (i = 0; i < 10000000; i++)      
        ;      
    if ((ct2 = clock ()) == -1)      
        perror ("clock");      

    printf ("ct1 = %ld, ct2 = %ld, diff = %ld\n", ct1, ct2, ct2 - ct1);      
}

The above program gives the following output on my computer,

CLOCKS_PER_SEC = 1000000    
ct1 = 0, ct2 = 30000, diff = 30000

There are one million clock ticks per second. The first clock function call gives 0, as the process has just started and hardly any CPU time has been clocked by the process. The second clock function call gives a CPU usage of 30000 microseconds, or, 0.03 seconds.

See also

  1. Calendar Time Under Linux
  2. Alarm, sleep and High Resolution Timers
  3. hwclock, the hardware clock query and set program
  4. Synchronize your computer’s clock using the NTP
Share

Karunesh Johri

Software developer, working with C and Linux.
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments