Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Питекантроп
246 / 140 / 6
Регистрация: 14.06.2010
Сообщений: 340
#1

Падение производительности на gcc - C++

28.02.2012, 22:31. Просмотров 764. Ответов 9
Метки нет (Все метки)

Кто-нибудь сталкивался с тем, что при компиляции gcc, если разносить определение класса и реализацию в заголовочный и, соответственно, в cpp файл, то падает производительность?
Привожу код "без разнесения"
показать

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "stdio.h"
#include  "time.h"
#include  "stdlib.h"
#include  "math.h"
 
//g++ -O3 -msse -msse3 -msse2 main.cpp
#include "pmmintrin.h"
#include "emmintrin.h"
#include "xmmintrin.h"
//__m128d x128 = {
//#include "complex.h"
 
 
__declspec(align(16)) 
struct dComplex
{
        union compl_value
        {
            __m128d value;
            struct re_im_ { double re, im; } re_im;
        } value_un;
#define Re value_un.re_im.re
#define Im value_un.re_im.im
#define Value value_un.value
#define to_xmm(v) *((__m128d*)(&(v)))
#define to_compl(v) *((dComplex*)(&(v)))
        dComplex()
        { }
        dComplex(double re, double im)
        { 
            Re = re;
            Im = im;
        }
        dComplex(const __m128d & val_xmm)
        { 
            Value = val_xmm;
        }
        dComplex(const dComplex & orig)
        { 
            Value = to_xmm(orig);
        }
 
        double Module()
        {
            compl_value x_un;
            x_un.value = _mm_sub_pd(Value, Value);
            return sqrt(x_un.re_im.re + x_un.re_im.im);
        }
        
        double Argument()
        {
            return atan2(Im, Re);
        }
        
        dComplex operator + (const dComplex & val)
        {
            return dComplex(_mm_add_pd(Value,val.Value));
        }
        dComplex operator - (const dComplex & val)
        {
            return dComplex(_mm_sub_pd(Value,to_xmm(val)));
        }
        
 
        dComplex operator * (const dComplex & val)
        {   
        //  return dComplex(Re * val.Re - Im * val.Im, Re * val.Im + Im * val.Re);
            return dComplex(_mm_addsub_pd(
                _mm_mul_pd(Value, _mm_movedup_pd(val.Value)),
                _mm_mul_pd(
                    _mm_shuffle_pd(Value ,Value, 1),
                    _mm_shuffle_pd(val.Value, val.Value, 3)
                    )
                ));
        }
        
        dComplex operator / (const dComplex & val)
        {   
            __m128d x = _mm_mul_pd(val.Value,val.Value),
                r = _mm_shuffle_pd(Value ,Value, 1);
 
            return dComplex(_mm_div_pd(
                _mm_add_pd(
                    _mm_mul_pd(Value,_mm_movedup_pd(val.Value)),//_mm_shuffle_pd(val.Value, val.Value, 0)),
                    _mm_mul_pd(
                        r,
                        _mm_shuffle_pd(val.Value, val.Value, 3)
                    )),
                _mm_hadd_pd(x,x)
                ));
        }
        dComplex& operator = (const dComplex & val)
        {
            return to_compl(Value = to_xmm(val));
        }
        dComplex& operator = (double val)
        {
            Re = val;
            Im = 0;
        }
        dComplex& operator = (const double values[])
        {
            Re = values[0];
            Im = values[1];
        }
};
 
 
int main()
{
    dComplex C(1,2), C1(2,4), C2(-1,-1);
    int tm = clock();
    double c1, c2 , c;
    for (int i = 0; i < 10000000; ++i)
    {
        C1.Re = 1.0 * rand() / RAND_MAX;
        C = C1 * (C1 / C2 + C2 * C2) * C1 * C2;
    }
    tm = clock() - tm;
    printf("time: %f\n",tm * 0.001);
    printf("%f %f\n",C.Re,C.Im);
    return 0;
}

Компилируется сие так
g++ -O3 -msse -msse3 -msse2 main.cpp
Запустите, покажет время выполнения.

Если создать файл complex.h и complex.cpp, перенести в них структуру и откомпилировать
g++ -O3 -msse -msse3 -msse2 main.cpp complex.cpp,
то у меня работает на 40% дольше.
В студии такого не возникает.
В чем причина? Может есть дополнительные опции компиляции, чтоб избежать такого?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
28.02.2012, 22:31
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Падение производительности на gcc (C++):

