Производительность оператора | против операторов + - PullRequest
2 голосов
/ 01 июня 2011

Есть ли существенная разница между | и + что повлияет на производительность кода в долгосрочной перспективе? или оба O (1)? код, с которым я работаю, выглядит примерно так:

uint64_t dostuff(uint64_t a,uint64_t b){
        // the max values of the inputs are 2^32 - 1

        // lots of stuff involving boolean operators
        // that have no way of being substituted by 
        // arithmetic operators

        return (a << 32) + b;
        //or
        return (a << 32) | b;
}

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

Ответы [ 8 ]

5 голосов
/ 01 июня 2011

Нет разницы в производительности на любом современном компьютере.

Однако оба оператора имеют разное значение.Если бит уже установлен, | ничего не сделает, но + очистит бит и все последующие ненулевые биты и установит следующий нулевой бит на 1.

3 голосов
/ 01 июня 2011

Оба, безусловно, O (1), поскольку O (1) означает константу.Вероятно, они не одинаковы.Обозначение Big Oh предназначено для понимания асимптотического поведения, независимого от констант. Всегда профиль, прежде чем оптимизировать.Вы очень быстро узнаете, что время не тратится там, где вы думаете. Всегда !

2 голосов
/ 01 июня 2011

Использование |.

+ может только добавить к времени работы по очевидным причинам.

1 голос
/ 02 июня 2011

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

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

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

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

1 голос
/ 01 июня 2011

Лучший ответ здесь - не пытаться предсказать, какой из них лучше, а тестировать его или проверять код сборки.Я предполагаю, что оба будут оптимизированы под одну и ту же инструкцию, и в любом случае число циклов ЦП, занятых обоими, может быть равным.

Но я настоятельно рекомендую вам проверить ASM и сравнить оба решения.

1 голос
/ 01 июня 2011

Оба являются одной инструкцией.Что касается времени распространения электроники, не знаю, какой из них быстрее.

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

0 голосов
/ 02 июня 2011

Это зависит от платформы (и, вероятно, зависит от компилятора).На SPU на PS3 динамическое ИЛИ довольно дорого, если я правильно помню.Я не уверен в цифрах, но думаю, что в конечном итоге это делится на несколько операций, в результате чего стоимость увеличивается до нескольких инструкций.На x86 / x64 или на большинстве современных CISC вполне вероятно, что любая из них - это всего лишь одна инструкция, и очень маловероятно, что она приведет к остановке конвейера или другим дорогостоящим операциям.

Редактировать: причина стоимости в том, что CellПроцессор имеет только один регистр общего назначения, что означает, что он не может загружать обе переменные в стандартные регистры и выполнять оптимизацию.Вместо этого значения должны быть загружены в набор регистров altivec, где должна быть выполнена операция, затем результат должен быть извлечен из регистров altivec в gpr по маске для получения результата.

Если вы переносите эти операции на PS3 или графический процессор на любом современном компьютере, возможно, вы захотите посмотреть, как эти процессоры ведут себя.У GPU также могут быть похожие проблемы, поскольку они также являются RISC-процессорами, предназначенными для SIMD-операций.

0 голосов
/ 01 июня 2011

| и '+ `являются различными математическими операциями.
Учитывая уравнения:

  unsigned int y = 2 + 2;
  unsigned int z = 2 | 2;

даст разные ответы.

Технически,` |'Операция происходит быстрее, поскольку она использует только вентили ИЛИ внутри процессора.Операция сложения требует больше ворот.

Производительность, достигнутая с помощью '|'«+» обычно теряется на время, необходимое для извлечения данных в процессор и из него.Другими словами, чистая производительность незначительна.(Разница во времени обычно находится в диапазоне наносекунд.)

Однако время обслуживания между двумя формами может быть больше.Когда кто-то нуждается в арифметике, а не в хитросплетении битов (или наоборот), попытка найти эту ошибку во время выполнения может быть большой.

Используйте соответствующий оператор для правильной цели.Дайте группам тестирования и обслуживания перерыв.Этот вид микрооптимизации не стоит.

...