Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.74/72: Рейтинг темы: голосов - 72, средняя оценка - 4.74
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
1

Производительность операций

20.11.2011, 06:34. Показов 13779. Ответов 135
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Не уверен в своих силах для самостоятельной оценки сабжа. Где можно найти информацию о производительности стандартных операций с++ (гуглением не справился, нашел только сравнение реализации на с++, джаве и на нескольких интерпретируемых языках)?
То есть интересует информация плана << : * как 1:15 или <= : == как 25:24... То есть, чрезвычайно интересно знать, какие операции выбирать если есть альтернатива.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.11.2011, 06:34
Ответы с готовыми решениями:

Вставить между цифрами 1, 2,..., 8, 9 в данном порядке, знак одной из 4-х арифметических операций так, чтобы результат восьми послед-х операций =100
Вычисления проводятся слева-направо, ни одна операция не имеет приоритета. Добавлено через 2...

Производительность
Подскажите, где или что почитать о том, как писать БЫСТРЫЕ программы? (про разработку...

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

Доказать равенства, используя свойства операций над множествами и определения операций
Доказать равенства, используя свойства операций над множествами и определения операций. Дальше...

135
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
21.11.2011, 16:31  [ТС] 2
Мою тему просмотрело 39 человек и всем нечего было сказать. Я решился сам.
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#include<iostream>
#include<vector>
 
int main()
{
    setlocale( LC_ALL, "Russian" );
    std::cout.width(5);
 
    typedef std::vector<double> proportions;
    proportions rezults;
    for (int q = 0; q != 200; ++q) { rezults.push_back(0); }
    unsigned long long iterationCounter = 0;
 
    while ( true || false )
    {
        int a, b, c, i = 0;
        
        //Инициализация и присваивание
        __asm
        {
            rdtsc
            mov a, eax
        }
        double n1;
        n1 = 0x55e100;
        __asm
        {
            rdtsc
            mov b, eax
        }
        double n2 = 0x55e100;
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
 
        //Префиксный или постфиксный инткримент
        int e = 0;
        __asm
        {
            rdtsc
            mov a, eax
        }
        e++;
        __asm
        {
            rdtsc
            mov b, eax
        }
        ++e;
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
 
        /*Насколько быстрее разименование указателя на double, чем итератора std::vector<double>*/
        std::vector<double> arr(1);
        arr[0] = asin(static_cast<double>(1)) * 2;//pi
        std::vector<double>::iterator it = arr.begin();
        double* val = new double;
        *val = arr[0];
        __asm
        {
            rdtsc
            mov a, eax
        }
        *it;
        __asm
        {
            rdtsc
            mov b, eax
        }
        *val;
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
 
        /*Обращение к элементу вектора и массива*/
        __asm
        {
            rdtsc
            mov a, eax
        }
        arr[0];
        __asm
        {
            rdtsc
            mov b, eax
        }
        val[0];
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
 
        //Сложение и умножение целочисленно
        int x = 23, y = 1234;
        __asm
        {
            rdtsc
            mov a, eax
        }
        x *= y;
        __asm
        {
            rdtsc
            mov b, eax
        }
        x += y;
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
 
        //Вещественно
        double f = log(static_cast<double>(55e12)), g = sqrt(f);
        __asm
        {
            rdtsc
            mov a, eax
        }
        f *= g;
        __asm
        {
            rdtsc
            mov b, eax
        }
        f += g;
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
        
        //Извлечение корня и умножение вещественно
        __asm
        {
            rdtsc
            mov a, eax
        }
        sqrt(f);
        __asm
        {
            rdtsc
            mov b, eax
        }
        f *= g;
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
 
 
        //Разименование или обращение по индексу для массива
        __asm
        {
            rdtsc
            mov a, eax
        }
        val[0];
        __asm
        {
            rdtsc
            mov b, eax
        }
        *val;
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
 
        
        //Разименование или обращение по индексу для вектора
        __asm
        {
            rdtsc
            mov a, eax
        }
        arr[0];
        __asm
        {
            rdtsc
            mov b, eax
        }
        *it;
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
 
        //Меньше или неравно
        __asm
        {
            rdtsc
            mov a, eax
        }
        x < y;
        __asm
        {
            rdtsc
            mov b, eax
        }
        x != y;
        __asm
        {
            rdtsc
            mov c, eax
        }
        rezults[i] = ( rezults[i] * iterationCounter + static_cast<double>( b - a ) / ( c - b ) ) / ( iterationCounter + 1 );
        ++i;
 
        
        if( !(++iterationCounter % 10000) )
        {
            std::cout << "Усреднение №" << iterationCounter << ":\n";
            std::cout << "Инициализация в " << rezults[0] << " раз быстрее, чем обявление+присвоение.\n";
            std::cout << "Префиксный инткримент в " << rezults[1] << " раз быстрее, чем постфиксный.\n";
            std::cout << "Разименование указателя в " << rezults[2] << " раз быстрее, чем итератора.\n";
            std::cout << "Обращение к элементу массива в " << rezults[3] << " раз быстрее, чем к элементу вектора.\n";
            std::cout << "Целочисленное сложение в " << rezults[4] << " раз быстрее, чем умножение.\n";
            std::cout << "Вещественное сложение в " << rezults[5] << " раз быстрее, чем умножение.\n";
            std::cout << "Умнжение в " << rezults[5] << " раз быстрее, чем извлечение корня.\n";
            std::cout << "Указатель в " << rezults[6] << " раз быстрее, чем индекс.\n";
            std::cout << "Итератор в " << rezults[7] << " раз быстрее, чем индекс.\n";
            std::cout << "Неравно в " << rezults[8] << " раз быстрее, чем меньше.\n";
        }
    }
}
Выдал у меня результаты
Код
Усреднение №2620000:
Инициализация в 1.09377 раз быстрее, чем обявление+присвоение.
Префиксный инткримент в 0.998926 раз быстрее, чем постфиксный.
Разименование указателя в 19.9195 раз быстрее, чем итератора.
Обращение к элементу массива в 8.17944 раз быстрее, чем к элементу вектора.
Целочисленное сложение в 1.02781 раз быстрее, чем умножение.
Вещественное сложение в 2.49602 раз быстрее, чем умножение.
Умнжение в 2.49602 раз быстрее, чем извлечение корня.
Указатель в 1.18523 раз быстрее, чем индекс.
Итератор в 1.04466 раз быстрее, чем индекс.
Неравно в 0.424205 раз быстрее, чем меньше.
в Visual C++ 2010, со стандартными настройками оптимизации (не менял, потому, что не знаю что значат настройки). Прошу прокомментировать объективность моего теста. Только умоляю, с премерами. Т. е. если вы говорите, что я что-либо определил неверно (скажем, отключенная оптимизация критически повлияла на скорость обращения к элементу вектора), укажите точно, что не верно (в случае с вектором, скажите, какой именно параметр оптимизации нужно включить).
Я уверен, что тема интересна не только мне, и буду рад, если кто-то проявит интерес и дополнит мой список сравнений своим.
Очень надеюсь, что найдётся человек, имеющий хорошее понятие об оптимизации в какой-либо среде разработки, и сможет сформулировать правило написания объективного теста сабжа.
0
Заблокирован
21.11.2011, 16:39 3
rdtsc нельзя доверять на многоядерных камнях
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
21.11.2011, 16:42  [ТС] 4
Во время правки, обнаружил явное свидетельство, что в таком виде результат не верен: если поменять местами порядок выполнения в последнем тесте( x < y; и x != y; ), не изменится ничего. Хотя, это можно объяснить тем, что операции выполняются одинаково долго, сопоставимо с затратами на засечение времени.

Добавлено через 1 минуту
Да, кстати. У меня sony Vaio с intel core i3 по моему. 4 ядра (виртуальное удвоение)

Добавлено через 1 минуту
Цитата Сообщение от Bers Посмотреть сообщение
rdtsc нельзя доверять на многоядерных камнях
Возможно, именно из-за этого у меня при небольшом количестве проходов (менее десяти) результаты сильно другие... Да и вообще, постоянно разные. В идеальном тесте соотношение должно быть постоянным.
0
Заблокирован
21.11.2011, 16:43 5
Не стал разбираться в вашем коде, так как сразу столкнулся с вызывающими вопросы конструкциями.

Например, в С++ (если имеется в виду стандарт 2003, как в 2011 я не знаю) нет такого типа, как long long. Или такая вычурная конструкция, как while ( true || false ). Очевидно, что true || false всегда равно true , поэтому почему бы просто не написать while ( true ), если вы имеете в виду бесконечный цикл.

Кроме того ваши выводы по поводу постинкремента и прединкоремента некорректные, так как обычно если значение постинкремента не присваивается другой переменной, то для функдаментальных типов компилятор генерирует один и тот же код для прединкремента и постинкремента. Если же речь заходит о пользовательских типах, то тем более ваш вывод некорректен, так как все зависит от сложности реализации пользовательских типов, и нельзя с определенностью указать разницу во времени исполнения.

То есть поднятый вами вопрос и то, как вы подощли к его решению, не представляет никакого интереса для профессиональных программистов..
2
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
21.11.2011, 16:45 6
А еще советую собрать программу в режиме релиза, врубить -O3 и попробовать еще раз.
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
21.11.2011, 16:50  [ТС] 7
процессор Core i5 2530 МГц в яндексмаркете написано

Добавлено через 3 минуты
Цитата Сообщение от Сыроежка Посмотреть сообщение
не представляет никакого интереса для профессиональных программистов..
Уходи из моего топика в раздел для профессионалов, злой человек. У страуструпа, в его великом толмуде написано, что префиксный лучше. Как вы упомянули, для вас очевидно, что компилятор учтёт, что для встроенного типа в данном контектсе разницы нет, и сгенерирует одинаковый код. Мне же, такие вещи, не дают покоя день и ночь. Я мало читал и не уверен, поведёт ли себя компилятор безупречно в таком контексте.
0
Заблокирован
21.11.2011, 16:53 8
Никаких проблем. Могут все уйти из вашего топика, если мнения других вас не интересуют!
0
Эксперт С++
5043 / 2622 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1
21.11.2011, 16:54 9
Цитата Сообщение от CEBEP Посмотреть сообщение
что префиксный лучше.
Эстетика это все, а не борьба за производительность.
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
21.11.2011, 17:00  [ТС] 10
Цитата Сообщение от ForEveR Посмотреть сообщение
А еще советую собрать программу в режиме релиза, врубить -O3 и попробовать еще раз.
Переключил на релиз, результаты изменились! Что такое -ОЗ, не понял... что это?
Код
Усреднение №2900000:
Инициализация в 1.22925 раз быстрее, чем обявление+присвоение.
Префиксный инткримент в 4.56375 раз быстрее, чем постфиксный.
Разименование указателя в 1.07129 раз быстрее, чем итератора.
Обращение к элементу массива в 2.59468 раз быстрее, чем к элементу вектора.
Целочисленное сложение в 2.56498 раз быстрее, чем умножение.
Вещественное сложение в 2.54113 раз быстрее, чем умножение.
Умнжение в 2.54113 раз быстрее, чем извлечение корня.
Указатель в 2.53189 раз быстрее, чем индекс.
Итератор в 2.50638 раз быстрее, чем индекс.
Неравно в 2.58332 раз быстрее, чем меньше.
Цитата Сообщение от Сыроежка Посмотреть сообщение
компилятор генерирует один и тот же код
Посмотрите, для теста в текущем состоянии, префиксный вид работает быстрее вчетверо!

Добавлено через 2 минуты
Цитата Сообщение от fasked Посмотреть сообщение
а не борьба за производительность
Нет, там подробный коментайрий. префиксный в с++ выполняется до каких-либо других операций. таким образом не нужно заводить копию переменной. А при выполнении постфиксного инкремента/декремента создаётся копия переменной, передаваемая для остальных операций, а значение соответствующее идентификатору к которому применена операция меняется независимо от копии.

Добавлено через 1 минуту
Цитата Сообщение от Сыроежка Посмотреть сообщение
если мнения других вас не интересуют
Просто ваша бескомпромиссность не располагает. Ведь уже сейчас, я продемонстрировал, что ваше утверждение о инкрементах/декрементах не верно в абсолютном смысле.
0
Заблокирован
21.11.2011, 17:04 11
Цитата Сообщение от CEBEP Посмотреть сообщение
Посмотрите, для теста в текущем состоянии, префиксный вид работает быстрее вчетверо!
едва ли это так
Код
int e = 0;
                __asm
                {
                        rdtsc
010A1251  rdtsc  
                        mov a, eax
010A1253  mov         dword ptr [esp+1Ch],eax  
                }
                e++;
                __asm
                {
                        rdtsc
010A1257  rdtsc  
                        mov b, eax
010A1259  mov         dword ptr [esp+18h],eax  
                }
                ++e;
                __asm
                {
                        rdtsc
010A125D  rdtsc  
                        mov c, eax
010A125F  mov         dword ptr [esp+20h],eax  
                }
0
Эксперт С++
5043 / 2622 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1
21.11.2011, 17:04 12
Цитата Сообщение от CEBEP Посмотреть сообщение
Что такое -ОЗ, не понял... что это?
Максимальный уровень оптимизации.
Цитата Сообщение от CEBEP Посмотреть сообщение
Нет, там подробный коментайрий. префиксный в с++ выполняется до каких-либо других операций. таким образом не нужно заводить копию переменной. А при выполнении постфиксного инкремента/декремента создаётся копия переменной, передаваемая для остальных операций, а значение соответствующее идентификатору к которому применена операция меняется независимо от копии.
Современные компиляторы, как уже говорилось выше, будут поумнее многих программистов и в состоянии определить когда надо делать копию, а когда нет. Поэтому - исключительно эстетика.

Не по теме:

И не надо мне объяснять почему префиксный лучше, это лишнее ;)