Gcc и c++ - C++
Доброго времени суток. Начну с предисловия. Я всегда писал на C++ под винду и в линукс не совался. Сейчас, я выполняю задание(тестовое) и...

gcc в c++ VS - C++
void MakeStrRef(RCString* sref,char* data){ asm(&quot;pushl %%eax\n&quot; &quot;call %%edx&quot; : ...

g++/gcc не компилирует - C++
есть С++ код #include &lt;iostream&gt; int main(){ std::cout &lt;&lt; &quot;hello ,world!&quot;; } запускаю компилятор и он ничего не...

gcc компиляция - C++
Проблема возникла при компиляции проекта code::block. При build and run все работает, в папке bin проекта появляется .exe Но...

gcc update - C++
как обновить gcc? Нужно качать новую версию и заново устанавливать или есть какая-то команда, чтобы сделать это?

Компиляция gcc - C++
Подскажите как в VS скомпилировать программу с помощью компилятора gcc

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Jupiter
Каратель
Эксперт С++
6553 / 3973 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
28.02.2012, 22:37 #2
методы описанные внутри класса/структуры - inline
Питекантроп
246 / 140 / 6
Регистрация: 14.06.2010
Сообщений: 340
28.02.2012, 22:47  [ТС] #3
Цитата Сообщение от Jupiter Посмотреть сообщение
методы описанные внутри класса/структуры - inline
inline ни к чему не привел. Насколько я знаю, gcc в режиме O3 и без того проводит инлайн, насколько позволяет ситуация
talis
791 / 543 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
28.02.2012, 22:53 #4
Питекантроп, имелось ввиду, что методам, чья релизация идёт прямо в описании класса, по-умолчанию присваивается квалификатор inline.

C++
1
2
3
4
5
6
7
8
9
class Foo
{
public
   /* inline */
   Foo()
   {
       std::cout << "Foo()\n";
   }
};
Питекантроп
246 / 140 / 6
Регистрация: 14.06.2010
Сообщений: 340
28.02.2012, 23:23  [ТС] #5
скорость вернулась на место, только когда я перенес в хидер конструктор, который часто вызывается в методах.
Если же я хочу в хидере явно указать инлайн для метода, реализованного в срр, то компилятору почему-то это не нравится. Пишет ворнинг: inline function %function_name used but never defined

И почему-то же MS C++ все-равно делает инлайн, где бы не была реализация
ForEveR
В астрале
Эксперт С++
7970 / 4732 / 321
Регистрация: 24.06.2010
Сообщений: 10,541
Завершенные тесты: 3
29.02.2012, 11:00 #6
Питекантроп, Функции определенные в классе по умолчанию со спецификатором inline.
Функции с явным указанием inline совершенно не обязательно будут такими - дело компилятора.
Функции без указания inline аналогично совершенно не обязательно будут не inline - дело компилятора.
grizlik78
Эксперт С++
1908 / 1440 / 111
Регистрация: 29.05.2011
Сообщений: 2,996
29.02.2012, 12:28 #7
При раздельной компиляции инлайнить совсем непросто (для компилятора-компоновщика). Так что имеет смысл inline-функции определять прямо в заголовочных файлах (внутри класса или вне — дело вкуса).
Цитата Сообщение от Питекантроп Посмотреть сообщение
И почему-то же MS C++ все-равно делает инлайн, где бы не была реализация
А это видно из машинного кода или по времени выполнения?
Питекантроп
246 / 140 / 6
Регистрация: 14.06.2010
Сообщений: 340
01.03.2012, 16:58  [ТС] #8
Цитата Сообщение от grizlik78 Посмотреть сообщение
А это видно из машинного кода или по времени выполнения?
Я погорячился, априори заявив, что студия делает инлайн. Сейчас посмотрел дизассемблерный код и увидел, что нет инлайна ни в одном ни в другом случае. В тестовой функции считается выражение на основе операторов, возможно, студия не может делать инлайн операторов, хз.
Я доработал код, скачал последнюю версию gcc и провел еще одно тестирование.
Получились интересные, как мне кажется, результаты.
Студия:
1. Реализация в хидере: 27.6 сек
2. Реализация в cpp: 27.7 сек
gcc:
1. Реализация в хидере: 16.5 сек
2. Реализация в срр: 51.6 сек
3. Реализация в хидере, но объявление отдельно 16.7

Тестирующующий участок во всех случаях один и тот же:
C++
1
2
3
4
5
6
7
8
9
    dComplex C(1,2), C1(2,4), C2(-1,-1), D(10,0);
    int tm = clock();
    for (int i = 0; i < 1000000000; ++i)
    {
        C1.Re = i & 15;     // меняем входной аргумент, чтоб компилер не пропускал цикл
        C = C1 * C2 + (C2 - C1) * C1;
    }
    tm = clock() - tm;
    printf("time: %f\n",tm * 0.001);
Я, не веря своим глазам, раз за разом гонял на gcc, но результат один и тот же:
gcc очень хорошо оптимизирует реализацию в хидере, и очень плохо в срр!
Студия же - стабильный середнячок в обоих случаях.
fasked
Эксперт С++
4934 / 2514 / 180
Регистрация: 07.10.2009
Сообщений: 4,311
Записей в блоге: 1
01.03.2012, 17:12 #9
Цитата Сообщение от Питекантроп Посмотреть сообщение
gcc очень хорошо оптимизирует реализацию в хидере, и очень плохо в срр!
Версия gcc?
Питекантроп
246 / 140 / 6
Регистрация: 14.06.2010
Сообщений: 340
01.03.2012, 17:27  [ТС] #10
Цитата Сообщение от fasked Посмотреть сообщение
Версия gcc?
с коллекции mingw 4.6.1

Добавлено через 7 минут
если интересно, то попробуйте сами:
main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "stdio.h"
#include  "time.h"
#include  "stdlib.h"
#include "complex.h"
 
#include  "math.h"
#include "string.h"
 
//g++ -O3 -msse -msse3 -msse2 main.cpp
#include "pmmintrin.h"
#include "emmintrin.h"
#include "xmmintrin.h"
//__m128d x128 = {
 
int main()
{
 
    dComplex C(1,2), C1(2,4), C2(-1,-1), D(10,0);
    int tm = clock();
    for (int i = 0; i < 1000000000; ++i)
    {
        C1.Re = i & 15;     // меняем входной аргумент, чтоб компилер не пропускал цикл
        C = C1 * C2 + (C2 - C1) * C1;
    }
    tm = clock() - tm;
    printf("time: %f\n",tm * 0.001);
 
 
    printf("%f %f\n",C.Re,C.Im);
 
    return 0;
}
complex.h:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#ifndef COMPLEX
#define COMPLEX
//g++ -O3 -march=k8 -mfpmath=sse -msse3 -msse2 main.cpp complex.cpp
//g++ -O3 -msse -msse3 -msse2 main.cpp
#include "stdlib.h"
#include "math.h"
#include "stdlib.h"
#include "math.h"
 
#include "pmmintrin.h"
#include "emmintrin.h"
#include "xmmintrin.h"
 
 
static __m128d __m128d_1_1 = {-1.0,-1.0},
        __m128d1_1 = {1.0,-1.0};
//__declspec(align(16)) 
struct dComplex
{
        union compl_value
        {
            __m128d value;
            struct re_im_ { double re, im; } re_im;
        } value_un;
#define Re value_un.re_im.re
#define Im value_un.re_im.im
#define Value value_un.value
#define to_xmm(v) *((__m128d*)(&(v)))
#define to_compl(v) *((dComplex*)(&(v)))
        dComplex()
        { }
        ~dComplex()
        { }
        dComplex(double re, double im);
        dComplex(const __m128d & val_xmm);
        dComplex(const dComplex & orig);
        dComplex& operator = (const dComplex & val);
 
        double Module();
        
        double Argument();
        
        dComplex operator + (const dComplex & val);
        dComplex operator - ();
        dComplex operator - (const dComplex & val);
        
 
        dComplex operator * (const dComplex & val);
        
        dComplex operator / (const dComplex & val);
        
        dComplex  operator ^ (int ext);
        
        dComplex  operator ^ (const dComplex & val);
        
        dComplex& operator = (double val);
        dComplex& operator = (const double values[]);
        //dComplex& operator = (const expComplex & exp_compl);
 
};
 
 
        dComplex::dComplex(double re, double im)
        { 
            Re = re;
            Im = im;
        }
        dComplex::dComplex(const __m128d & val_xmm)
        { 
            Value = val_xmm;
        }
        dComplex::dComplex(const dComplex & orig)
        { 
            Value = orig.Value;
        }
        dComplex& dComplex::operator = (const dComplex & val)
        {
            return to_compl(Value = val.Value);
        }
 
        double dComplex::Module()
        {
            compl_value x_un;
            x_un.value = _mm_sub_pd(Value, Value);
            return sqrt(x_un.re_im.re + x_un.re_im.im);
        }
        
        double dComplex::Argument()
        {
            return atan2(Im, Re);
        }
        
        dComplex dComplex::operator + (const dComplex & val)
        {
            return dComplex(_mm_add_pd(Value,val.Value));
        }
        dComplex dComplex::operator - ()
        {
            return dComplex(_mm_mul_pd(Value,__m128d_1_1));
        }
        dComplex dComplex::operator - (const dComplex & val)
        {
            return dComplex(_mm_sub_pd(Value,to_xmm(val)));
        }
        
 
        dComplex dComplex::operator * (const dComplex & val)
        {   
        //  return dComplex(Re * val.Re - Im * val.Im, Re * val.Im + Im * val.Re);
            return dComplex(_mm_addsub_pd(
                _mm_mul_pd(Value, _mm_movedup_pd(val.Value)),
                _mm_mul_pd(
                    _mm_shuffle_pd(Value ,Value, 1),
                    _mm_shuffle_pd(val.Value, val.Value, 3)
                    )
                ));
        }
        
        dComplex dComplex::operator / (const dComplex & val)
        {   
            __m128d x = _mm_mul_pd(val.Value,val.Value),
                r = _mm_shuffle_pd(Value ,Value, 1),
                val_inv = _mm_mul_pd(val.Value, __m128d1_1);
 
            return dComplex(_mm_div_pd(
                _mm_addsub_pd(
                    _mm_mul_pd(Value,_mm_movedup_pd(val_inv)),//_mm_shuffle_pd(val.Value, val.Value, 0)),
                    _mm_mul_pd(
                        r,
                        _mm_shuffle_pd(val_inv, val_inv, 3)
                    )),
                _mm_hadd_pd(x,x)
                ));
        }
        
        dComplex  dComplex::operator ^ (int ext)
        {
            int ex = abs(ext);
            dComplex ret = (ex & 1) ? *this : dComplex(1,0), 
                p = *this;
            while (ex >>= 1)
            {
                p = p * p;
                if (ex & 1) ret = ret * p;
            }
            return ext >= 0 ? ret : dComplex(1,0) / ret;
        }
        
        dComplex  dComplex::operator ^ (const dComplex & val)
        {
            if (val.Im == 0 && val.Re == (int)val.Re)
                return operator ^ ((int)val.Re);
            dComplex EXT(dComplex(
                        0.5 * log(Im * Im + Re * Re),
                        atan2(Im, Re)
                        ) * val);
            return _mm_mul_pd(
                        _mm_movedup_pd(_mm_set_sd(exp(EXT.Re))),
                        _mm_set_pd(sin(EXT.Im),cos(EXT.Im))
                        );
        }
        
        dComplex& dComplex::operator = (double val)
        {
            Re = val;
            Im = 0;
            return *this;
        }
        dComplex& dComplex::operator = (const double values[])
        {
            Re = values[0];
            Im = values[1];
            return *this;
        }
#endif
компиляция: g++ -O3 -msse -msse2 -msse3 main.cpp complex.h

Затем скопируйте реализацию вместе с инклудами в complex.cpp, дописав #include "complex.h" и откомпилируйте
g++ -O3 -msse -msse2 -msse3 main.cpp complex.cpp

Какие у вас результаты?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.03.2012, 17:27
Привет! Вот еще темы с ответами:

gcc VS DEV-C++ 4.9.9.2 - C++
Люди!! Срочно нужны знающие люди по данному вопросу.Только сейчас узнал,что вся практика будет в gcc...... Какие отличия вообще между ними...

Глюк gcc? - C++
Компилируя программу в gcc, выводит от части неверный ответ. В code::blocks все в порядке. Как это понимать? Программа выполняет сдвиг...

Компиляция (gcc) - C++
Добрый вечер! После компиляции текстовый файл становится вдруг двоичным, как следствие его невозможно открыть для исправлений. Почему? ...

GotoXY в GCC - C++
ДОБРОГО ВРЕМЕНИ СУТОК !!! Я использую GCC и мне нужно использовать функцию GotoXY. В GCC нет библиотеки conio.h. Прошу дать код...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
01.03.2012, 17:27
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru