Ответ: Немного не в тему, а может и вовсе не в тему.
(«Телесистемы»: «Конференция «Микроконтроллеры и их применение»»)

миниатюрный аудио-видеорекордер mAVR

Отправлено trainer 23 апреля 2003 г. 23:16
В ответ на: Господа! Прошу уделить некоторое время и дать свою оценку, поправку и т.д. отправлено ShiphT 23 апреля 2003 г. 15:10

Данное сообщение должно было бы быть озаглавлено примерно так: "Даешь оптимизацию!" :)
Предлагаю всем желающим проверить качество оптимизации кода, выполняемой используемыми компиляторами.
Сразу должен сказать:
1) Я не имею никакого отношения к данному тесту;
2) Если данные тест уже публиковался в данной конференции - не обессудьте, поиск не является сильной стороной данной конференции;
3) Данный тест не дает количественной оценки качества оптимизации, результаты данного теста являются только лишь справочными;
4) Данный тест в оригинале предназначен для архитектуры 80x86 и, возможно, не учитывает какие-то приемы оптимизации, используемые в компиляторах для других архитектур;
5) Я публикую данный тест в том виде, в каком он попал ко мне. Отличие от оригинала не исключается.
А вот и он(тест) собственной персоной:



/* ---------------------------------------------------------- *
¦ ¦
¦ Серия тестов PC Tech Journal ¦
¦ Тест оптимизации кода Си ¦
¦ ¦
¦ Copyright (c) 1988 Ziff-Devis Publishing Company ¦
¦ ¦
¦ Эта программа-тест была разработана для проверки ¦
¦ методов оптимизации кода, применяемых компилятором ¦
¦ Си. Она не вырабатывает разумные результаты и не ¦
¦ представляет хороший стиль программирования. ¦
¦ ¦
* ---------------------------------------------------------- */


#include
/*#include */
#define max_vector 2
#define constant5 5

typedef unsigned char uchar;

int i, j, k, l, m;
int i2, j2, k2;
int g3, h3, i3, k3, m3;
int i4, j4;
int i5, j5, k5;

double flt_1, flt_2, flt_3, flt_4, flt_5, flt_6;

int ivector[ 3 ];
uchar ivector2[ 3 ];
short ivector4[ 6 ];
int ivector5[ 100 ];

#ifndef NO_PROTOTYPES
void dead_code( int, char * );
void unnecessary_loop( void );
void loop_jamming( int );
void loop_unrolling( int );
int jump_compression( int, int, int, int, int );
#else
void dead_code();
void unnecessary_loop();
void loop_jamming();
void loop_unrolling();
int jump_compression();
#endif

/* следующую строку раскомментировать ТОЛЬКО ЕСЛИ копилятор выдает ошибку,
предупреждающую о делении на 0 в двух строках, расположенных сразу после
комментария, помеченного как №1 */
/* #define NO_ZERO_DIVIDE 1 */

int main( argc, argv ) /* optbench */
int argc;
char **argv;
{
/* ---------------------------- *
¦ Размножение констант и копий ¦
*------------------------------*/
j4 = 2;
if( i2 < j4 && i4 < j4 )
i2 = 2;

j4 = k5;
if( i2 < j4 && i4 < j4 )
i5 = 3;

/* ------------------------------------------ *
¦ Свертка констант, арифметические тождества ¦
¦ и излишние операции загрузки/сохранения ¦
* ------------------------------------------ */

i3 = 1 + 2;
flt_1 = 2.4 + 6.3;
i2 = 5;
j2 = i + 0;
k2 = i / 1;
i4 = i * 1;
i5 = i * 0;

#ifndef NO_ZERO_DIVIDE
/* Комментарий №1
* Некоторые компиляторы распознают ошибку
* деления на нуль и не генерируют объектный код
*/
i2 = i / 0;
flt_2 = flt_1 / 0.0;
#else
printf( "This compiler handles divide-by-zero as an error\n");
#endif
flt_3 = 2.4 / 1.0;
flt_4 = 1.0 + 0.0000001;
flt_5 = flt_6 * 0.0;
flt_6 = flt_2 * flt_3;

/* -------------------- *
¦ Лишнее присваивание ¦
* -------------------- */

k3 = 1;
k3 = 1;

/* ------------------ *
¦ Снижение мощности ¦
* ------------------ */

k2 = 4 * j5;
for( i = 0; i <= 5; i++ )
ivector4[ i ] = i * 2;

/* ------------- *
¦ Простой цикл ¦
* ------------- */

j5 = 0;
k5 = 10000;
do {
k5 = k5 - 1;
j5 = j5 + 1;
i5 = (k5 * 3) / (j5 * constant5);
} while ( k5 > 0 );

/* -------------------------------------- *
¦ Управление переменной индукции цикла ¦
* -------------------------------------- */
for( i = 0; i < 100; i++ )
ivector5[ i * 2 + 3 ] = 5;

/* ----------------------- *
¦ Глубокие подвыражения ¦
* ----------------------- */

if( i < 10 )
j5 = i5 + i2;
else
k5 = i5 + i2;

/* ------------------------------------------------ *
¦ Проверка того, как компилятор генерирует адрес ¦
¦ переменной с константным индексом, размножает ¦
¦ копии и регистры ¦
* ------------------------------------------------ */

ivector[ 0 ] = 1; /* генерация константного адреса */
ivector[ i2 ] = 2; /* значение i2 должно быть скопировано*/
ivector[ i2 ] = 2; /* копирование регистров */
ivector[ 2 ] = 3; /* генарация константного адреса */

/* ----------------------------- *
¦ Удаление общих подвыражений ¦
* ----------------------------- */

if(( h3 + k3 ) < 0 || ( h3 + k3 ) > 5 )
printf("Common subexpression elimination\n");
else {
m3 = ( h3 + k3 ) / i3;
g3 = i3 + (h3 + k3);
}
/* -------------------------------------- *
¦ Вынесение инвариантного кода ¦
¦ (j * k) может быть вынесено из цикла ¦
* -------------------------------------- */

for( i4 = 0; i4 <= max_vector; i4++)
ivector2[ i4 ] = j * k;

/* ----------------------------- *
¦ Вызов функции с аргументами ¦
* ----------------------------- */

dead_code( 1, "This line should not be printed" );

/* ------------------------------ *
¦ Вызов функции без аргументов ¦
* ------------------------------ */

unnecessary_loop();

} /* Конец функции main */


