Разница между Debug/Release в C++ VS2012
От: ravik  
Дата: 03.01.19 12:40
Оценка:
Приветствую, коллеги! Не могу понять в чем проблема — в Debug все работает как надо, в Release — неправильно. Как выйти из ситуации — знаю, в чем причина — так и не пойму.

Есть класс с перегруженными операторами, тела которых в основном ассемлерные вставки. Писать их, а особенно отлаживать, было грустно: один из операторов (деления) зашкалил за несколько сотен строк. Естественно, хотелось сэкономить. Поэтому, когда по ходу выполнения оператора выяснялось, что можно переключиться на выполнение другого, я просто завершал работу его вызовом. Например:

class kint
{
    //...
public:
    //...
    kint  operator * (const kint& ki) const;
    kint  operator * (unsigned int) const;
    friend kint operator * (unsigned int ui, const kint& ki) { return ki * ui; };
    kint  operator * (int) const;
    friend kint operator * (int i, const kint& ki) { return ki * i; };
    //...
}


Как представлено, есть операция умножения kint на такой же kint. А можно умножить kint и на беззнаковое целое, чему посвящен второй по тексту перегруженный оператор. И если по ходу выполнения kint::operator* вдруг выясняется, что переданный по ссылке операнд типа kint вообще-то оказался беззнаковым целым, мне было влом вставлять дополнительную ветвь ассемблерного кода. Вот как это происходило:

kint kint::operator *(const kint& Operand) const
{
    kint res;
    unsigned int nCount;    //счетчик внутреннего цикла, равен числу блоков this
    unsigned int
        *pEsp,                //сохраненный указатель вершины стека
        *pStart,            //указатель на текущий блок this
        *pCurrent,            //указатель на текущий блок Operand
        *pStop;                //указатель на последний блок Operand
    __asm
    {
        mov pEsp, esp;            //сохраняем начальное значение указателя на вершину стека
        mov esi, this;
        mov ecx, [esi+m_uiPos];
        cmp ecx, 0;
        je QUIT;            //выход, если this = empty
        mov edx, ecx;            //делаем копию позиции вершины для последующего контроля за переполнением
        dec ecx;
        shr ecx, 5;
        jz OPERAND_ONE_32bit;        //this состоит всего из 1 блока - переход к простому умножению
        //... до-фига-до-фига кода с циклами
QUIT:
        mov esp, pEsp;
    };
    return res;
OPERAND_ONE_32bit:
    return Operand * this->m_arr[0];
OPERAND_TOO_32bit:
    return *this * Operand.m_arr[0];
OVERFLOW:
    throw L"Переполнение в операции умножения";
}


По коду видно, что управление передается по метке OPERAND_ONE_32bit, а там происходит вызов другого метода return Operand * this->m_arr[0];

Так вот, в режиме Debug работает как надо, а в Release внешний метод возвращает в код клиента пустой (сконструированный по умолчанию, нулевой) объект типа kint. Я вставил вместо предположительно бажной строки прямо блоком тело второго метода, но, блин, почему так выходит-то?
Re: Разница между Debug/Release в C++ VS2012
От: kov_serg Россия  
Дата: 03.01.19 13:20
Оценка: +2
Здравствуйте, ravik, Вы писали:

R>Приветствую, коллеги! Не могу понять в чем проблема — в Debug все работает как надо, в Release — неправильно. Как выйти из ситуации — знаю, в чем причина — так и не пойму.

Не используйте ассемблерные вставки.
Re[2]: Разница между Debug/Release в C++ VS2012
От: ravik  
Дата: 03.01.19 14:11
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, ravik, Вы писали:


R>>Приветствую, коллеги! Не могу понять в чем проблема — в Debug все работает как надо, в Release — неправильно. Как выйти из ситуации — знаю, в чем причина — так и не пойму.

_>Не используйте ассемблерные вставки.

Cпасибо за ответ! Не могу не использовать... Был обычный код практически на чистом C с массивами указателями и т.п. Работал недопустимо медденно. Там по коду видно, что я первой инструкцией сохраняю указатель стека, а на выходе восстанавливаю... Короче, я поднял производительность в 700 раз, поступиться таким достижением не всякий разработчик сможет.

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

Короче, интерес академический. Почему в Release компилятор не вставил вызов конструктора копирования? Я годами читаю форум, здесь ребята с огромным опытом, вдруг кто-то натыкался...
Re: Разница между Debug/Release в C++ VS2012
От: _NN_ www.nemerleweb.com
Дата: 03.01.19 17:12
Оценка:
Здравствуйте, ravik, Вы писали:

Для начала стоии понять почему недостаточно было добавить конструктор и операцию перемещения, а также расставить всякие компиляторо-специфические вещи типа __forceinline (MSVC).
Ну и noexcept расставить также помогает оптимизации.
Возможно ещё опции оптимизации не выбраны достаточно агрессивно .
А только потом уже обращаться к ассемблеру.

В общем если есть возможность привести минимально компилируемый пример в студию, можно будет помочь с его оптимизацией.
А то что где когда получается с тем , что у вас в происходит.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Разница между Debug/Release в C++ VS2012
От: kov_serg Россия  
Дата: 03.01.19 17:41
Оценка: +1
R>Не могу не использовать... Был обычный код практически на чистом C с массивами указателями и т.п. Работал недопустимо медденно. Там по коду видно, что я первой инструкцией сохраняю указатель стека, а на выходе восстанавливаю...
По мимо стека вы должны гарантировать сохранность еще ряду региcтров

R>Короче, я поднял производительность в 700 раз, поступиться таким достижением не всякий разработчик сможет.

700 раз да вы колдун! С https://gmplib.org сравнивали?

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


R>Короче, интерес академический. Почему в Release компилятор не вставил вызов конструктора копирования? Я годами читаю форум, здесь ребята с огромным опытом, вдруг кто-то натыкался...

Что мешает посмотреть сгенерированный код? Скорее всего он выкинул конструктор копирования за ненадобностью, предполагае несколько иное поведение, нежели реализованное вами.
Re[2]: Разница между Debug/Release в C++ VS2012
От: ravik  
Дата: 03.01.19 18:20
Оценка:
Здравствуйте, _NN_, Вы писали:

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

Своими замечаниями Вы натолкнули меня на мысль. Приведенный мной код возвращает переменную res(ult) пользовательского типа kint, продекларированную без инициализации. Там есть конструктор по умолчанию, когда я писал, все проверялось... У меня остался старый глючный код, в котором я сейчас объявил переменную с инициализацией: kint res(777); и запустил с данными, которые увели поток выполнения на возвращение не самой res, а результата работы другого метода. Потрясающе! Сборка в режиме Release вернула "три семерки"... Другими словами, дело именно что во встроенном оптимизаторе, и это тот вывод, который меня успокоил.

Потому что, если быть совсем честным, я сам виноват, что оптимизатор умыл руки. Не надо было строить код так, чтобы управление передавалось из ассемблерной вставки во внешний код по метке. Красивая иллюстрация, к чему может привести использование goto. Поленился добавлять ассемблерный код вызова метода и последующей очистки стека. Вперед наука. А Вам я очень признателен за потраченное время! Удачи в наступившем году!
Re[4]: Разница между Debug/Release в C++ VS2012
От: ravik  
Дата: 03.01.19 18:39
Оценка:
Здравствуйте, kov_serg, Вы писали:

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

В соседней ветке флейма разобрались, что случилось. Виноват оптимизатор, а правильней сказать, мои кривые руки, передававшие управление из ассемблера по метке во внешний код, и по-человечески объяснимая лень.

Удачи Вам в Новом году!
Re[3]: Разница между Debug/Release в C++ VS2012
От: landerhigh Пират  
Дата: 03.01.19 19:04
Оценка: +6
Здравствуйте, ravik, Вы писали:

R>Короче, я поднял производительность в 700 раз, поступиться таким достижением не всякий разработчик сможет.


Это явно указывает на изменение алгоритмической сложности, в связи с чем равновероятны два сценария:
1. Новый код делает не совсем то или даже совсем не то, что и старый
2. Старый код на ровном месте делает что-то лишнее, например, где-то накручено что-то вроде O(n^n)

Для решения обоих проблем использование ассемблера несколько преждевременно совершенно бессмысленно.
www.blinnov.com
Re[4]: Разница между Debug/Release в C++ VS2012
От: AndrewJD США  
Дата: 03.01.19 19:12
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>Это явно указывает на изменение алгоритмической сложности, в связи с чем равновероятны два сценария:

Изменение паттерна доступа к памяти и как следствие более эффективное использование кеша, тоже может дать ускорение на два порядка.

L>Для решения обоих проблем использование ассемблера несколько преждевременно совершенно бессмысленно.

+1
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[4]: Разница между Debug/Release в C++ VS2012
От: ravik  
Дата: 03.01.19 19:51
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>Здравствуйте, ravik, Вы писали:


R>>Короче, я поднял производительность в 700 раз, поступиться таким достижением не всякий разработчик сможет.


L>Это явно указывает на изменение алгоритмической сложности, в связи с чем равновероятны два сценария:

L>1. Новый код делает не совсем то или даже совсем не то, что и старый
L>2. Старый код на ровном месте делает что-то лишнее, например, где-то накручено что-то вроде O(n^n)

L>Для решения обоих проблем использование ассемблера несколько преждевременно совершенно бессмысленно.


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

Приведу пример. Представьте деление столбиком. Ручкой. На бумаге. Вы берете делитель и пытаетесь подобрать такой множитель, чтобы результат произведения был подходящий под разовое вычитание результата умножения из старших разрядов делимого, число которых тоже приходится определять параллельно с подбором. В какой момент вы понимаете, что, скажем, множитель 7 мало, а 9 — много? В старом коде производилось полное вычисление результата умножения, потом сравнивалось и отбраковывалось. А в новом коде умножение делается неполным, для чего умножение делается задом-наперед, начиная не с младших байтов, а со старших. В подавляющем числе случаев для оценки, попадет результат умножения в разрядность или нет, достаточно произвести умножение старших разрядов операндов, умещающихся в стандартный регистр.

Да, я забыл сказать, что в проекте операции производится не со встроенными целочисленными типами, поддерживаемые процессором, а с числами, запись которых в десятичных знаках превышает 100 символов и более. У меня есть образцы кода, где я еще еще поднял скорость — ну не в разы, а еще на несколько десятков процентов — но, как говорится, покойничку и так хватило. Пользуясь вышеприведенным примером, это когда у вас в результате деления цифры повторяются, промежуточное умножение делается только в первый раз.
Re[5]: Разница между Debug/Release в C++ VS2012
От: watchmaker  
Дата: 03.01.19 21:54
Оценка:
Здравствуйте, ravik, Вы писали:

R>Приведу пример. Представьте деление столбиком. Ручкой. На бумаге. Вы берете делитель и пытаетесь подобрать такой множитель, чтобы результат произведения был подходящий под разовое вычитание результата умножения из старших разрядов делимого, число которых тоже приходится определять параллельно с подбором. В какой момент вы понимаете, что, скажем, множитель 7 мало, а 9 — много? В старом коде производилось полное вычисление результата умножения, потом сравнивалось и отбраковывалось.

Всё же верно тебе говорят, что "чудодейственная сила ассемблера" тут ни при чём. landerhigh выше прямо оба пункта угадал: и алгоритм был другой и в старом коде делались лишние операции.

