Компилятор Intel проигнорировал большой цикл?

Все:

У меня есть очень простой тестовый код C, использующий компилятор Intel, чтобы выполнить некоторое время для большого цикла для операции с плавающей запятой, код (test.c) выглядит следующим образом:

#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <omp.h>

int main(char *argc, char **argv) {
      const long N = 1000000000;
      double t0, t1, t2, t3;
      double sum=0.0;
      clock_t start, end;
      struct timeval r_start, r_end;
      long i;
      gettimeofday(&r_start, NULL);
      start = clock();
      for (i=0;i<N;i++)
          sum += i*2.0+i/2.0; // doing some floating point operations
      end = clock();
      gettimeofday(&r_end, NULL);
      double cputime_elapsed_in_seconds = (end - start)/(double)CLOCKS_PER_SEC;
      double realtime_elapsed_in_seconds = ((r_end.tv_sec * 1000000 + r_end.tv_usec)
                - (r_start.tv_sec * 1000000 + r_start.tv_usec))/1000000.0;
      printf("cputime_elapsed_in_sec: %e\n", cputime_elapsed_in_seconds);
      printf("realtime_elapsed_in_sec: %e\n", realtime_elapsed_in_seconds);
      //printf("sum= %4.3e\n", sum);
      return 0;
}

Однако, когда я попытался скомпилировать и запустить его с помощью компилятора Intel 13.0, казалось, что большой цикл проигнорирован, и выполнение привело к нулевому времени:

$ icc test.c
$ ./a.out
cputime_elapsed_in_sec: 0.000000e+00
realtime_elapsed_in_sec: 9.000000e-06

Только если я напечатаю сумму (раскомментированная строка 26), цикл действительно будет выполнен:

$ icc test.c
$ ./a.out
cputime_elapsed_in_sec: 2.730000e+00
realtime_elapsed_in_sec: 2.736198e+00
sum= 1.250e+18

Возникает вопрос, почему цикл не выполняется, если я не печатаю значение суммы?

Та же проблема не возникает с компиляторами gcc-4.4.7, я предполагаю, что компилятор Intel, возможно, сделал некоторую оптимизацию, что, если переменная не указана, цикл, вероятно, игнорируется?

Системная информация выглядит следующим образом:

$ uname -a
Linux node001 2.6.32-642.11.1.el6.x86_64 #1 SMP Wed Oct 26 10:25:23 EDT 2016 x86_64 x86_64 x86_64 GNU/Linux
$ icc -v
icc version 13.0.0 (gcc version 4.4.7 compatibility)
$ gcc -v
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC)

Спасибо за любые предложения!

Рой


person Roy Li    schedule 09.05.2017    source источник
comment
Какой у Вас вопрос?   -  person user253751    schedule 09.05.2017
comment
Попробуйте отключить оптимизацию и посмотрите, дает ли это результат, когда вы печатаете сумму: stackoverflow.com/questions/5765899/   -  person J.N.    schedule 09.05.2017
comment
Один из вариантов - объявить sum как volatile.   -  person paddy    schedule 09.05.2017


Ответы (1)


Учитывая ваше наблюдение, что печать окончательного значения замедляет его (a), есть довольно хороший шанс, что оптимизатор выясняет, что вы на самом деле не используете sum ни для чего после того, как вы его вычислили, поэтому он оптимизирует весь цикл вычислений.

Я действительно видел нечто подобное довольно давно, когда мы тестировали производительность последней машины VAX 11/780, которую получил наш университет (показывая там мой возраст). Он был быстрее на несколько тысяч процентов по той же причине: новый оптимизирующий компилятор решил, что цикл на самом деле не нужен.

Чтобы быть уверенным, вам нужно изучить вывод сборки. Я считаю, что это можно сделать с помощью icc, используя параметр -Fa <asmFileName>, а затем изучив файл, имя которого вы использовали вместо <asmFileName>.


(a) Другая возможность, о которой я подумал, кажется, здесь не учитывается.

Это была возможность того, что, учитывая, что диапазон i является постоянным (на основе N) и что вычисление в противном случае включает константы, возможно, что сам компилятор вычислил окончательное значение при его компиляции, что привело к простой операции постоянной загрузки.

Я видел gcc такие вещи на -O3 "безумном" уровне оптимизации.

Я исключаю эту возможность, поскольку печать значения, скорее всего, не повлияет на эту операцию.

person paxdiablo    schedule 09.05.2017
comment
Спасибо за ответ, попробовал -O1, -O2, -O3 без строки суммы печати, результат тот же. Если полностью отключить оптимизацию, используя -O0, цикл будет выполнен, поэтому я думаю, что да, ответ должен заключаться в том, что компилятор оптимизировал весь цикл. - person Roy Li; 09.05.2017