/* ------------------------------------------------------ *
¦ Функция: dead_code ¦
¦ Проверка недостижимого кода и лишних ¦
¦ присваиваний. Не должен генерироваться код. ¦
* ------------------------------------------------------ */

void dead_code( a, b )
int a;
char *b;
{
int idead_store;

idead_store = a;
if( 0 )
printf( "%s\n", b );
} /* Конец dead_code */


/* ---------------------------------------------------- *
¦ Функция: unnecessary_loop ¦
¦ Цикл в следующей функции ненужен, так как ¦
¦ значение присваивания постоянно. В идеале ¦
¦ цикл должен быть удален. ¦
* ---------------------------------------------------- */

void unnecessary_loop()
{
int x;

x = 0;
for( i = 0; i < 5; i++ ) /* Цикл не должен генерироваться*/
k5 = x + j5;
} /* Конец unnecessary_loop */

/* ---------------------------------------------------- *
¦ Функция: loop_jamming ¦
¦ Два цикла в этой функции имеют одинаковые ¦
¦ заголовки и могут быть слиты в один. ¦
* ---------------------------------------------------- */


void loop_jamming( x )
int x;
{
for( i = 0; i < 5; i++ )
k5 = x + j5 * i;
for( i = 0; i < 5; i++ )
i5 = x * k5 * i;
} /* Конец loop_jamming */

/* ------------------------------------------------------ *
¦ Функция: loop_unrolling ¦
¦ Цикл в этой функции должен быть заменен ¦
¦ тремя присваиваниями с использованием ¦
¦ константной индексации массива или машинно- ¦
¦ зависимыми командами для инициализации ¦
¦ блока памяти. ¦
* ------------------------------------------------------ */

void loop_unrolling( x )
int x;
{
for( i = 0; i < 6; i++ )
ivector4[ i ] = 0;
} /* Конец loop_unrolling */

/* ----------------------------------------------------- *
¦ Функция: jump_compression ¦
¦ Эта программа полезна для демонстрации ¦
¦ сжатия цепочки переходов. goto end_1 может ¦
¦ быть заменен на прямой переход на beg_1. ¦
* ----------------------------------------------------- */

int jump_compression( i, j, k, l, m )
int i, j, k, l, m;
{
beg_1:
if( i < j )
if( j < k )
if( k < l )
if( l < m )
l += m;
else
goto end_1;
else
k += l;
else {
j += k;
end_1:
goto beg_1;
}
else
i += j;
return( i + j + k + l + m );
} /* Конец jump_compression */




Прмечание:
Расшифровка методов оптимизации:
1)"Размножение констант" - при его применении любая ссылка на константное значение замещается самим значением;
2)"Размножение копий" - в этом методе копируются переменные вместо константных значений;
3)"Свертка констант" (константная арифметика) - сводит выражения, которые содержат константные данные, к возможно простейшей форме;
4)"Алгебраические упрощения" - вид свертки констант, который удаляет арифметичесике тождества;
5)"Извлечение общих подвыражений" - процесс удаления лишних вычислений. Вместо того, чтобы генерировать код для вычисления значения каждый раз, когда оно используется, оптимизирующий компилятор пытается выделить выражение таким образом, чтобы его значение вычислялось только однажды;
6)"Глубокое выделение общих подвыражений" - в соответствии с названием является более сложным вариантом предыдущего и перекрывает базовые блоки;
7)"Снижение мощности" подразумевает замещение операций, которые требуют большего времени выполнения, более быстрыми;
8)"Удаление недостижимого кода" - еще один метод оптимизации. Недостижимый код - это некоторая последовательность инструкций программы, которая недостижима ни по одному пути в программе;
9)"Удаление лишних присваиваний" включает нахождение промежутка жизни переменной и удаление присваиваний этой переменной, если эти присваивания не могут изменить логику программы;
10)"Распределения переменных по регистрам" - попытка обеспечить оптимальное назначение регистров путем сохранения часто используемых переменных в регистрах так долго, как это возможно, для того, чтобы исключить более медленный доступ к памяти;
11)"Вынесение инвариантного (неизменяющегося) кода" - один из путей ускорения циклов, заключающийся в вынесении выражений за пределы цикла, если значения, ими вычисляемые, являются неизменными во время выполнения цикла;
12)"Слияние циклов" минимизирует управляющие заголовки циклов путем сращивания кода из циклов, имеющих одинаковые управляющие заголовки, в один цикл;
13)"Разворачивание циклов" - минимизация количества проходов через цикл путем увеличения числа операций, выполняемых внутри каждой итерации;
14)"Минимизация заголовков вызова функций" - вроде и так понятно;
15)"Передача параметров функций через регистры" - также вроде понятно, частично пересекаеся с п.10;
16)"Замена вызова функции ее телом" - аналогично.

Составить ответ ||| Конференция ||| Архив

Ответы



Перейти к списку ответов ||| Конференция ||| Архив ||| Главная страница ||| Содержание

E-mail: info@telesys.ru