0
Заблокирован
21.11.2011, 17:05 13
Цитата Сообщение от CEBEP Посмотреть сообщение
Посмотрите, для теста в текущем состоянии, префиксный вид работает быстрее вчетверо!

Добавлено через 2 минуты

Нет, там подробный коментайрий. префиксный в с++ выполняется до каких-либо других операций. таким образом не нужно заводить копию переменной. А при выполнении постфиксного инкремента/декремента создаётся копия переменной, передаваемая для остальных операций, а значение соответствующее идентификатору к которому применена операция меняется независимо от копии.
Я вам уже все написал, только вы из-за своего гонора дилетанта не внимательно читаете, что вам пишут другие!
Повторю еще раз, если с первого раза до вас не доходит. Если результат посинкрементной операции для фундаментального типа не присваивается другой переменной, то компилятор генерирует один и тот же код для прединкремента и постинкремента.

Например, в следующих двух примерах никакой разницы нет

C++
1
2
for ( int i = 0; i < 10; i++ );
for ( int i = 0; i < 10; ++i );
Для этих двух строк компилятор генерирует один и тот же код. Поэтому польза от ваших тестов нулевая. Не проще ли сразу посмотреть, какой окд генерируется компилятором? Тем более, как я уже написал, если речь идет о пользовательсикх типах, то тем более ваши оценки не имеют смыса, так как все зависит от сложности реализации пользовательских типов.