R> В какой момент вы понимаете, что, скажем, множитель 7 мало, а 9 — много? В старом коде производилось полное вычисление результата умножения, потом сравнивалось и отбраковывалось.

Так а зачем это делалось? Можно было бы точно также и из кода на C/C++ эти действия убрать, не переписывая на ассемблер. Ведь для алгоритма деления столбиком это не нужно.
То есть взять, например, классическое описание Кнутом этого алгоритма и реализовать его.
А ещё лучше не самому реализовывать, а взять gmp, где эта задача давно решена и решена хорошо.

Кстати говоря, в gmp доступны как реализация этих алгоритмом на C, так и переписанные на различные ассемблеры под различные архитектуры. Их забавно на производительность сравнивать. Только там никакой речи о стократном ускорении нет: выжимают проценты для тех, кому это важно. Что ещё раз подтверждает, что хороший алгоритм важнее низкоуровневых оптимизаций.


R>Как бы объяснить... Дело в том, что высокоуровневый язык не поддерживает операции с битами

Это про какой высокоуровневый язык речь? В C/C++ то поддержка битовых операций всё же скорее есть, чем нет :)
Можно, конечно, согласится, что не все аппаратные возможности отображены и доступны явно (например, как всякие там parity-биты из регистра флагов на x86), но для алгоритма деления эта экзотика всё равно малополезна.
Re[6]: Разница между Debug/Release в C++ VS2012
От: ravik  
Дата: 04.01.19 07:03
Оценка:
Здравствуйте, watchmaker, Вы писали:

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

Пример деления столбиком — это абстрактный пример, приведенный для иллюстрации. В реальном проекте используется тип данных, которые, конечно, можно считать натуральными числами, но это последовательности. А арифметические операции, для поддержки которых применяются перегруженные операторы, введены для поддержки иллюзии, что этим можно как-то управлять. В реальности это не прямая арифметика.
Тем не менее. Вот смотрите. Меня кое-что заинтересовало.

C1_1:    mov ecx, 31;
    sub ecx, BhbR;
    shld edx, eax, cl;
    shld eax, ebx, cl;
    mov ebx, divd32;
    cmp edx, ebx;
    jb C1_2;
    shrd eax, edx, 1;
    shr edx, 1;
C1_2:    div ebx;


В приведенном участке кода в регистры EDX, EAX, EBX загружены три старших 4-байтовых блока операнда. После чего вся эта гирлянда сдвигается до упора влево таким образом, чтобы старший значащий разряд операнда оказался в старшем разряде регисnра EDX. После чего в EBX подаются старшие 32 разряда делителя. Непосредственно перед делением производится контроль, не вызовет ли операция деления переполнения, и если это так, производится коррекция. После чего по метке C1_2 деление таки происходит.

У меня, конечно, есть представление, что на C/C++ можно реализовать что угодно, но вот этот финт из десятка инструкций процессора заменил цикл вызовов методов, которые сами вызывали другие методы... Так что чуда нет. Я со всеми вами согласен, и спорить здесь ни с кем не хочется.
Re[7]: Разница между Debug/Release в C++ VS2012
От: _NN_ www.nemerleweb.com
Дата: 04.01.19 08:45
Оценка: +2
Здравствуйте, ravik, Вы писали:

Вы недооцениваете оптимизации компилятора.
Если правильно расставить constexpr, noexcept, определить операции перемещения и использовать соответствующие ключи компиляции, то результат зачастую превзойдёт ваши ожидания.

Конечно имеются моменты где этого недостаточно, но я бы не стал бежать в ассемблер не выжав максимум из того что есть.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Разница между Debug/Release в C++ VS2012
От: Zhendos  
Дата: 04.01.19 09:48
Оценка:
Здравствуйте, ravik, Вы писали:


