Компилятор силы для не оптимизации операторов побочного эффекта меньше

Основанное на JavaScript приложение нес открытым исходным кодом довольно глупо. JavaScript является клиентским интерпретируемым языком.. Путаница не является большой защитой..

путаница JS обычно делается, чтобы уменьшить размер сценария, вместо того, чтобы "защитить" его. Если Вы находитесь в ситуации, где Вы не хотите, чтобы Ваш код был общедоступен, JavaScript не является правильным языком..

существует много инструментов вокруг, но большинство имеет слово "компрессор" (или "minifier") на его имя по причине..

11
задан GManNickG 20 July 2009 в 09:52
поделиться

10 ответов

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

int float_to_int(float f)
{
    return static_cast<int>(f); // has no side-effects
}

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

4
ответ дан 3 December 2019 в 02:11
поделиться

Назначение переменной volatile никогда не следует оптимизировать, поэтому это может дать вам желаемый результат:

static volatile int i = 0;

void float_to_int(float f)
{
    i = static_cast<int>(f); // has no side-effects
}
9
ответ дан 3 December 2019 в 02:11
поделиться

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

int float_to_int(float f)
{
   return static_cast<int>(f);
}

Затем ваш вызывающий код может выполнить его с помощью printf, чтобы гарантировать, что он не оптимизирует его. Также убедитесь, что float_to_int находится в отдельном модуле компиляции, чтобы компилятор не мог использовать какие-либо трюки.

extern int float_to_int(float f)
int sum = 0;
// start timing here
for (int i = 0; i < 1000000; i++)
{
   sum += float_to_int(1.0f);
}
// end timing here
printf("sum=%d\n", sum);

Теперь сравните это с пустой функцией, например:

int take_float_return_int(float /* f */)
{
   return 1;
}

Которая также должна быть внешней.

Разница во времени должна дать вы имеете представление о стоимости того, что вы пытаетесь измерить.

6
ответ дан 3 December 2019 в 02:11
поделиться

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

Вы по определению искажаете результаты.

Вот как решить проблему попытки профилировать "фиктивный" код, который вы написали только для test: Для профилирования сохраните результаты в глобальном / статическом массиве и распечатайте один член массива на выходе в конце программы. Компилятор не сможет оптимизировать из вычислений, которые помещают значения в массив, но вы все равно получите любые другие оптимизации, которые он может внести, чтобы сделать код быстрым.

7
ответ дан 3 December 2019 в 02:11
поделиться

То, что всегда работало на всех компиляторах, которые я использовал до сих пор:

extern volatile int writeMe = 0;

void float_to_int(float f)
{    
  writeMe = static_cast<int>(f); 
}

обратите внимание, что это искажает результаты, методы boith должны записывать в writeMe .

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

extern volatile float readMe = 0;
extern volatile int writeMe = 0;

void float_to_int(float f)
{    
  writeMe = static_cast<int>(f); 
}

int main()
{
  readMe = 17;
  float_to_int(readMe);
}

Тем не менее, все оптимизации между чтением и записью могут применяться «в полную силу». Чтение и запись в глобальную переменную часто являются хорошими «препятствиями» при проверке сгенерированной сборки.

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

3
ответ дан 3 December 2019 в 02:11
поделиться

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

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

2
ответ дан 3 December 2019 в 02:11
поделиться

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

добавив фиктивный + = i; не проблема, если вы сохраните тот же фрагмент кода и в альтернативном профиле. (Итак, код, с которым вы его сравниваете).

И последнее, но не менее важное: сгенерируйте asm-код. Даже если вы не можете кодировать в asm, сгенерированный код обычно понятен, поскольку за ним будут метки и закомментированный код C. Итак, вы знаете (sortoff), что происходит и какие биты сохраняются.

R

ps тоже обнаружил:

 inline float pslNegFabs32f(float x){
       __asm{
         fld  x //Push 'x' into st(0) of FPU stack
         fabs
         fchs   //change sign
         fstp x //Pop from st(0) of FPU stack
        }
       return x;
 } 

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

2
ответ дан 3 December 2019 в 02:11
поделиться

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

0
ответ дан 3 December 2019 в 02:11
поделиться

GCC 4 теперь выполняет множество микрооптимизаций, которых GCC 3.4 никогда не делал. GCC4 включает в себя векторизатор дерева, который, оказывается, очень хорошо использует преимущества SSE и MMX. Он также использует библиотеки GMP и MPFR, чтобы помочь в оптимизации вызовов таких вещей, как sin () , fabs () и т. Д., А также для оптимизации таких вызовов их FPU, SSE. или 3D сейчас! эквиваленты.

Я знаю, что компилятор Intel также чрезвычайно хорош в такого рода оптимизации.

Я предлагаю не беспокоиться о таких микрооптимизациях, как эта - на относительно новом оборудовании (все, что было создано за последние 5 или 6 лет ), они почти полностью спорные.

Редактировать: На последних процессорах FPU ' Инструкция s fabs намного быстрее, чем приведение к int и битовой маске, а инструкция fsin обычно будет быстрее, чем предварительное вычисление таблицы или экстраполяция Серия Тейлора. Многие оптимизации, которые вы найдете, например, в «Уловках гуру игрового программирования», совершенно спорны и, как указано в другом ответе, потенциально могут быть медленнее, чем инструкции в FPU и в SSE.

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

Все подробности см. В руководствах по программированию процессоров AMD и Intel.

а инструкция fsin обычно выполняется быстрее, чем предварительное вычисление таблицы или экстраполяция ряда Тейлора. Многие оптимизации, которые вы найдете, например, в «Уловках гуру игрового программирования», совершенно спорны и, как указано в другом ответе, потенциально могут быть медленнее, чем инструкции в FPU и в SSE.

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

Все подробности см. В руководствах по программированию процессоров AMD и Intel.

а инструкция fsin обычно выполняется быстрее, чем предварительное вычисление таблицы или экстраполяция ряда Тейлора. Многие оптимизации, которые вы найдете, например, в «Уловках гуру игрового программирования», совершенно спорны и, как указано в другом ответе, потенциально могут быть медленнее, чем инструкции в FPU и в SSE.

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

Все подробности см. В руководствах по программированию процессоров AMD и Intel.

полностью спорны и, как указано в другом ответе, потенциально могут быть медленнее, чем инструкции в FPU и в SSE.

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

Все подробности см. В руководствах по программированию процессоров AMD и Intel.

полностью спорны и, как указано в другом ответе, потенциально могут быть медленнее, чем инструкции в FPU и в SSE.

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

Все подробности см. В руководствах по программированию процессоров AMD и Intel.

0
ответ дан 3 December 2019 в 02:11
поделиться

Вернуть значение?

int float_to_int(float f)
{
    return static_cast<int>(f); // has no side-effects
}

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

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

1
ответ дан 3 December 2019 в 02:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: