2017-01-28 2 views
0

Я делал эксперимент для измерения времени выполнения '' for loop '' на микроколлеллере. Это «для цикла» содержит некоторую операцию с целым числом и указателем.Для устранения LOOP оптимизацией компилятора

Случай 1: когда я устанавливаю флаг оптимизации компилятора в '' none '' (без оптимизации) сгенерирован код сборки, и я могу измерить время выполнения.

Случай 2: Когда я устанавливаю оптимизацию компилятора на «скорость» (оптимизированную для скорости) , то для этого цикла не создается код сборки. Похоже, компилятор выкидывать это «» цикл «»

/* the basic concept behind this code is data manipulation in an array.Therefore I created an array then with the help of loops, tried to manipulate data*/ 

    int abc[1000]; 
    for(n=0; n<1000; n++) 
      { 
       abc[n]= 0xaa;       
      } 
    for(n=2; n<1000; n=n+2) 
      { 
       abc[n]= 0xbb;       
      } 
    for(n=5; n<1000; n=n+2) 
      { 
    for(i=(n+n); i<1000; i++) 
       { 
        abc[i]= i;       
       } 
      } 

Может кто-нибудь объяснить, почему компилятор выбросить эту петлю, когда я установил флаг компилятора скорости.

+0

Можете ли вы показать содержимое цикла 'for' и функции, в которой он вызван? –

+0

Я добавил код примера для вашей справки. – user7439633

+0

Правильно отформатируйте свой код, чтобы сделать его доступным для чтения. –

ответ

1

Если вы не используете abc, возможно, что оптимизатор распознал его (и все записи на нем) как «мертвые» и полностью удалил.

1

Компилятор просматривает ваш код и видит, что abc установлен и никогда не используется. Некоторые компиляторы дают вам предупреждение об этом. Поскольку abc никогда не используется, компилятор оптимизирует его, потому что смысл в настройке переменной, если вы ее никогда не используете.

Вы можете сделать abc volatile, но это, вероятно, победит цель вашего теста. Внесите переменную volatile, сообщив компилятору, он не может делать никаких предположений о ее использовании. Когда вы делаете переменную volatile, компилятор не может выполнять какие-либо оптимизации, поэтому время будет одинаковым с оптимизацией и без него.

0

вот пара ПРИМЕРНЫХ примеров, так как ваша неполна до такой степени, что мы не можем точно ответить на ваш вопрос.

unsigned int fun (void) 
{ 
    unsigned int x[8]; 
    unsigned int ra; 
    unsigned int rb; 

    for(ra=0;ra<5;ra++) x[ra]=ra; 
    rb=0; for(ra=0;ra<5;ra++) rb+=x[ra]; 
    return(rb); 
} 

void more_fun (void) 
{ 
    unsigned int x[8]; 
    unsigned int ra; 

    for(ra=0;ra<5;ra++) x[ra]=ra; 
} 

и пример оптимизированного скомпилированного

00000000 <fun>: 
    0: e3a0000a mov r0, #10 
    4: e12fff1e bx lr 

00000008 <more_fun>: 
    8: e12fff1e bx lr 

вторая функция первой, это очень легко видеть, что ни ра, ни х используются за пределами функции, ничего, что они делают, производство ничего из реальной стоимости, он мертв код с неиспользованным переменными, так что все это уходит, и вся функция оптимизирована для этого:

void more_fun (void) 
{ 
} 

, как это должно быть.

Принимая это дальше, и я использую такие вещи гораздо дальше, используя рандомизаторы и другие алгоритмы, а иногда компилятор его вычисляет, иногда нет. В этом случае это было довольно легко.

Таким образом, ни одна из функций функции fun() не имеет значения во время выполнения, это все мертвый код, результат не зависит от входа или чего-то глобального, это математика, полностью содержащаяся в функции с точным ответ, который может быть предварительно вычислен. Поэтому компилятор вычисляет ответ во время компиляции (0 + 1 + 2 + 3 + 4 = 10) и удаляет весь мертвый код. в основном придумывают правильный ответ

unsigned int fun (void) 
{ 
    return(10); 
} 

Если вы желаете, чтобы записать время с помощью петли или, возможно, даже увидеть, как реализуются петли и т.д., то вы можете попробовать несколько вещей.

void dummy (unsigned int); 
unsigned int fun (void) 
{ 
    unsigned int ra; 
    volatile unsigned int rb; 

    rb=0; for(ra=0;ra<5;ra++) rb+=ra; 
    return(rb); 
} 