R>
R>C1_1:    mov ecx, 31;
R>    sub ecx, BhbR;
R>    shld edx, eax, cl;
R>    shld eax, ebx, cl;
R>    mov ebx, divd32;
R>    cmp edx, ebx;
R>    jb C1_2;
R>    shrd eax, edx, 1;
R>    shr edx, 1;
R>C1_2:    div ebx;
R>


R>В приведенном участке кода в регистры EDX, EAX, EBX загружены три старших 4-байтовых блока операнда. После чего вся эта гирлянда сдвигается до упора влево таким образом, чтобы старший значащий разряд операнда оказался в старшем разряде регисnра EDX. После чего в EBX подаются старшие 32 разряда делителя. Непосредственно перед делением производится контроль, не вызовет ли операция деления переполнения, и если это так, производится коррекция. После чего по метке C1_2 деление таки происходит.


R>У меня, конечно, есть представление, что на C/C++ можно реализовать что угодно, но вот этот финт из десятка инструкций процессора заменил цикл вызовов методов, которые сами вызывали другие методы... Так что чуда нет. Я со всеми вами согласен, и спорить здесь ни с кем не хочется.


А можете привести этот участок в виде функции на C/C++, интересно что icc сгенерирует?
Re[5]: Разница между Debug/Release в C++ VS2012
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 04.01.19 10:08
Оценка:
Здравствуйте, ravik, Вы писали:

R>в проекте операции производится не со встроенными целочисленными типами, поддерживаемые процессором, а с числами, запись которых в десятичных знаках превышает 100 символов и более.


Готовых реализаций такой арифметики — выше крыши, хоть оптимизированных, хоть в лоб. Достаточно было поискать.
Re[3]: Разница между Debug/Release в C++ VS2012
От: T4r4sB Россия  
Дата: 04.01.19 10:13
Оценка: +1
Здравствуйте, ravik, Вы писали:

R>Короче, я поднял производительность в 700 раз, поступиться таким достижением не всякий разработчик сможет.


Я уверен, что дело тут не в ассемблере, а в низком качестве изначального С++ кода.
Re[7]: Разница между Debug/Release в C++ VS2012
От: T4r4sB Россия  
Дата: 04.01.19 10:22
Оценка:
Здравствуйте, ravik, Вы писали:


R>
R>C1_1:    mov ecx, 31;
R>    sub ecx, BhbR;
R>    shld edx, eax, cl;
R>    shld eax, ebx, cl;
R>    mov ebx, divd32;
R>    cmp edx, ebx;
R>    jb C1_2;
R>    shrd eax, edx, 1;
R>    shr edx, 1;
R>C1_2:    div ebx;
R>


R>В приведенном участке кода в регистры EDX, EAX, EBX загружены три старших 4-байтовых блока операнда. После чего вся эта гирлянда сдвигается до упора влево таким образом, чтобы старший значащий разряд операнда оказался в старшем разряде регисnра EDX. После чего в EBX подаются старшие 32 разряда делителя. Непосредственно перед делением производится контроль, не вызовет ли операция деления переполнения, и если это так, производится коррекция. После чего по метке C1_2 деление таки происходит.


R>У меня, конечно, есть представление, что на C/C++ можно реализовать что угодно, но вот этот финт из десятка инструкций процессора заменил цикл вызовов методов, которые сами вызывали другие методы...


Я не знаю, что было в С++, но можно ж было написать примерно так, да?
  int32_t ecx = 31-BhbR
  int32_t neax = (eax << ecx) + (ebx >> (32-ecx));
  int32_t nedx = (edx << ecx) + (eax >> (32-ecx));
  eax = neax;
  edx = nedx;
  ebx = didv32;
  if (edx<ebx) {
    eax = (eax >> 1) + (edx << 31);
    edx = edx >> 1;
  }

  eax =  eax / ebx;
Re[5]: Разница между Debug/Release в C++ VS2012
От: landerhigh Пират  
Дата: 04.01.19 12:33
Оценка:
Здравствуйте, AndrewJD, Вы писали:

