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

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

Войти
Регистрация
Восстановить пароль
 
Питекантроп
 Аватар для Питекантроп
246 / 140 / 6
Регистрация: 14.06.2010
Сообщений: 340
28.02.2012, 22:31     Падение производительности на gcc #1
Кто-нибудь сталкивался с тем, что при компиляции 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 VS DEV-C++ 4.9.9.2
Падение капли C++
Падение тела C++
C++ gcc в c++ VS
g++/gcc не компилирует C++
Падение Release C++
gcc компиляция C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Jupiter
Каратель
Эксперт C++
6545 / 3965 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
28.02.2012, 22:37     Падение производительности на gcc #2
методы описанные внутри класса/структуры - inline
Питекантроп
 Аватар для Питекантроп
246 / 140 / 6
Регистрация: 14.06.2010
Сообщений: 340
28.02.2012, 22:47  [ТС]     Падение производительности на gcc #3
Цитата Сообщение от Jupiter Посмотреть сообщение
методы описанные внутри класса/структуры - inline
inline ни к чему не привел. Насколько я знаю, gcc в режиме O3 и без того проводит инлайн, насколько позволяет ситуация
talis
 Аватар для talis
789 / 541 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
28.02.2012, 22:53     Падение производительности на gcc #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  [ТС]     Падение производительности на gcc #5
скорость вернулась на место, только когда я перенес в хидер конструктор, который часто вызывается в методах.
Если же я хочу в хидере явно указать инлайн для метода, реализованного в срр, то компилятору почему-то это не нравится. Пишет ворнинг: inline function %function_name used but never defined

И почему-то же MS C++ все-равно делает инлайн, где бы не была реализация
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7955 / 4717 / 318
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
29.02.2012, 11:00     Падение производительности на gcc #6
Питекантроп, Функции определенные в классе по умолчанию со спецификатором inline.
Функции с явным указанием inline совершенно не обязательно будут такими - дело компилятора.
Функции без указания inline аналогично совершенно не обязательно будут не inline - дело компилятора.
grizlik78
Эксперт С++
 Аватар для grizlik78
1887 / 1419 / 103
Регистрация: 29.05.2011
Сообщений: 2,967
29.02.2012, 12:28     Падение производительности на gcc #7
При раздельной компиляции инлайнить совсем непросто (для компилятора-компоновщика). Так что имеет смысл inline-функции определять прямо в заголовочных файлах (внутри класса или вне — дело вкуса).
Цитата Сообщение от Питекантроп Посмотреть сообщение
И почему-то же MS C++ все-равно делает инлайн, где бы не была реализация
А это видно из машинного кода или по времени выполнения?
Питекантроп
 Аватар для Питекантроп
246 / 140 / 6
Регистрация: 14.06.2010
Сообщений: 340
01.03.2012, 16:58  [ТС]     Падение производительности на gcc #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
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
01.03.2012, 17:12     Падение производительности на gcc #9
Цитата Сообщение от Питекантроп Посмотреть сообщение
gcc очень хорошо оптимизирует реализацию в хидере, и очень плохо в срр!
Версия gcc?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.03.2012, 17:27     Падение производительности на gcc
Еще ссылки по теме:

C++ Глюк gcc?
Компиляция gcc C++
GotoXY в GCC C++
C++ Gcc и c++

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

Или воспользуйтесь поиском по форуму:
Питекантроп
 Аватар для Питекантроп
246 / 140 / 6
Регистрация: 14.06.2010
Сообщений: 340
01.03.2012, 17:27  [ТС]     Падение производительности на gcc #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

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

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