2012-03-09 3 views
4

Я заметил это случайно однажды, и теперь решил тщательно его протестировать.Почему const int быстрее const int &?

Так что, когда я вызвать функцию:

#define Type int 
#define Prm const Type & 
Type testfunc1(Prm v1, Prm v2, Prm v3, Prm v4, Prm v5, Prm v6, Prm v7, Prm v8, Prm v9, Prm v10){ 
    return (v1|v2|v3|v4|v5|v6|v7|v8|v9|v10); 
} 

100 миллион раз:

 for(Type y = 0; y < 10000; y++){ 
      for(Type x = 0; x < 10000; x++){ 
       out |= testfunc1(x,y,x,x,y,y,x,y,x,y); 
      } 
     } 

С типами int, const int и const int &, я заметил, что const int быстрее, чем const int &. (Примечание: im использует возвращаемое значение, чтобы гарантировать, что функция не будет оптимизирована).

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

Мои тесты:

const int: 7.95s 
const int &: 10.2s 

Edit: Я думаю, что это на самом деле из-за моей архитектуры; Я тестировал с Sint64 типа и результаты были:

const Sint64: 17.5s 
const Sint64 &: 16.2s 

Edit2: Или это? Испытано с double типа (который является 64-битной?), И результаты заставляют меня озадачило:

const double: 11.28s 
const double &: 12.34s 

Edit3: обновлен код цикла, чтобы соответствовать моим новейшие тесты с типами 64-битных.

+2

Использование возвращаемого значения, как и вы, не гарантирует, что он не будет оптимизирован. Как и все вычисления могут быть выполнены во время компиляции, поэтому компилятор может оптимизировать все, заменив циклы просто «0x3FFF». –

+0

Мне будет интересен ответ на этот вопрос. Может быть, что const int обрабатывается по-разному с помощью пролог-кода функции (помещается компилятором), чем const int &. Я принимаю обоснованное предположение. – octopusgrabbus

+0

@ R.MartinhoFernandes, ну, если бы он оптимизировал его, он не выполнил бы его за 7,95 секунды;) не говоря уже о том, что мой компилятор не уверен в этом умном (ему удалось оптимизировать его, только если я дал постоянные значения для параметров) , – Rookie

ответ

9

Поместив в аргумент &, вы добавляете в программу больше кода.Без &, эта последовательность:

push values 
call Function 
pop values <- usually an update to stack pointer 

и функции:

return sp[arg1] | sp[arg2] | etc <- value read direct from stack. 

Добавление '&' делает это:

push address of value1 
push address of value2 
etc 
call Function 
pop values <- usually an update to stack pointer 

и функции:

return_value = 0; 
address = sp[arg1] 
or return_value, [address] 
address = sp[arg2] 
or return_value, [address] 
etc 
return return_value 

Итак, как вы можете видеть, & добавляет много. Так зачем использовать его? Если у вас очень большой объект, передача указателя более оптимальна, чем копирование объекта в стек.

+3

Я также должен добавить, что приведенное выше является общим описанием. Оптимизаторы могут помещать значения в регистры, а не в стек. Компиляторы IA64 также могут помещать аргументы в регистры. – Skizz

+0

плюс 1 для упоминания регистров. –

7

Этот результат сильно зависит от системы. Это указывает на то, что на вашей конкретной системе копирование значения ссылки (которое, скорее всего, реализовано как указатель) имеет более высокую стоимость, чем копирование значения целого числа. Наиболее вероятной причиной этого различия является то, что для вашего целого требуется 32 бита для представления, а вашему представлению указателя/ссылки требуется 64 бит. EDIT Это не говоря уже о стоимости , обращаясь к целым числам: получение их значений потребует дополнительной косвенности. Поскольку вы передаете только два элемента, использование кеширования скрывает дополнительную стоимость в значительной степени, но стоимость там.

Вы абсолютно правы в более крупных типах: передавая ссылку на, скажем, большой struct или vector<...>, по-прежнему требуется только 64 бит (или что бы то ни было в вашей системе), независимо от количества элементов вашей структуры имеет или сколько предметов находится у вашего vector<...>. Чем больше структура, тем выше затраты, чтобы передать ее по стоимости, и, следовательно, экономия, которую вы понимаете, сделав ее ссылкой.

+3

Даже если указатель требует только 32 бита, доступ к фактическому значению int потребует одной косвенности, которая может учитывать разницу. –

+2

Даже если копирование 'int' было дороже, чем копирование адреса, эталонная версия также включает операцию косвенной выборки памяти, которая, вероятно, равна стоимости копирования' int'. –

+1

@ R.MartinhoFernandes Вы правы, есть стоимость косвенности. Тест в OP структурирован таким образом, чтобы скрыть эту стоимость несколько, потому что он будет передавать адреса только двух переменных вместо десяти, поэтому восемь косвенных доступов будут обслуживаться кешем, но вы правы, стоимость остается там. – dasblinkenlight

1

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

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

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