Опубликован: 19.01.2025 | Доступ: свободный | Студентов: 0 / 0 | Длительность: 05:57:00
Лекция 9:

Лабораторная работа №8. Оптимизации на этапе компиляции

< Лекция 8 || Лекция 9: 12 || Лекция 10 >

8.2.5 Измерение уменьшения объема бинарного файла от оптимизаций

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

$ ls -l a.out 
-rw-r--r-- 1 root root 13423 сен 26  2023 a.out  

Значение в пятой колонке соответствует размеру файла в байтах. О значениях в прочих колонках можно подробнее узнать в справке.

Для более точной оценки можно использовать утилиту size. Она отображает размер каждой секции в рамках бинарного файла:

$ size a.out 
   text	   data	    bss	    dec	    hex	filename
   1524	    600	      8	   2132	    854	a.out

8.3. Задание к лабораторной работе

Подготовьте исходный код программы на языке С, которая будет выполнять заданное вариантом действие со случайной целочисленной матрицей А размера 20 на 20. Необходимо самостоятельно скомпилировать программу с различными опциями для архитектуры RISC-V, а также убедится в работоспособности. Опции для компиляции:

  1. Сборка без оптимизации.
  2. Оптимизация размера бинарного файла.
  3. Оптимизация скорости работы.

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

Варианты заданий (действия для матрицы):

  1. Произведение всех элементов.
  2. Сумма всех элементов.
  3. Поиск минимального элемента в матрице.
  4. Поиск элемента с наименьшим остатком от деления на 5.
  5. Поиск строки с наименьшим количеством четных чисел.
  6. a[i][j] = a[i][j] * a[i][j]
  7. a[i][j] = a[i][j] % 9
  8. a[i][j] = a[i][j+1] + a[i][j-1]
  9. a[i][j] = a[i][j] * a[j][i]
  10. Транспонирование матрицы.

Примечание для преподавателей: данную лабораторную работу можно проводить не только в стандартном режиме, описанном выше, но и на соревновательной основе по аналогии с олимпиадами. Для этого предлагается следующий упрощенный алгоритм:

  1. Выбрать один из вариантов заданий, выдать его в качестве общего на группу студентов.
  2. Зафиксировать тривиальное решение для выбранного задания (исходный код и команду для сборки), которое будет выступать в качестве базового уровня с точки зрения оптимизируемых характеристик (объем файла и скорость).
  3. Зафиксировать параметры среды и способа измерения скорости (версии компиляторов и линковщика, ОС, инструментов измерения, параметров виртуальной машины).
  4. В качестве задания указать оптимизацию одного или обоих параметров приложения, не меняя его сути и не нарушая корректность работы основного алгоритма.

8.3.1. Описание последовательности выполнения работы

В качестве первого шага, необходимо реализовать программу согласно выбранному варианту. При реализации программы не забудьте реализовать вывод исходных данных и ответа в консоль. Выполним сборку программы без флагов оптимизации с помощью. компилятора gcc (или путем кросс компиляции, или запуская компилятор непосредственно в рамках RISC-V ОС). Программу необходимо отладить перед оптимизацией - с помощью данных меньшего объема и многократных запусков убедитесь, что она корректно справляется с поставленной задачей и успешно выполняется без сбоев и ошибок.

Далее, измерим исходные значения времени работы программы и объем бинарного файла с помощью утилит time / multitime и size. При измерении времени работы программы, убедитесь, что вы измеряете время работы программы, а не время ее запуска в рамках процесса qemu-riscv64:

$ qemu-riscv64 -L "$RISCV/sysroot" time ./hello # Корректное измерение
$ time qemu-riscv64 -L "$RISCV/sysroot" ./hello # Некорректное измерение

Далее необходимо выполнить оптимизацию с помощью флагов компиляции. Мы рекомендуем увеличивать степень оптимизации постепенно, начиная с флага -O1, контролируя корректность работы самой программы по вводимым значениям и измеряя время работы. Аналогичные действия необходимо предпринять и для оптимизации объема бинарного файла. После окончания оптимизации необходимо повторить измерения и внести полученные данные в отчет.

8.3.2. Пример выполнения задания на защиту

Оптимизируйте время работы бинарного файла для программы суммирования остатков от деления на 3 для целочисленного случайного массива из 10 элементов. Предположим, что исходный код программы уже написан. Выполним сборку и измерим время работы на 10 запусках:

$ gcc main.c -o a.out
$ multitime -n 10 ./a.out
…
===> multitime results
1: ./a.out
            Mean        Std.Dev.    Min         Median      Max
real        0.016       0.002       0.012       0.016       0.021       
user        0.007       0.005       0.000       0.007       0.013       
sys         0.008       0.004       0.004       0.007       0.015  

Для начала оптимизации по времени рекомендуется выполнить компиляцию c флагом -O1 и оценить достигнутый эффект.

$ gcc -O1 main.c -o a.out
$ multitime -n 10 ./a.out
…
===> multitime results
1: ./a.out
            Mean        Std.Dev.    Min         Median      Max
real        0.012       0.002       0.010       0.016       0.020       
user        0.005       0.005       0.000       0.007       0.013       
sys         0.008       0.004       0.004       0.007       0.015  

8.4. Вопросы для контроля

  1. Для каких задач требуется оптимизация размера бинарного файла?
  2. Какие негативные последствия может нести оптимизация времени выполнения программы?
  3. Какие флаги отвечают за оптимизацию времени выполнения программы?
< Лекция 8 || Лекция 9: 12 || Лекция 10 >