Заранее предвижу вашу реакцию, так как дилетанты всегда агрессивны, поэтому убедительная просьба, перечитать мой ответ по крайнней мере два раза, прежде чем, что-то возражать.
0
Эксперт С++
5043 / 2622 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1
21.11.2011, 17:08 14
Цитата Сообщение от Сыроежка Посмотреть сообщение
Для этих двух строк компилятор генерирует один и тот же код.
А если выражаться точно, то никакого кода для этих двух примеров не генерируется
0
385 / 229 / 12
Регистрация: 06.07.2011
Сообщений: 512
21.11.2011, 17:12 15
имеется ввиду, что разница в производительности в большинстве случаев настолько несущественна с современными мощностями и компиляторами, что никакого отношения к серьезной оптимизации оно не имеет и чаще всего интересна из чистого любопытства. и когда пишется код, правильнее выбирать то, что очевидно в данной ситуации и наиболее понятно при чтении кода.

и вообще странное противопоставление сложения и умножения...

не проще сравнить ассемблерные команды операций для оценки производительности?
0
Заблокирован
21.11.2011, 17:17 16
Цитата Сообщение от fasked Посмотреть сообщение
А если выражаться точно, то никакого кода для этих двух примеров не генерируется
Не надо делать скоропалитеьных выводов! Это все зависит от компилятора и режима компиляции.
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
21.11.2011, 17:20  [ТС] 17
Цитата Сообщение от Сыроежка Посмотреть сообщение
Повторю еще раз,
Но ведь я же продемонстрировал, что в текущем состоянии мой код выдаёт результаты, расходящиеся с тем, что прогнозируете вы (кстати, я доверительно отнёсся к вашему посылу, ведь в первоначальном варианте результаты польностью ему соответствовали). Если расхождение есть, объясните, откуда оно а не говорите что сделает компилятор, если очевидно обратное.