void more_fun (void) 
{ 
    unsigned int ra; 
    for(ra=0;ra<5;ra++) dummy(ra); 
} 

который может дать что-то вроде (компиляторы варьироваться)

00000000 <fun>: 
    0: e3a03000 mov r3, #0 
    4: e24dd008 sub sp, sp, #8 
    8: e58d3004 str r3, [sp, #4] 
    c: e59d3004 ldr r3, [sp, #4] 
    10: e58d3004 str r3, [sp, #4] 
    14: e59d3004 ldr r3, [sp, #4] 
    18: e2833001 add r3, r3, #1 
    1c: e58d3004 str r3, [sp, #4] 
    20: e59d3004 ldr r3, [sp, #4] 
    24: e2833002 add r3, r3, #2 
    28: e58d3004 str r3, [sp, #4] 
    2c: e59d3004 ldr r3, [sp, #4] 
    30: e2833003 add r3, r3, #3 
    34: e58d3004 str r3, [sp, #4] 
    38: e59d3004 ldr r3, [sp, #4] 
    3c: e2833004 add r3, r3, #4 
    40: e58d3004 str r3, [sp, #4] 
    44: e59d0004 ldr r0, [sp, #4] 
    48: e28dd008 add sp, sp, #8 
    4c: e12fff1e bx lr 

00000050 <more_fun>: 
    50: e92d4010 push {r4, lr} 
    54: e3a04000 mov r4, #0 
    58: e1a00004 mov r0, r4 
    5c: e2844001 add r4, r4, #1 
    60: ebfffffe bl 0 <dummy> 
    64: e3540005 cmp r4, #5 
    68: 1afffffa bne 58 <more_fun+0x8> 
    6c: e8bd4010 pop {r4, lr} 
    70: e12fff1e bx lr 

Летучий решение, как вы можете видеть это довольно некрасиво он говорит, я хочу, чтобы вы на самом деле выйти и сенсорным таран каждый раз, когда вы используете эту переменную, прочитайте ее из ram, когда вы хотите что-то сделать с ней и запишите ее после каждого шага. Решение more_fun() не полагается на надежду на то, что компилятор почитает volatile, как вы надеялись (почему компилятор считает volatile на локальной, мертвой, переменной, кажется неправильной), вместо этого, если вы заставите компилятор вызвать внешнюю функцию (один который не находится в домене оптимизации и не может быть встроен в результат и, возможно, показывает мертвый код, если, например, dummy() не использует входную переменную). Будучи такой маленькой петлей, компилятор мог реализовать цикл или мог развернуть его, вы могли бы попросить его попытаться развернуть, если это имеет смысл, поэтому реализуйте его как цикл, поскольку он имеет выше или, возможно, реализует его как серию вызовов.

void more_fun (void) 
{ 
    dummy(0); 
    dummy(1); 
    dummy(2); 
    dummy(3); 
    dummy(4); 
} 

Красота всего этого заключается в том, что с бесплатными инструментами, такими как gnu, хотя и не лучшим компилятором, насколько самый быстрый/быстрый код (один размер подходит всем никому не подходит), он компилируется в объектный или двоичный и имеет дизассемблер, который будет разбирать оба объекта и двоичные файлы, чтобы вы могли играть с такими простыми функциями, как эти, и изучить, что делают параметры компиляции, и начать понимать, что такое мертвый код. Не стоит вам ничего, кроме времени.

Большинство людей, которые в некоторой степени справляются с этим волатильным решением, если вы пытаетесь сделать некоторую оптимизацию рук и начинаете медленно и наращивать, volatile будет бесполезно с вашими результатами, это не поможет вам, оно перегружает процессор в неестественным способом, чем если бы у вас его не было, вы могли бы придумать реальный код, который вызывает другие функции, находящиеся в цикле, чья производительность будет сильно отличаться и без изменчивости одной из переменных.

В любом случае бенчмаркинг одним словом является фиктивным, слишком простым для управления результатами, даже если он использует тот же самый точный исходный код на одном и том же компьютере с одним и тем же компилятором. Все, что имеет значение, - это ваша фактическая программа, которая выполняет вашу фактическую задачу, имеет эту производительность. Реализуйте это по-другому и измерьте, если это возможно, и добавьте некоторый запас и решите, что быстрее, и пойдите с ним, или, если примерно, пойдите с более легким для чтения и/или поддержания.

Смежные вопросы