L>>Это явно указывает на изменение алгоритмической сложности, в связи с чем равновероятны два сценария:

AJD>Изменение паттерна доступа к памяти и как следствие более эффективное использование кеша, тоже может дать ускорение на два порядка.

Вполне может быть, но своим опытом пока ни подтвердить, ни опровергнуть не могу.
www.blinnov.com
Re[6]: Разница между Debug/Release в C++ VS2012
От: _NN_ www.nemerleweb.com
Дата: 04.01.19 12:46
Оценка: 1 (1)
Здравствуйте, landerhigh, Вы писали:

L>Вполне может быть, но своим опытом пока ни подтвердить, ни опровергнуть не могу.

Классическая задачка на перебор двумерного/многомерного массива.
Можете замерить разницу между перебором по столбцам или по строкам.

http://www.drdobbs.com/parallel/cache-friendly-code-solving-manycores-ne/240012736
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[8]: Разница между Debug/Release в C++ VS2012
От: ravik  
Дата: 04.01.19 14:16
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>Здравствуйте, ravik, Вы писали:



R>>
R>>C1_1:    mov ecx, 31;
R>>    sub ecx, BhbR;
R>>    shld edx, eax, cl;
R>>    shld eax, ebx, cl;
R>>    mov ebx, divd32;
R>>    cmp edx, ebx;
R>>    jb C1_2;
R>>    shrd eax, edx, 1;
R>>    shr edx, 1;
R>>C1_2:    div ebx;
R>>


R>>В приведенном участке кода в регистры EDX, EAX, EBX загружены три старших 4-байтовых блока операнда. После чего вся эта гирлянда сдвигается до упора влево таким образом, чтобы старший значащий разряд операнда оказался в старшем разряде регисnра EDX. После чего в EBX подаются старшие 32 разряда делителя. Непосредственно перед делением производится контроль, не вызовет ли операция деления переполнения, и если это так, производится коррекция. После чего по метке C1_2 деление таки происходит.


R>>У меня, конечно, есть представление, что на C/C++ можно реализовать что угодно, но вот этот финт из десятка инструкций процессора заменил цикл вызовов методов, которые сами вызывали другие методы... Так что чуда нет. Я со всеми вами согласен, и спорить здесь ни с кем не хочется.


Z>А можете привести этот участок в виде функции на C/C++, интересно что icc сгенерирует?


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

        BYTE tmp = (unsigned char)0x00;
        while ( r >= b && r.m_number > 0)
        {
            r -= b;
            ++tmp;
        };


Это фрагмент типа эдакого деления. На самом деле на каждой итерации ищется сочетание полей переменной r пользовательского типа и некоторого шаблона, который сам может динамически и скачкообразно измениться. Все приведенные арифметические операторы и операторы сравнения перегружены, то есть компилятор вызывает другие методы, а там внутри тоже может попасться какой-нибудь вызов. Что делает этот код? Он берет вершину "числа" (на самом деле это закодированная структура) и помаленечку от не "откусывает" порцию-константу (с некоторым приближением это "делитель") — наблюдая, не произойдет ли совпадения с шаблоном (r.m_number > 0).

Для прикладника упоминаемого проекта идея, запечатленная в этом куске кода очень наглядна. "Деление" — это метафора проекта. А с точки зрения производительности — полная катастрофа. Я предложил подрихтовать способ контроля за шаблоном, практически объединив перегрузки операторов и контроль шаблона в одну процедуру. Там около 1 тыс. ассемблерных инструкций. Так что простите душевно, для анализа icc моего энтузиазма не хватило.

Еще раз. У меня такое ощущение, что вопрос поднятия производительности С/C++ в 700 раз при помощи ассемблера, приобретает оттенок религии. Дайте мне кто-нибудь пистолет, и я первым пристрелю заявившего, что "серебрянная пуля" есть.

Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.