Цитата Сообщение от Paporotnik Посмотреть сообщение
странное противопоставление сложения и умножения
Я недавно изучал алгоритм построения гладкой линии, в википедии был приведёт вариант реализации, тщательно избегавший операции умножения. Мне хотелось понять, насколько это оправданно.


Цитата Сообщение от fasked Посмотреть сообщение
Максимальный уровень оптимизации.
Боюсь, это приведёт к тому, что выполнение части моих операций будет отключено вовсе. Было бы хорошо добиться того, чтобы компилятор делал какую-то оптимизацию, скажем, по обращению к элементу вектора, но в то же время, не на столько грубую, чтобы отключать операции, в которых нет явной необходимости.

Цитата Сообщение от Paporotnik Посмотреть сообщение
разница в производительности в большинстве случаев настолько несущественна с современными мощностями и
Отказываюсь понимать, почему производительность кого-то не интересует. Если я планирую не уходить от разработки простых интерфейсов, возможно. Но по моей специальности (не програмирование), мне в ближайшее время придётся писать максимально эффективные коды (в частности, решение специфичных СЛАУ, не имеющих эффективной реализации в библиотеках типа boost).
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
21.11.2011, 17:22 18
CEBEP, Точно не имеющих? http://www.boost.org/doc/libs/... /index.htm
0
Эксперт С++
5043 / 2622 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1
21.11.2011, 17:24 19
Цитата Сообщение от Сыроежка Посмотреть сообщение
Не надо делать скоропалитеьных выводов! Это все зависит от компилятора и режима компиляции.
В таком случае Ваш вывод о префиксном и постфиксном тоже скоропостижен
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
21.11.2011, 17:24  [ТС] 20
Цитата Сообщение от ForEveR Посмотреть сообщение
Точно не имеющих?
зуб даю
0
21.11.2011, 17:24
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.11.2011, 17:24
Помогаю со студенческими работами здесь

Доказать равенства, используя свойства операций над множествами и определения операций
Доказать равенства, используя свойства операций над множествами и определения операций. A\subseteq...

Сколько нужно провести операций, чтобы 13 операций подряд были успешными?
Вероятность успешной операции = 63% Сколько нужно провести операций, чтобы 13 операций подряд были...

Доказать равенства, используя свойства операций над множествами и определения операций
Доказать равенства, используя свойства операций над множествами и определения операций. б) ...

Напечатать все знаки арифметических операций и операций отношения
Напечатать все знаки арифметических операций и операций отношения,которые входят в заданый массив и...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru