Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `do{} while(0);` so fast?

I'v tried the following 3 for loops:

#define loop 1000000000
NSDate *start;
NSDate *end;


// 1: empty for loop
start = [NSDate date];
for (NSInteger i = 0; i < loop; i++) {
}
end = [NSDate date];
NSLog(@"time interval: %f", [end timeIntervalSince1970] - [start timeIntervalSince1970]);


// 2: do-while for loop
start = [NSDate date];
for (NSInteger i = 0; i < loop; i++) {
    do {
    } while (0);
}
end = [NSDate date];
NSLog(@"time interval: %f", [end timeIntervalSince1970] - [start timeIntervalSince1970]);

// 3: @try-@finally for loop
start = [NSDate date];
for (NSInteger i = 0; i < loop; i++) {
    @try {
    }
    @finally {
    }
}
end = [NSDate date];
NSLog(@"time interval: %f", [end timeIntervalSince1970] - [start timeIntervalSince1970]);

I test those three for loops about 1 billion on my '07 Macbook Pro. And I recorded the timestamp to calculate the execution duration. Here are the results:

1: empty for loop => 2.947088 sec
2: do-while for loop => 2.581905 sec
3: @try-@finally for loop => 4.216685 sec

What? do-while for loop is faster than empty for loop!

Why?


UPDATED

I add some additional code (j++) in the for loop:

NSInteger j;
#define loop 1000000000

// 1: empty for loop
j = 0
for (NSInteger i = 0; i < loop; i++) {
    j++;
}

// 2: do-while for loop
j = 0;
for (NSInteger i = 0; i < loop; i++) {
    do {
        j++;
    } while (0);
}

// 3: @try-@finally for loop
j = 0;
for (NSInteger i = 0; i < loop; i++) {
    @try {
        j++;
    }
    @finally {
    }
}

Output:

1: empty for loop => 2.590103 sec
2: do-while for loop => 2.138528 sec
3: @try-@finally for loop => 3.983589 sec

Those 3 are much faster than previous code, and do-while for loop is still fastest. Weird!

like image 357
Xaree Lee Avatar asked Dec 19 '22 21:12

Xaree Lee


1 Answers

It's not. The output depends a lot on the particular compiler being used as well as the optimization settings in effect. Any compiler worth its salt will optimize away both of the loops. When I compile the following sample code, both Clang and GCC completely remove the loops at any non-zero optimization level (i.e. -O1 and above):

#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>

#define loop 1000000000

int main(void)
{
  struct timeval t1, t2, t3;
  gettimeofday(&t1, NULL);

  for (long i = 0; i < loop; i++) {
  }

  gettimeofday(&t2, NULL);

  for (long i = 0; i < loop; i++) {
    do {
    } while (0);
  }

  gettimeofday(&t3, NULL);

  int64_t d1 = (t2.tv_sec - t1.tv_sec) * 1000000ll + (t2.tv_usec - t1.tv_usec);
  int64_t d2 = (t3.tv_sec - t2.tv_sec) * 1000000ll + (t3.tv_usec - t2.tv_usec);

  printf("Empty for loop:    %lld.%06d\n", d1 / 1000000, (int)(d1 % 1000000));
  printf("do-while for loop: %lld.%06d\n", d2 / 1000000, (int)(d2 % 1000000));

  return 0;
}

At optimization level 0 (-O0, unoptimized code), both Clang and GCC produce code where either both loops run with the same speed (to within experimental error), or the do-while loop runs slightly slower due to the extra unoptimized code. My results on a 64-bit Mac, using Clang 4.1 and GCC 4.2.1:

Clang, 32-bit, -O0:
Empty for loop:    2.632714
do-while for loop: 2.633194

Clang, 64-bit, -O0:
Empty for loop:    2.632078
do-while for loop: 2.632046

Clang, 32-bit, -O1:
Empty for loop:    0.000000
do-while for loop: 0.000000

Clang, 64-bit, -O1:
Empty for loop:    0.000000
do-while for loop: 0.000000

GCC, 32-bit, -O0:
Empty for loop:    2.633221
do-while for loop: 2.633754

GCC, 64-bit, -O0:
Empty for loop:    2.778056
do-while for loop: 2.983421  (!!!)

GCC, 32-bit, -O1:
Empty for loop:    0.000001
do-while for loop: 0.000000

GCC, 64-bit, -O1:
Empty for loop:    0.000000
do-while for loop: 0.000000
like image 157
Adam Rosenfield Avatar answered Dec 22 '22 10:12

Adam Rosenfield