Aleexeey
Постоялец
Offline
|
|
« : 23-01-2010 10:12 » |
|
Доброго всем времени суток! хотелось поговорить с вами по поводу производительности методов на C++: 1) советы по повышению производительности из личного опыта; 2) наиболее продуктивные операции над переменными, и возможные ошибки провоцирующие понижение эффективности; 3) наиболее эффективные способы использования функций (или классов), от которых зависит вся производительность приложения (на C++); 4) ну и т. д. и т. п. если кто что-нибудь знает как "выжать" максимальную скорость и эффективность, отзовитесь! спасибо всем за участие!
|
|
|
Записан
|
|
|
|
Aleexeey
Постоялец
Offline
|
|
« Ответ #1 : 23-01-2010 11:21 » |
|
Добавляю ссылки, относящиеся к этой теме: h**p://msdn.microsoft.com/ru-ru/library/ms235421.aspx - инструкции по настройке оптимизации компилятора. h**p://blog.alno.name/2008/06/virtual-functions-in-cpp-and-performance - проблема производительности виртуальных функций. h**p://msdn.microsoft.com/ru-ru/magazine/cc337887.aspx - описание использование профилировщика (технология анализирования производительности приложений).
|
|
« Последнее редактирование: 23-01-2010 16:21 от Алексей1153++ »
|
Записан
|
|
|
|
Aleexeey
Постоялец
Offline
|
|
« Ответ #2 : 23-01-2010 16:58 » |
|
h**p://www.gamedev.ru/code/faq/?id=3585 самодельный замер производительности;
h**p://www.realcoding.net/articles/tekhnika-optimizatsii-programm-fragment-23.html использование стандартных утилит: Intel VTune и AMD Code Analyst - мощные технологии оптимизации приложений;
h**p://www.codenet.ru/progr/optimize/kk/ пошаговое описание оптимизации приложений: выявления очень медленных функций (те, что грузят больше всех процессор), анализ количества вызовов, время выполнения, ..., а также анализ вплоть до каждой команды ассемблера.
|
|
« Последнее редактирование: 23-01-2010 17:08 от Алексей1153++ »
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #3 : 25-01-2010 08:28 » |
|
имхо это тема для статьи, а вот так взять и вывалить в одно 2 сообщение кучу знаний, это боюсь перебор.
|
|
|
Записан
|
Странно всё это....
|
|
|
Антон (LogRus)
|
|
« Ответ #4 : 25-01-2010 18:07 » |
|
По теме. из личного опыта (мой хит парад): 1. не оптимальные алгоритмы 2. лишние копирования памяти (при работе с контейнерами есть ряд хитростей позволяющих уменьшить копирования) 3. выделение/высвобождение памяти 4. не верный выбор мьютекса 5. излишне длинные блокировки мои любимые ссылки (по параллелизму и lock-free): http://herbsutter.wordpress.com/http://software.intel.com/ru-ru/parallel/http://groups.google.com/group/lock-freePS: может общения оформить в вики? мой первый вклад Element c; c.a = 1; // первое копирование c.b = 2; // первое копирование ........................... std::vector<Element> Cont; Cont.push_back(c); // второе копирование
иногда Element - это несколько килобайт немного оптимизируем: std::vector<Element> Cont; Cont.resize(Cont.size() + 1); Element & c = Cont.back(); c.a = 1; // одно копирование c.b = 2; // одно копирование
просьба выбор контейнера не критиковать.
|
|
|
Записан
|
Странно всё это....
|
|
|
Антон (LogRus)
|
|
« Ответ #5 : 26-01-2010 05:31 » |
|
Хитрость номер 2. пускай есть некий map в котором естественно лежат некоторые данные, ключем для поиска является число (или строка ) map по сути черно красное дерево в узлах которого лежит: typedef pair<key_type, mapped_type> value_type;
если мы храним элементы, как обычно (по значению), то при поиске возникает ситуация, когда для того, чтобы проанализировать ключ из 4-х байт вынужден обновлять кэш линию, а иногда и не одну т.е. в кэш линию помещается не большое количество ключей или вообще не одного, из-за чего возникает потребность в обновлении кэш линий чаще чем нужно что бы убрать этот не приятный эффект, заменим на тест: #include "stdafx.h" #include <iostream> #include <map> #include <fstream> #include <string> #include <typeinfo.h> #include <Windows.h>
struct ElemType { char some_data_[128]; };
typedef std::map<size_t, ElemType> StdCont; typedef std::map<size_t, long> OptiCont;
size_t cMaxElem = 0x10000; size_t cMaxSearch = cMaxElem;
template <typename T> void testMap(const std::string & testName) { T cont; T::mapped_type Elem; std::cout << testName << " fill count=" << cMaxElem << " elem size="<< sizeof(T::value_type) << " cont size="<< sizeof(T::value_type) * cMaxElem/1024 << std::endl; for (size_t i = 0; i != cMaxElem; ++i) cont.insert(cont.end(), std::make_pair(i,Elem));
std::cout << testName << " search=" << cMaxSearch << std::endl; size_t startTime = GetTickCount(); for (size_t i = 0; i != cMaxSearch; ++i) { cont.find((rand() * rand())%cMaxElem); } size_t finishTime = GetTickCount(); size_t deltaTime = finishTime - startTime; std::cout << testName << " search done Time(ms)=" << (deltaTime) << " ops=" << (1000.*cMaxElem/(deltaTime)) << std::endl << std::endl; }
int main(int argc, char* argv[]) { if (argc > 1) { cMaxElem = atoi(argv[1]); cMaxSearch = cMaxElem; }
if (argc > 2) cMaxSearch = atoi(argv[2]);
testMap<StdCont>("StdCont"); testMap<OptiCont>("OptiCont"); return 0; }
результаты запусков с различными размерами элемента: C:\...s\My Documents\Visual Studio Projects\poli_examp\Release>poli_examp.exe 1000000 1000000 StdCont fill count=1000000 elem size=36 cont size=35156 StdCont search=1000000 StdCont search done Time(ms)=2297 ops=435350
OptiCont fill count=1000000 elem size=8 cont size=7812 OptiCont search=1000000 OptiCont search done Time(ms)=2140 ops=467290
C:\...s\My Documents\Visual Studio Projects\poli_examp\Release>poli_examp.exe 1000000 1000000 StdCont fill count=1000000 elem size=68 cont size=66406 StdCont search=1000000 StdCont search done Time(ms)=2500 ops=400000
OptiCont fill count=1000000 elem size=8 cont size=7812 OptiCont search=1000000 OptiCont search done Time(ms)=1938 ops=515996
C:\...s\My Documents\Visual Studio Projects\poli_examp\Release>poli_examp.exe 1000000 1000000 StdCont fill count=1000000 elem size=132 cont size=128906 StdCont search=1000000 StdCont search done Time(ms)=3032 ops=329815
OptiCont fill count=1000000 elem size=8 cont size=7812 OptiCont search=1000000 OptiCont search done Time(ms)=2125 ops=470588
C:\...s\My Documents\Visual Studio Projects\poli_examp\Release>poli_examp.exe 1000000 1000000 StdCont fill count=1000000 elem size=504 cont size=492187 StdCont search=1000000 StdCont search done Time(ms)=3860 ops=259067
OptiCont fill count=1000000 elem size=8 cont size=7812 OptiCont search=1000000 OptiCont search done Time(ms)=2109 ops=474158
при размере элемента в 500 байт, скорость поиска удвоилась
|
|
|
Записан
|
Странно всё это....
|
|
|
Aleexeey
Постоялец
Offline
|
|
« Ответ #6 : 26-01-2010 12:51 » |
|
Увеличить скорость можно также используя ассемблерные вставки: Т. к. обращение к любой переменной влечет обращению к памяти, а на ассемблере переменные хранятся в сверх быстрых регистрах процессора. вот пример: unsigned int Blend(unsigned int dst, unsigned int src, unsigned int alpha) { unsigned int dstRB = (dst & 0x00ff00ff); unsigned int dstG = (dst & 0x0000ff00); unsigned int rb = (src & 0x00ff00ff) - dstRB; unsigned int g = (src & 0x0000ff00) - dstG;
rb *= alpha; g *= alpha; rb >>= 8; g >>= 8; rb += dstRB; g += dstG; rb &= 0x00ff00ff; g &= 0x0000ff00;
return (rb | g); }; теперь на ассемблере: unsigned int Blend(unsigned int dst, unsigned int src, unsigned int alpha) { unsigned int Result = 0; __asm { MOV EBX, dst AND EBX, 0xff00ff // unsigned int dstRB = (dst & 0x00ff00ff); MOV EAX, src AND EAX, 0xff00ff SUB EAX, EBX // unsigned int rb = (src & 0x00ff00ff) - dstRB; IMUL EAX, alpha // rb *= alpha; SHR EAX, 0x8 // rb >>= 8; ADD EAX, EBX // rb += dstRB; AND EAX, 0xff00ff // rb &= 0x00ff00ff;
MOV EBX, dst AND EBX, 0xff00 // unsigned int dstG = (dst & 0x0000ff00); MOV ECX, src AND ECX, 0xff00 SUB ECX, EBX // unsigned int g = (src & 0x0000ff00) - dstG; IMUL ECX, alpha // g *= alpha; SHR ECX, 0x8 // g >>= 8; ADD ECX, EBX // g += dstG; AND ECX, 0xff00 // g &= 0x0000ff00;
OR EAX, ECX // return (rb | g); MOV Result, EAX } return Result; };
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #7 : 26-01-2010 16:34 » |
|
Aleexeey, давай это отнесём к крайнему случаю кроме того где тест, доказывающий, что твой код быстрее чем код оптимизированный компилятором?
|
|
|
Записан
|
Странно всё это....
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #8 : 26-01-2010 17:01 » |
|
Ассемблером делу не поможешь. Главный затык в производительности на современных процессорах - это даже не то, что какая-то формула считается целиком на регистрах, а то, что из-за непредсказуемых переходов сбрасывается конвейер, и у процессора случаются простои из-за неоптимального обмена данными между кэшами разных уровней и собственно оперативной памятью. А в данных вопросах заниматься оптимизацией можно только под конкретную железяку, зная в точности размер её кэшей и особенности работы конвейера.
Поэтому нафиг - лучше довериться компилятору. Было время, когда ассемблерные вставки для CPU действительно имели смысл - когда CPU были простыми, а теория компиляции была менее совершенной. Сейчас в области приложений широкого профиля на универсальных машинах, по-моему, это уже из разряда легенд и мифологии.
Вот, например, в коде на C для GPU (CUDA для видеокарт NVIDIA) борьба больше идёт за сокращение перемещений данных из обычной памяти в видепамять и обратно, нежели за оптимальность расчётных алгоритмов. Потому что время расчёта мизерно по сравнению со временем загрузки/выгрузки.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Антон (LogRus)
|
|
« Ответ #9 : 26-01-2010 17:08 » |
|
эксперимент проведён результаты в ms Blend time=14875
Blend time=14719
BlendAsm time=13891
BlendAsm time=14296
ИМХО прирост производительности в 7% не стоит уродования кода #include "stdafx.h" #include <string> #include <iostream> #include <windows.h>
unsigned int Blend(unsigned int dst, unsigned int src, unsigned int alpha) { unsigned int dstRB = (dst & 0x00ff00ff); unsigned int dstG = (dst & 0x0000ff00); unsigned int rb = (src & 0x00ff00ff) - dstRB; unsigned int g = (src & 0x0000ff00) - dstG;
rb *= alpha; g *= alpha; rb >>= 8; g >>= 8; rb += dstRB; g += dstG; rb &= 0x00ff00ff; g &= 0x0000ff00;
return (rb | g); };
unsigned int BlendAsm(unsigned int dst, unsigned int src, unsigned int alpha) { unsigned int Result = 0; __asm { MOV EBX, dst AND EBX, 0xff00ff // unsigned int dstRB = (dst & 0x00ff00ff); MOV EAX, src AND EAX, 0xff00ff SUB EAX, EBX // unsigned int rb = (src & 0x00ff00ff) - dstRB; IMUL EAX, alpha // rb *= alpha; SHR EAX, 0x8 // rb >>= 8; ADD EAX, EBX // rb += dstRB; AND EAX, 0xff00ff // rb &= 0x00ff00ff;
MOV EBX, dst AND EBX, 0xff00 // unsigned int dstG = (dst & 0x0000ff00); MOV ECX, src AND ECX, 0xff00 SUB ECX, EBX // unsigned int g = (src & 0x0000ff00) - dstG; IMUL ECX, alpha // g *= alpha; SHR ECX, 0x8 // g >>= 8; ADD ECX, EBX // g += dstG; AND ECX, 0xff00 // g &= 0x0000ff00;
OR EAX, ECX // return (rb | g); MOV Result, EAX } return Result; };
size_t MaxCount = 1000000; typedef unsigned int (*BlendF)(unsigned int, unsigned int, unsigned int); void Test(BlendF f, const std::string & name) { size_t vect[1000] = { 0 }; size_t start = GetTickCount(); for(size_t i = 0; i != MaxCount; ++i) { for(size_t j = 0; j != 1000; ++j) vect[j] = f(vect[j], i, j); } size_t finish = GetTickCount(); std::cout << name << " time=" << (finish - start) << std::endl << std::endl;
for(size_t j = 0; j != 1000; ++j) std::cerr << " " << vect[j] ; }
int _tmain(int argc, _TCHAR* argv[]) { Test(Blend, "Blend"); Test(Blend, "Blend"); Test(BlendAsm, "BlendAsm"); Test(BlendAsm, "BlendAsm"); return 0; }
|
|
|
Записан
|
Странно всё это....
|
|
|
Антон (LogRus)
|
|
« Ответ #10 : 26-01-2010 17:22 » |
|
попытался эту хрень скомпилировать в GCC, удовольствие ниже среднего а если вспомнить том, что эту возможно придется переводить под MIPS с использованием хитрого компайлера от HP или куда по хлеще, становится совсем грустно
|
|
|
Записан
|
Странно всё это....
|
|
|
Aleexeey
Постоялец
Offline
|
|
« Ответ #11 : 26-01-2010 18:24 » |
|
...Было время, когда ассемблерные вставки для CPU действительно имели смысл... ну почему тогда функции strcpy, memset, ... оптимизировали Inline Assembler (встроенным ассемблером)? впрочем неуместно будет здесь отстаивать эту точку зрения!
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #12 : 26-01-2010 18:38 » |
|
ну почему тогда функции strcpy, memset, ... оптимизировали Inline Assembler (встроенным ассемблером)? Кто эти загадочные "они"? О какой версии библиотеки от какого производителя и для какой платформы идёт речь?
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #13 : 26-01-2010 22:46 » |
|
Aleexeey, Вот код memset из glibc 2.10.1 /* Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */
#include <string.h> #include <memcopy.h>
#undef memset
void * memset (dstpp, c, len) void *dstpp; int c; size_t len; { long int dstp = (long int) dstpp;
if (len >= 8) { size_t xlen; op_t cccc;
cccc = (unsigned char) c; cccc |= cccc << 8; cccc |= cccc << 16; if (OPSIZ > 4) /* Do the shift in two steps to avoid warning if long has 32 bits. */ cccc |= (cccc << 16) << 16;
/* There are at least some bytes to set. No need to test for LEN == 0 in this alignment loop. */ while (dstp % OPSIZ != 0) { ((byte *) dstp)[0] = c; dstp += 1; len -= 1; }
/* Write 8 `op_t' per iteration until less than 8 `op_t' remain. */ xlen = len / (OPSIZ * 8); while (xlen > 0) { ((op_t *) dstp)[0] = cccc; ((op_t *) dstp)[1] = cccc; ((op_t *) dstp)[2] = cccc; ((op_t *) dstp)[3] = cccc; ((op_t *) dstp)[4] = cccc; ((op_t *) dstp)[5] = cccc; ((op_t *) dstp)[6] = cccc; ((op_t *) dstp)[7] = cccc; dstp += 8 * OPSIZ; xlen -= 1; } len %= OPSIZ * 8;
/* Write 1 `op_t' per iteration until less than OPSIZ bytes remain. */ xlen = len / OPSIZ; while (xlen > 0) { ((op_t *) dstp)[0] = cccc; dstp += OPSIZ; xlen -= 1; } len %= OPSIZ; }
/* Write the last few bytes. */ while (len > 0) { ((byte *) dstp)[0] = c; dstp += 1; len -= 1; }
return dstpp; } libc_hidden_builtin_def (memset)
Не вижу, где тут ассемблер.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Антон (LogRus)
|
|
« Ответ #14 : 27-01-2010 07:23 » |
|
...Было время, когда ассемблерные вставки для CPU действительно имели смысл... ну почему тогда функции strcpy, memset, ... оптимизировали Inline Assembler (встроенным ассемблером)? впрочем неуместно будет здесь отстаивать эту точку зрения! ну что же давай начнём сначала. понятно что можно писать на асме, но в таком случае причем тут C++ стоимость поддержки решения сильно возрастает, приходится поддерживать код для кучу компиляторов разом (это мой случай) я совершенно не против асма когда это действительно необходимо что касается memcpy то эта функция максимально приближена по своей сути к железу, а не к прикладной логике, к тому же она может быть реализована на асме всего парой строк. и как справедливо заметил Finch не всегда она реализована на asm. есть еще один не приятный момент во вставке asm, компилятор долго выстраивал команды, прореживал их nop`ами менял операции местами, что бы максимально наполнить конвейеры процессора, а тут ты весь такой на белом коне и в шляпе, одну маленькую инструкцию встраиваешь она же "быстрая", при этом разрушаешь порядок команд и часть конвейеров процессора пару тактов отрабатывают в холостую. повторил тест на работе в студии по младше но зато не Express (в которой нет кое-каких опций сборки) Blend time=16360 Blend time=15109
BlendAsm time=18265 BlendAsm time=19625
чувствуешь разницу? asm проигрывает. это то что сгеренерировал сам компилятор: unsigned int Blend(unsigned int dst, unsigned int src, unsigned int alpha) { unsigned int dstRB = (dst & 0x00ff00ff); 00401000 mov eax,dword ptr [esp+4] unsigned int dstG = (dst & 0x0000ff00); unsigned int rb = (src & 0x00ff00ff) - dstRB; 00401004 mov ecx,dword ptr [esp+8] 00401008 mov edx,eax 0040100A and eax,0FF00h 0040100F push esi 00401010 mov esi,eax 00401012 mov eax,ecx 00401014 and eax,0FF00FFh unsigned int g = (src & 0x0000ff00) - dstG; 00401019 and ecx,0FF00h 0040101F sub ecx,esi 00401021 push edi
rb *= alpha; 00401022 mov edi,dword ptr [esp+14h] 00401026 and edx,0FF00FFh g *= alpha; 0040102C imul ecx,edi 0040102F sub eax,edx 00401031 imul eax,edi rb >>= 8; 00401034 shr eax,8 g >>= 8; 00401037 shr ecx,8 rb += dstRB; 0040103A add eax,edx g += dstG; 0040103C add ecx,esi rb &= 0x00ff00ff; 0040103E and eax,0FF00FFh g &= 0x0000ff00; 00401043 and ecx,0FF00h 00401049 pop edi
return (rb | g); 0040104A or eax,ecx 0040104C pop esi }; 0040104D ret
при желании можно повторить тест используя gcc и icc опции: -mtune=pentium4 -O2 gcc (тесты выполнялись на железяке отличное от предыдущих и в RHEL5) Blend time=10837 Blend time=10821
BlendAsm time=11623 BlendAsm time=11580
icc(подозреваю что icc переколбасил код) Blend time=6476 Blend time=6480
BlendAsm time=6391 BlendAsm time=6370
проверяем BlandAsm cгенерированный icc Dump of assembler code for function _Z8BlendAsmjjj: 0x080494fa <BlendAsm(unsigned int, unsigned int, unsigned int)+0>: push %edi 0x080494fb <BlendAsm(unsigned int, unsigned int, unsigned int)+1>: push %ebp 0x080494fc <BlendAsm(unsigned int, unsigned int, unsigned int)+2>: push %ebx 0x080494fd <BlendAsm(unsigned int, unsigned int, unsigned int)+3>: mov 0x10(%esp),%edx 0x08049501 <BlendAsm(unsigned int, unsigned int, unsigned int)+7>: mov 0x14(%esp),%ebp 0x08049505 <BlendAsm(unsigned int, unsigned int, unsigned int)+11>: mov 0x18(%esp),%edi 0x08049509 <BlendAsm(unsigned int, unsigned int, unsigned int)+15>: mov %edx,%ebx 0x0804950b <BlendAsm(unsigned int, unsigned int, unsigned int)+17>: and $0xff00ff,%ebx 0x08049511 <BlendAsm(unsigned int, unsigned int, unsigned int)+23>: mov %ebp,%eax 0x08049513 <BlendAsm(unsigned int, unsigned int, unsigned int)+25>: and $0xff00ff,%eax 0x08049518 <BlendAsm(unsigned int, unsigned int, unsigned int)+30>: sub %ebx,%eax 0x0804951a <BlendAsm(unsigned int, unsigned int, unsigned int)+32>: imul %edx,%eax 0x0804951d <BlendAsm(unsigned int, unsigned int, unsigned int)+35>: shr $0x8,%eax 0x08049520 <BlendAsm(unsigned int, unsigned int, unsigned int)+38>: add %ebx,%eax 0x08049522 <BlendAsm(unsigned int, unsigned int, unsigned int)+40>: and $0xff00ff,%eax 0x08049527 <BlendAsm(unsigned int, unsigned int, unsigned int)+45>: mov %edx,%ebx 0x08049529 <BlendAsm(unsigned int, unsigned int, unsigned int)+47>: and $0xff00,%ebx 0x0804952f <BlendAsm(unsigned int, unsigned int, unsigned int)+53>: mov %ebp,%ecx 0x08049531 <BlendAsm(unsigned int, unsigned int, unsigned int)+55>: and $0xff00,%ecx 0x08049537 <BlendAsm(unsigned int, unsigned int, unsigned int)+61>: sub %ebx,%ecx 0x08049539 <BlendAsm(unsigned int, unsigned int, unsigned int)+63>: imul %edi,%ecx 0x0804953c <BlendAsm(unsigned int, unsigned int, unsigned int)+66>: shr $0x8,%ecx 0x0804953f <BlendAsm(unsigned int, unsigned int, unsigned int)+69>: add %ebx,%ecx 0x08049541 <BlendAsm(unsigned int, unsigned int, unsigned int)+71>: and $0xff00,%ecx 0x08049547 <BlendAsm(unsigned int, unsigned int, unsigned int)+77>: or %ecx,%eax 0x08049549 <BlendAsm(unsigned int, unsigned int, unsigned int)+79>: mov %eax,%edx 0x0804954b <BlendAsm(unsigned int, unsigned int, unsigned int)+81>: mov %edx,%eax 0x0804954d <BlendAsm(unsigned int, unsigned int, unsigned int)+83>: pop %ebx 0x0804954e <BlendAsm(unsigned int, unsigned int, unsigned int)+84>: pop %ebp 0x0804954f <BlendAsm(unsigned int, unsigned int, unsigned int)+85>: pop %edi 0x08049550 <BlendAsm(unsigned int, unsigned int, unsigned int)+86>: ret 0x08049551 <BlendAsm(unsigned int, unsigned int, unsigned int)+87>: nop End of assembler dump.
и наблюдаем интересную картину - icc решил, что мы не слишком сильны в кодировании на asm. именно по этому я полагаюсь на компилятор
|
|
|
Записан
|
Странно всё это....
|
|
|
Aleexeey
Постоялец
Offline
|
|
« Ответ #15 : 27-01-2010 12:56 » |
|
Полностью с вами согласен! Оптимизация программного кода компилятором - наилучший вариант, ЕСЛИ ты не лучше компилятора! Finch не догадывался, что на старинке сижу, буду менять! LogRus! я что-то не пойму! как компилятор ICC добился такой скорости? опции: -mtune=pentium4 -O2 прежние замеры были на той же машине?
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #16 : 27-01-2010 13:52 » |
|
первый тест - домашний AMD Athlon XP 2500+ - VS Express 2008 - O2 + Blended второй тест - рабочий P4 2400 - VS Enterprise 2003 - O2 + Pentium4 третий + четвёртый - рабочий 2xZeon - GCC/ICC - O2 + Pentium4 Полностью с вами согласен! Оптимизация программного кода компилятором - наилучший вариант, ЕСЛИ ты не лучше компилятора!
попервых, как видишь ты оказался не лучше во вторых, ранняя оптимизация корень всех зол в третьих, пиши на ассемблере зачем тогда вообще С++ и тема в этом разделе тоже не нужна. в четвёртых, иногда действительно без ASM не обойтись, но уж точно не в ситуации с калькуляцией пары 32-х битных чисел. а то получается, такая фигня, народ сидит, тратит годы на изучение: архитектур, особенностей работы и т.д. и т.п. Пишут компиляторы, оптимизируют базовые библиотеки. Понимая, что от качества конкретно их работы, зависит скорость кучи ПО. А тут я или еще кто, приходит весь в белом и с порога заявляет: "Компилятор ваш фуфло, я круче могу" Можешь? Пиши на асме и студия тебе не нужна. Коллеги давайте вернёмся к хитростям в C++, а не упражнениям на ASM и так уже Холивар пошел.
|
|
|
Записан
|
Странно всё это....
|
|
|
sss
Специалист
Offline
|
|
« Ответ #17 : 28-01-2010 08:32 » |
|
LogRus, не в тему конечно, но почему деревья черно-красные а не красно-черные? У меня MIT-овский курс "Алгоритмы" с красно-черными деревьями? До этого вы меня поправляли и вот опять... Почему?
P.S.: Ещё не забывайте про кодовое слово register в C++. Можно 7% производительность добытую asm-ом опрокинуть...
|
|
« Последнее редактирование: 28-01-2010 08:42 от sss »
|
Записан
|
while (8==8)
|
|
|
RXL
|
|
« Ответ #18 : 28-01-2010 08:50 » |
|
sss, поддерживаю: красно-черные (red black tree, rbtree). Хотя, в общем-то, смысл особо не меняется.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
sss
Специалист
Offline
|
|
« Ответ #19 : 28-01-2010 09:25 » |
|
Ну я только никого не хочу обидеть.... Я вон тоже register кодовым а не ключевым словом обозвал. Просто вдруг где нибудь в толмутах так дают...
|
|
|
Записан
|
while (8==8)
|
|
|
Антон (LogRus)
|
|
« Ответ #20 : 28-01-2010 11:39 » |
|
sss, а хакер его знает, лично мне до лампочки
|
|
|
Записан
|
Странно всё это....
|
|
|
|
|
|