Вопрос
Я тестирую простой код, который вычисляет фрактал Мандельброта. Я проверял его производительность в зависимости от количества итераций в функции, которая проверяет, принадлежит ли точка множеству Мандельброта или нет. Удивительно то, что после добавления флага -fPIC
я получаю большую разницу во времени. Из того, что я прочитал, накладные расходы обычно ничтожны, и самые высокие накладные расходы, с которыми я столкнулся, составляли около 6%. Я измерял около 30% накладных расходов. Любой совет будет оценен!
Подробности моего проекта
Я использую флаг -O3
, gcc 4.7.2, Ubuntu 12.04.2, x86_64. Результаты выглядят следующим образом
#iter C (fPIC) C C/C(fPIC) 1 0.01 0.01 1.00 100 0.04 0.03 0.75 200 0.06 0.04 0.67 500 0.15 0.1 0.67 1000 0.28 0.19 0.68 2000 0.56 0.37 0.66 4000 1.11 0.72 0.65 8000 2.21 1.47 0.67 16000 4.42 2.88 0.65 32000 8.8 5.77 0.66 64000 17.6 11.53 0.66
Команды, которые я использую:
gcc -O3 -fPIC fractalMain.c fractal.c -o ffpic
gcc -O3 fractalMain.c fractal.c -o f
Код: fractalMain.c
#include <time.h>
#include <stdio.h>
#include <stdbool.h>
#include "fractal.h"
int main()
{
int iterNumber[] = {1, 100, 200, 500, 1000, 2000, 4000, 8000, 16000, 32000, 64000};
int it;
for(it = 0; it < 11; ++it)
{
clock_t start = clock();
fractal(iterNumber[it]);
clock_t end = clock();
double millis = (end - start)*1000 / CLOCKS_PER_SEC/(double)1000;
printf("Iter: %d, time: %lf \n", iterNumber[it], millis);
}
return 0;
}
Код: fractal.h
#ifndef FRACTAL_H
#define FRACTAL_H
void fractal(int iter);
#endif
Код: fractal.c
#include <stdio.h>
#include <stdbool.h>
#include "fractal.h"
void multiplyComplex(double a_re, double a_im, double b_re, double b_im, double* res_re, double* res_im)
{
*res_re = a_re*b_re - a_im*b_im;
*res_im = a_re*b_im + a_im*b_re;
}
void sqComplex(double a_re, double a_im, double* res_re, double* res_im)
{
multiplyComplex(a_re, a_im, a_re, a_im, res_re, res_im);
}
bool isInSet(double P_re, double P_im, double C_re, double C_im, int iter)
{
double zPrev_re = P_re;
double zPrev_im = P_im;
double zNext_re = 0;
double zNext_im = 0;
double* p_zNext_re = &zNext_re;
double* p_zNext_im = &zNext_im;
int i;
for(i = 1; i <= iter; ++i)
{
sqComplex(zPrev_re, zPrev_im, p_zNext_re, p_zNext_im);
zNext_re = zNext_re + C_re;
zNext_im = zNext_im + C_im;
if(zNext_re*zNext_re+zNext_im*zNext_im > 4)
{
return false;
}
zPrev_re = zNext_re;
zPrev_im = zNext_im;
}
return true;
}
bool isMandelbrot(double P_re, double P_im, int iter)
{
return isInSet(0, 0, P_re, P_im, iter);
}
void fractal(int iter)
{
int noIterations = iter;
double xMin = -1.8;
double xMax = 1.6;
double yMin = -1.3;
double yMax = 0.8;
int xDim = 512;
int yDim = 384;
double P_re, P_im;
int nop;
int x, y;
for(x = 0; x < xDim; ++x)
for(y = 0; y < yDim; ++y)
{
P_re = (double)x*(xMax-xMin)/(double)xDim+xMin;
P_im = (double)y*(yMax-yMin)/(double)yDim+yMin;
if(isMandelbrot(P_re, P_im, noIterations))
nop = x+y;
}
printf("%d", nop);
}
История позади сравнения
Может показаться немного искусственным добавление флага -fPIC
при сборке исполняемого файла (согласно одному из комментариев). Итак, несколько слов объяснения: сначала я только скомпилировал программу как исполняемый файл и хотел сравнить с моим кодом Lua, который вызывает функцию isMandelbrot из C. Поэтому я создал общий объект для вызова его из lua - и имел большие временные различия. Но не мог понять, почему они росли с числом итераций. В итоге выяснилось, что это из-за -fPIC
. Когда я создаю небольшую программу на c, которая вызывает мой скрипт lua (настолько эффективно, что я делаю то же самое, только не нужно .so) - времена очень похожи на C (без -fPIC
). Поэтому я проверил его в нескольких конфигурациях за последние несколько дней, и он последовательно показывает два набора очень похожих результатов: быстрее без -fPIC
и медленнее с ним.