Usage and difference of clock(), time(), clock_gettime() and gettimeofday() functions

A) ANSI clock function 


1) Overview:
The return value type of the clock function is clock_t, which is divided by CLOCKS_PER_SEC to get the time. Generally, the clock function is used twice to calculate the running time of the process itself.

The ANSI clock has three problems:
1) If it exceeds one hour, it will cause an overflow.
2) The function clock does not consider the use of the CPU by the child process.
3) It cannot distinguish between user space and kernel space.

So the clock function becomes meaningless on the linux system.

2) Test
Write the test1.c program to test the difference between the output of the clock function and the time program.

vi test1.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main( void )
{
   long i=1000L;
   clock_t start, finish;
   double  duration;
   printf( "Time to do %ld empty loops is ", i );
   start = clock();
   while (--i){
    system("cd");
   }
   finish = clock();
   duration = (double)(finish - start) / CLOCKS_PER_SEC;
   printf( "%f seconds\n", duration );
   return 0;
}

gcc test1.c -o test1

time ./test1
Time to do 1000 empty loops is 0.180000 seconds

real    0m3.492s
user    0m0.512s
sys     0m2.972s

3) Summary:
(1) The program calls system("cd");, here is mainly the consumption of system mode sub-processes, the test1 program cannot reflect this.
(2) The consumption of 0.180000 seconds is two clock() function calls Divide by CLOCKS_PER_SEC.
(3) The return value of the clock() function is a relative time, not an absolute time.
(4) CLOCKS_PER_SEC is a system-defined macro, defined as 1000000 by the GNU standard library.


Two) times() time function

1 Overview:

The prototype is as follows:
clock_t times(struct tms *buf);

The tms structure is as follows:
strace  tms { clock_t tms_utime;  clock_t tms_stime;  clock_t tms_cutime;  clock_t tms_cstime; }




Note:
tms_utime records the time the process executes the user code.
tms_stime records the time the process executes the kernel code.
tms_cutime records the time the child process executes the user code.
tms_cstime records the time the child process executes the kernel code.


2) Test:

vi test2.c
#include <sys/times.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

static void do_cmd(char *);
static void pr_times(clock_t, struct tms *, struct tms *);

int main(int argc, char *argv[]){
        int i;
        for(i=1; argv[i]!=NULL; i++){
                do_cmd(argv[i]);
        }
        exit(1);
}
static void do_cmd(char *cmd){
        struct tms tmsstart, tmsend;
        clock_t start, end;
        int status;
        if((start=times(&tmsstart))== -1)
                puts("times error");
        if((status=system(cmd))<0)
                puts("system error");
        if((end=times(&tmsend))== -1)
                puts("times error");
        pr_times(end-start, &tmsstart, &tmsend);
        exit(0);
}
static void pr_times(clock_t real, struct tms *tmsstart, struct tms *tmsend){
        static long clktck=0;
        if(0 == clktck)
                if((clktck=sysconf(_SC_CLK_TCK))<0)
                           puts("sysconf err");
        printf("real:%7.2f\n", real/(double)clktck);
        printf("user-cpu:%7.2f\n", (tmsend->tms_utime - tmsstart->tms_utime)/(double)clktck);
        printf("system-cpu:%7.2f\n", (tmsend->tms_stime - tmsstart->tms_stime)/(double)clktck);
        printf("child-user-cpu:%7.2f\n", (tmsend->tms_cutime - tmsstart->tms_cutime)/(double)clktck);
        printf("child-system-cpu:%7.2f\n", (tmsend->tms_cstime - tmsstart->tms_cstime)/(double)clktck);
}

Compile:
gcc test2.c -o test2

测试这个程序:
time ./test2 "dd if=/dev/zero f=/dev/null bs=1M count=10000"
10000+0 records in
10000+0 records out
10485760000 bytes (10 GB) copied, 4.93028 s, 2.1 GB/s
real:   4.94
user-cpu:   0.00
system-cpu:   0.00
child-user-cpu:   0.01
child-system-cpu:   4.82

real    0m4.943s
user    0m0.016s
sys     0m4.828s


3) Summary:
(1) Through this test, the output of the time program of the system is basically the same as that of the test2 program.
(2) (double)clktck is obtained by clktck=sysconf(_SC_CLK_TCK), that is, to get the user-cpu the time taken, will use
(tmsend-> tms_utime - tmsstart-> tms_utime) / (Double) clktck);
(. 3) of clock_t times (struct TMS * buf); return value is the number of the clock ticking over time.
( 4) The return value of the times() function is also a relative time.

Three) real-time function clock_gettime

This function was added in
POSIX1003.1, and its prototype is as follows: int clock_gettime(clockid_t clk_id, struct timespec *tp);

It has the following characteristics:
1) It also has a time structure: timespec, the unit of timespec to calculate the number of times is one billionth of a second.
strace timespec{  time_t tv_sec;  long tv_nsec; }


2) clockid_t is to determine which clock type.

CLOCK_REALTIME: Standard POSIX real-time clock
CLOCK_MONOTONIC: POSIX clock, running at a constant rate; it will not be reset and adjusted, and its value is the same as
CLOCK_REALTIME . CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID are implemented in the hardware timer in the CPU.


3)测试:
#include<time.h>
#include<stdio.h>
#include<stdlib.h>

#define MILLION 1000000


int main(void)
{
        long int loop = 1000;
        struct timespec tpstart;
        struct timespec tpend;
        long timedif;

        clock_gettime(CLOCK_MONOTONIC, &tpstart);

        while (--loop){
                system("cd");
        }

        clock_gettime(CLOCK_MONOTONIC, &tpend);
        timedif = MILLION*(tpend.tv_sec-tpstart.tv_sec)+(tpend.tv_nsec-tpstart.tv_nsec)/1000;
        fprintf(stdout, "it took %ld microseconds\n", timedif);

        return 0;
}

Compile:
gcc test3.c -lrt -o test3

Calculation time:
time ./test3
it took 3463843 microseconds

real    0m3.467s
user    0m0.512s
sys     0m2.936s


Four) Time function gettimeofday()

1) Overview:
gettimeofday() can get the current system time, which is an absolute value

The prototype is as follows:
int gettimeofday (struct timeval * tv, struct timezone * tz)

The prototype of the timeval knot body is as follows:
struct timeval {                time_t tv_sec;                    suseconds_t tv_usec;               };


So it can be accurate to microseconds


测试:
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
int
main(){
        int i=10000000;
        struct timeval tvs,tve;
        gettimeofday(&tvs,NULL);
        while (--i);
        gettimeofday(&tve,NULL);
        double span = tve.tv_sec-tvs.tv_sec + (tve.tv_usec-tvs.tv_usec)/1000000.0;
        printf("time: %.12f\n",span);
        return 0;
}

gcc test5.c
./a.out
time: 0.041239000000

5) Comparison of four time functions

1) Accuracy comparison:

The following is the type conversion of various accuracy:
1 second = 1000 milliseconds (ms), 1 millisecond = 1/1000 seconds (s);
1 second = 1000000 microseconds (μs), 1 microsecond = 1/1000000 seconds (s) );
1 second = 1000000000 nanoseconds (ns), 1 nanosecond = 1/1000000000 seconds (s);


2)
The accuracy of the clock() function is 10 milliseconds (ms)
The accuracy of the times() function is 10 milliseconds (ms)
The accuracy of the gettimofday() function is microseconds (μs)
The measurement unit of the clock_gettime() function is ten One billionth, which is nanosecond (ns)


3) Test the accuracy of 4 functions:

vi test4.c


#include    <stdio.h>
#include    <stdlib.h>
#include    <unistd.h>
#include    <time.h>
#include    <sys/times.h>
#include    <sys/time.h>
#define WAIT for(i=0;i<298765432;i++);
#define MILLION    1000000
    int
main ( int argc, char *argv[] )
{
    int i;
    long ttt;
    clock_t s,e;
    struct tms aaa;



    s=clock();
    WAIT;
    e=clock();
    printf("clock time : %.12f\n",(e-s)/(double)CLOCKS_PER_SEC);


    long tps = sysconf(_SC_CLK_TCK);
    s=times(&aaa);
    WAIT;
    e=times(&aaa);
    printf("times time : %.12f\n",(e-s)/(double)tps);


    struct timeval tvs,tve;
    gettimeofday(&tvs,NULL);
    WAIT;
    gettimeofday(&tve,NULL);
    double span = tve.tv_sec-tvs.tv_sec + (tve.tv_usec-tvs.tv_usec)/1000000.0;
    printf("gettimeofday time: %.12f\n",span);


    struct timespec tpstart;
    struct timespec tpend;

    clock_gettime(CLOCK_REALTIME, &tpstart);
    WAIT;
    clock_gettime(CLOCK_REALTIME, &tpend);
    double timedif = (tpend.tv_sec-tpstart.tv_sec)+(tpend.tv_nsec-tpstart.tv_nsec)/1000000000.0;
    printf("clock_gettime time: %.12f\n", timedif);

    return EXIT_SUCCESS;
}

gcc -lrt test4.c -o test4
debian:/tmp# ./test4
clock time : 1.190000000000
times time : 1.180000000000
gettimeofday time: 1.186477000000
clock_gettime time: 1.179271718000

6) Core clock

The default Linux clock cycle is 100HZ, and now the latest kernel clock cycle defaults to 250HZ.
How to get the kernel clock cycle?
grep ^CONFIG_HZ /boot/config-2.6.26-1-xen-amd64

CONFIG_HZ_250=y
CONFIG_HZ=250

The result is 250HZ.

And use sysconf(_SC_CLK_TCK); to get 100HZ,
for example:

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

int
main ( int argc, char *argv[] )
{

    long tps = sysconf(_SC_CLK_TCK);
    printf("%ld\n", tps);
   
    return EXIT_SUCCESS;
}

Why do you get different values?
Because sysconf(_SC_CLK_TCK) and CONFIG_HZ represent different meanings.
sysconf(_SC_CLK_TCK) is the clock_t frequency of the GNU standard library.
It is defined in: /usr/include/asm/param.h

For example:
#ifndef HZ
#define HZ 100
#endif

Finally, summarize the kernel time:
the standard time of the kernel is jiffy, a jiffy is an internal clock cycle, and the internal clock cycle is generated by a frequency of 250HZ, which is a clock tick, and the interval time is 4 milliseconds (ms).

In other words:
1 jiffy = 1 internal clock cycle = 250HZ = 1 clock tick = 4 milliseconds

The clock interrupt handler is called every time a clock tick passes. The handler uses jiffy to accumulate the number of clock ticks, and increments by 1 every time a clock interrupt occurs.
After each interrupt, the system selects whether to use the scheduler according to the time slice. The process continues to run, or the process enters the ready state.

The last thing to note is that the clock tick frequency of each operating system is different, LINUX can choose (100, 250, 1000) HZ, and the frequency of DOS is 55HZ.

7) Time the application

Use the time program to monitor the CPU usage of any command or script.

1) The bash built-in command time
e.g.
time sleep 1

real    0m1.016s
user    0m0.000s
sys     0m0.004s


2) General command line of /usr/bin/time
For example:
\time sleep 1
0.00user 0.00system 0:01.01elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (1major+176minor)pagefaults 0swaps

Note:
Add a slash before the command to bypass the internal command.
You can also add -v to /usr/bin/time to see more specific output:
\time -v sleep 1
        Command being timed: "sleep 1"
        User time (seconds): 0.00
        System time (seconds): 0.00
        Percent of CPU this job got: 0%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.00
        Average shared text size (kbytes): 0
        Average unshared data size (kbytes): 0
        Average stack size (kbytes): 0
        Average total size (kbytes): 0
        Maximum resident set size (kbytes): 0
        Average resident set size (kbytes): 0
        Major (requiring I/O ) page faults: 0
        Minor (reclaiming a frame) page faults: 178
        Voluntary context Switches: 2
        Involuntary context Switches: 0
        Swaps: 0
        File System Inputs: 0
        File System Outputs: 0
        the Socket messages Sent: 0
        the Socket messages Received: 0
        the Signals delivered: 0
        Page size (bytes): 4096
        the Exit Status: 0
       
here The output is more derived from the structure rusage.

Finally, we see that real time is greater than the sum of user time and sys time, which shows that the process is either blocked in the system call or has no chance to run.
The use of sleep() also illustrates this point.

Guess you like

Origin blog.csdn.net/daocaokafei/article/details/114806675