Почему присваивание выполняется медленнее при неявном преобразовании?

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

Фон:

Я просто играл и обнаружил некоторое поведение, которое я не могу полностью объяснить... Для примитивных типов это похоже на то, что при неявном преобразовании оператор присваивания = занимает больше времени по сравнению с явным присваиванием.

int iTest = 0;
long lMax = std::numeric_limits<long>::max();
for (int i=0; i< 100000; ++i)
{
    // I had 3 such loops, each running 1 of the below lines.
    iTest = lMax;
    iTest = (int)lMax;
    iTest = static_cast<int>(lMax);
}

В результате приведение в стиле c и static_cast в стиле c++ в среднем выполняется одинаково (каждый раз различается, но видимой разницы нет). И они оба превосходят неявное назначение.

Result:
iTest=-1, lMax=9223372036854775807
(iTest = lMax) used 276 microseconds

iTest=-1, lMax=9223372036854775807
(iTest = (int)lMax) used 191 microseconds

iTest=-1, lMax=9223372036854775807
(iTest = static_cast<int>(lMax)) used 187 microseconds

Вопрос:

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

Спасибо!


person Ooops    schedule 26.03.2015    source источник
comment
Я предполагаю, что ваш бенчмаркинг ошибочен.   -  person Henrik    schedule 26.03.2015
comment
Попробуйте изменить порядок тестов. Может быть, это всегда первый, который занимает больше всего времени. Также кажется, что 100000 здесь слишком мало. Сделайте тесты длиннее.   -  person TonyK    schedule 26.03.2015


Ответы (2)


Если вы хотите знать, почему что-то происходит под одеялом, лучше всего искать... подождите... под одеялом.

Это означает изучение языка ассемблера, созданного вашим компилятором.

Среду C++ лучше всего рассматривать как абстрактную машину для выполнения кода C++. Стандарт (в основном) диктует поведение, а не детали реализации. Как только вы выходите за пределы стандарта и начинаете думать о том, что происходит внутри, исходный код C++ уже мало чем поможет — вам нужно изучить фактический код, который компьютер работает, материал выводится компилятором (обычно машинный код).

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

Было время много лун назад, когда компилятор VAX Fortran (я сказал много лун) превзошел своих конкурентов на несколько порядков в заданном тесте.

Именно по этой точной причине. Он определил, что результаты цикла не использовались, поэтому оптимизировал весь цикл.


Еще одна вещь, на которую вы, возможно, захотите обратить внимание, — это сами измерительные инструменты. Когда вы говорите о длительности 1/10 000th секунды, ваши результаты могут быть затоплены малейший шум.

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

Но суть в том, что результаты, которые вы видите, могут быть связаны с методологией измерения.

person paxdiablo    schedule 26.03.2015
comment
Среду C++ лучше всего рассматривать как виртуальную машину для выполнения кода C++. -- Эээ, нет, потому что это не... - person DevSolar; 26.03.2015
comment
@DevSolar, из C++11 1.9: семантические описания в этом международном стандарте определяют параметризованную недетерминированную абстрактную машину. Настоящий международный стандарт не предъявляет требований к структуре соответствующих реализаций. В частности, им не нужно копировать или эмулировать структуру абстрактной машины. Скорее, соответствующие реализации необходимы для эмуляции (только) наблюдаемого поведения абстрактной машины, как объяснено ниже. - person paxdiablo; 26.03.2015
comment
Хотя, по общему признанию, я неправильно запомнил цитату, поэтому я изменил ответ, чтобы использовать лучшую фразу «абстрактная машина». - person paxdiablo; 26.03.2015
comment
Я понимаю концепцию стандартной формулировки. Но хотя это помогает определить язык, в конкретной реализации нет ничего виртуального или абстрактного. Вот почему у меня проблема с терминологией VM. Далее мы вызываем непосредственно исполняемый машинный код байт-кодом, а ЦП - JIT-компилятором... ах, забудьте об этом. Хорошего дня! ;-) - person DevSolar; 26.03.2015
comment
Я использовал эту фразу, потому что реализация не была указана. Следовательно, это следует рассматривать как вопрос о самом С++, а не о какой-либо его реализации. попробую уточнить. - person paxdiablo; 26.03.2015
comment
Это эталон, я думаю. Когда время выполнения достигает уровня секунд, разница исчезает. Мне нужно поиграться со сборкой, я думаю. Кстати, -O0 был использован, поэтому цикл не оптимизируется компилятором (по крайней мере, моим компилятором), иначе не было бы разницы во времени выполнения. Спасибо за ответ! - person Ooops; 26.03.2015
comment
Спасибо за усилия и +1 вам. - person DevSolar; 26.03.2015

#include <limits>

int iTest = 0;
long lMax = std::numeric_limits<long>::max();

void foo1()
{
  iTest = lMax;
}

void foo2()
{
  iTest = (int)lMax;
}

void foo3()
{
  iTest = static_cast<int>(lMax);
}

Скомпилировано с GCC 5 с использованием -O3 дает:

__Z4foo1v:
    movq    _lMax(%rip), %rax
    movl    %eax, _iTest(%rip)
    ret

__Z4foo2v:
    movq    _lMax(%rip), %rax
    movl    %eax, _iTest(%rip)
    ret

__Z4foo3v:
    movq    _lMax(%rip), %rax
    movl    %eax, _iTest(%rip)
    ret

Они все одинаковые.

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

person user657267    schedule 26.03.2015