Millet Porridge

English version of https://corvo.myseu.cn

0%

Pitfalls I Hit with clock()

The Original Program

I was writing a program recently; the pseudocode was roughly like this.

1
2
3
4
5
6
7
8
9
10
start = get_time();
while(!stop) {
// some actions

if(get_time() - start > 1s) { // interval exceeds 1s (physical 1s)
// other actions.

start = get_time();
}
}

We all know that we’ve previously used the clock() function to get a program’s runtime.

For example:

1
2
3
4
5
6
7
clock_t start = clock();

// actions.

clock_t end = clock();

int run_time = end - start;

A Problem in the Program

In the program I used the clock() function the same way, and the result was disappointing: extremely low program efficiency (perhaps my interval was too short, causing repeated calls).

  1. In my program the 1s interval needs to be fairly precise — the previous operation and this one must truly be 1s apart.
  2. clock() only counts CPU running time; if the program sleeps, no CPU time is consumed. That is to say, the interval measured by clock() may be a bit longer than the real time — and as for how much longer, I don’t know how to compute that either.

My Experiment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

// A simple time-consuming function
int frequency_of_primes (int n) {
int i,j;
int freq=n-1;
for (i=2; i<=n; ++i) for (j=sqrt(i);j>1;--j) if (i%j==0) {--freq; break;}
return freq;
}


clock_t start = clock();

// The sleep function cannot be used here — while sleeping the clock does not advance

// sleep(2);
// Get clock 0.000022

frequency_of_primes(999999);
// Get clock 1.579848

clock_t end = clock();
printf("Get clock %fs\n", (double)(end - start) / CLOCKS_PER_SEC);

If sleep(2) is called, clock() barely changes, which shows that in the sleeping state the CPU clock is not consumed.

Correct Time Measurement

For polling timers, I recommend the clock_gettime() function.

1
2
3
4
5
6
7
8
9
10
11
12
struct timespec start, finish;
double elapsed;

clock_gettime(CLOCK_MONOTONIC, &start);
sleep(2);

clock_gettime(CLOCK_MONOTONIC, &finish);

elapsed = (finish.tv_sec - start.tv_sec);
elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;

printf("Now we get %fs\n", elapsed);

The code above can be seen in the gist.