Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Вопросы производительности  (Прочитано 24359 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Aleexeey
Постоялец

ru
Offline Offline

« : 23-01-2010 10:12 » 

Доброго всем времени суток!
хотелось поговорить с вами по поводу производительности методов на C++:
1) советы по повышению производительности из личного опыта;
2) наиболее продуктивные операции над переменными, и
    возможные ошибки провоцирующие понижение эффективности;
3) наиболее эффективные способы использования функций (или классов),
    от которых зависит вся производительность приложения (на C++);
4) ну и т. д. и т. п.
если кто что-нибудь знает как "выжать" максимальную скорость и эффективность, отзовитесь!  Улыбаюсь
спасибо всем за участие!
Записан
Aleexeey
Постоялец

ru
Offline 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
Постоялец

ru
Offline 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)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #3 : 25-01-2010 08:28 » 

имхо это тема для статьи, а вот так взять и вывалить в одно 2 сообщение кучу знаний, это боюсь перебор.
Записан

Странно всё это....
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #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-free

PS:
может общения оформить в вики?

мой первый вклад
Код:
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)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #5 : 26-01-2010 05:31 » 

Хитрость номер 2.
пускай есть некий map в котором естественно лежат некоторые данные, ключем для поиска является число (или строка Улыбаюсь )

map по сути черно красное дерево в узлах которого лежит:
Код:
typedef pair<key_type, mapped_type> value_type;
если мы храним элементы, как обычно (по значению), то при поиске возникает ситуация, когда для того, чтобы проанализировать ключ из 4-х байт вынужден обновлять кэш линию, а иногда и не одну
т.е. в кэш линию помещается не большое количество ключей или вообще не одного, из-за чего возникает потребность в обновлении кэш линий чаще чем нужно
что бы убрать этот не приятный эффект, заменим
Код:
map<key, Elem>
на
Код:
map<key, Elem*>

тест:
Код:
#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
Постоялец

ru
Offline Offline

« Ответ #6 : 26-01-2010 12:51 » 

Увеличить скорость можно также используя ассемблерные вставки:

Код:
__asm {
...
}

Т. к. обращение к любой переменной влечет обращению к памяти, а на ассемблере
переменные хранятся в сверх быстрых регистрах процессора.

вот пример:

Код:
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)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #7 : 26-01-2010 16:34 » 

Aleexeey, давай это отнесём к крайнему случаю
кроме того где тест, доказывающий, что твой код быстрее чем код оптимизированный компилятором? Улыбаюсь
Записан

Странно всё это....
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 26-01-2010 17:01 » 

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

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

Вот, например, в коде на C для GPU (CUDA для видеокарт NVIDIA) борьба больше идёт за сокращение перемещений данных из обычной памяти в видепамять и обратно, нежели за оптимальность расчётных алгоритмов. Потому что время расчёта мизерно по сравнению со временем загрузки/выгрузки.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #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)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #10 : 26-01-2010 17:22 » 

попытался эту хрень скомпилировать в GCC, удовольствие ниже среднего
а если вспомнить том, что эту возможно придется переводить под MIPS с использованием хитрого компайлера от HP или куда по хлеще, становится совсем грустно Жаль
Записан

Странно всё это....
Aleexeey
Постоялец

ru
Offline Offline

« Ответ #11 : 26-01-2010 18:24 » 

Цитата
...Было время, когда ассемблерные вставки для CPU действительно имели смысл...
ну почему тогда функции strcpy, memset, ... оптимизировали Inline Assembler (встроенным ассемблером)?

впрочем неуместно будет здесь отстаивать эту точку зрения!
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 26-01-2010 18:38 » 

Цитата: Aleexeey
ну почему тогда функции strcpy, memset, ... оптимизировали Inline Assembler (встроенным ассемблером)?
Кто эти загадочные "они"? О какой версии библиотеки от какого производителя и для какой платформы идёт речь?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Finch
Спокойный
Администратор

il
Offline 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)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #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
Постоялец

ru
Offline Offline

« Ответ #15 : 27-01-2010 12:56 » 

Полностью с вами согласен! Оптимизация программного кода компилятором - наилучший вариант, ЕСЛИ
ты не лучше компилятора!
Finch не догадывался, что на старинке сижу, буду менять!
LogRus! я что-то не пойму! как компилятор ICC добился такой скорости?
Цитата
опции: -mtune=pentium4 -O2
прежние замеры были на той же машине?
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #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
Специалист

ru
Offline 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
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #18 : 28-01-2010 08:50 » 

sss, поддерживаю: красно-черные (red black tree, rbtree). Хотя, в общем-то, смысл особо не меняется.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
sss
Специалист

ru
Offline Offline

« Ответ #19 : 28-01-2010 09:25 » 

Ну я только никого не хочу обидеть.... Я вон тоже register кодовым а не ключевым словом обозвал. Просто вдруг где нибудь в толмутах так дают...
Записан

while (8==8)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #20 : 28-01-2010 11:39 » 

sss, а хакер его знает, лично мне до лампочки Улыбаюсь
Записан

Странно всё это....
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #21 : 15-02-2010 17:07 » 

Заглянув в очередной раз в свой RSS агрегатор увидел новую заметку от Херба Саттера Улыбаюсь
в ней содержится ссылка на занятную статейку, касающуюся оптимизации
http://herbsutter.wordpress.com/2010/02/15/igor-ostrovsky-and-the-seven-cache-effects/
http://igoro.com/archive/gallery-of-processor-cache-effects/

настоятельно рекомендую.
Записан

Странно всё это....
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #22 : 03-03-2010 16:24 » new

и снова Саттер
http://herbsutter.wordpress.com/2010/02/22/machine-architecture-slides-back-online/
занятная статья где мало слов, но много картинок
тема: Как архитектура влияет на поведение кода.
Записан

Странно всё это....
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines