Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Объекты функций обычно работают быстрее функций, Так говорит Джосьютис в своей книге... 
:(
    Опции темы
EvilsInterrupt
Дата 15.12.2012, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Executables research
***


Профиль
Группа: Завсегдатай
Сообщений: 1019
Регистрация: 14.7.2007
Где: Железнодорожный, МО, Россия

Репутация: 2
Всего: 9



Читая книгу Джосьютиса "C++. Стандартная библиотека" русское издание от 2004 года столкнулся с мыслью от автора на стр.136 где он приводит преимущества использования объектов функций. 

Мысль такая: "Шаблоны обычно лучше оптимизируются чем функции, поскольку на стадии компиляции доступно больше информации".

На мой взгляд обычная ф-ция доступна в том же объеме компилятору насколько доступен объект функции.

Вопросы: Почему автор так утверждает? Это действительно так?
PM MAIL WWW ICQ Jabber   Вверх
EvilsInterrupt
Дата 15.12.2012, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Executables research
***


Профиль
Группа: Завсегдатай
Сообщений: 1019
Регистрация: 14.7.2007
Где: Железнодорожный, МО, Россия

Репутация: 2
Всего: 9



Кажется нашел здесь такое пояснение:

Цитата

Причина проста - объекты функций обеспечивают более эффективный код. В книге Скотта Мейерса на этот случай приводится пример с функцией std::sort - использование объектов функций всегда работает быстрее, выигрыш в скорости может составлять от 50% до 160%. Объясняется все тривиально - при использовании объекта функции компилятор способен встроить передаваемую функцию в тело алгоритма, а при использовании обычной функции встраивания не производится. 


Но насколько это отражает реальное положение дел?
PM MAIL WWW ICQ Jabber   Вверх
volatile
Дата 15.12.2012, 14:45 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(EvilsInterrupt @  15.12.2012,  12:38 Найти цитируемый пост)
Но насколько это отражает реальное положение дел? 

Именно так все и есть. когда-то я замерял стл-овские алгортимы, и сравнивал функции и функторы. Последние были всегда несколько быстрее.

PM MAIL   Вверх
W4FhLF
Дата 15.12.2012, 15:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 20
Всего: 121



Функцию можно определить как inline, тогда компилятор тоже постарается её встроить.


--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
EvilsInterrupt
Дата 15.12.2012, 15:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Executables research
***


Профиль
Группа: Завсегдатай
Сообщений: 1019
Регистрация: 14.7.2007
Где: Железнодорожный, МО, Россия

Репутация: 2
Всего: 9



volatile, 
Даже если поставить перед обычными функциями слово inline ?

Добавлено через 21 секунду
W4FhLF, 
Опередил )))
PM MAIL WWW ICQ Jabber   Вверх
volatile
Дата 15.12.2012, 23:42 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(volatile @  15.12.2012,  14:45 Найти цитируемый пост)
когда-то я замерял стл-овские алгортимы,

Давненько это уже было... щас я покапался в своих архивах. 
Нашел таки. вот небольшой отрывок тех старых результатов
Код

 Сравнение скоростей сортировки. STL c функтором, STL с функцией и qsort
 Результаты  (запускалось при LOOP=2000000)

                          I         II         III
 1.STL c функтором     265278 us  265475 us  264615 us  *sort
 1.STL c функтором     340669 us  342627 us  342112 us  *stable_sort
 2.STL с функцией      404181 us  411751 us  409956 us  *sort
 2.STL с функцией      436370 us  437983 us  436325 us  *stable_sort
 3.qsort               550263 us  549610 us  549178 us

quiksort в 2 раза медленнее чем STL c функтором
STL с функцией медленнее чем STL c функтором.
(добавление inline к funkcia ничего не меняет.)

Римские цифры, это просто прогоны.
us - микросекунды.
остальное понятно.
Конкретные цифры, как вы понимаете не важны, но общая тенденция - довольно наглядна

Цитата(EvilsInterrupt @  15.12.2012,  15:26 Найти цитируемый пост)
Даже если поставить перед обычными функциями слово inline ?

прочтите последнюю строчку. я ничего щас не менял. (да собственно какой мне интерес что-то менять?)

Добавлено через 2 минуты и 29 секунд
Да, возможно вы спросите почему инлайн ничего не меняет.
Там компилировалось с макс. оптимизацией на скорость, в том числе:
/Ob2 (inline = any suitable)
Все результаты в общем и так инлайн.  smile


PM MAIL   Вверх
Alca
Дата 16.12.2012, 09:09 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 7
Всего: 50



volatile, ну так выложи и тестовый код для полной картины

Это сообщение отредактировал(а) Alca - 16.12.2012, 09:09


--------------------
PM WWW ICQ Skype Jabber   Вверх
volatile
Дата 16.12.2012, 10:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(Alca @  16.12.2012,  09:09 Найти цитируемый пост)
выложи и тестовый код 


Вот, например одна из тестовых функций:
Код

struct funktor : binary_function <int, int, bool> {
   bool operator() (int lhd, int rhd) const
   {
      return (lhd < rhd);
   }
};
bool funkcia (int lhd, int rhd)
{
   return (lhd < rhd);
}
int f_qsort(const void *pl, const void *pr)
{
   return (*(int*)(pl) - *(int*)(pr));
}
void time_compare()
{
    stopwatch sw;
    const int LOOP=2000000;
    //const int LOOP=100000;
    //const int LOOP=1000;
    vector<int> v;
    v.reserve(LOOP);
    for(int i=0; i<LOOP; ++i)
    {
        v.push_back(i);
    }

    myrnd mrnd;
    for(int i=0; i<10; ++i)
    {
       random_shuffle(v.begin(), v.end(), mrnd);
    }
    vector<int> vt(v);

    // Сначала с функтором
    sw.restart();
    sort(v.begin(), v.end(), funktor());
    sw.pause();
    sw.print("sort funktor()                  =", 1000000);

    // Затем с функтором (стабильная сортировка)
    v= vt;
    sw.restart();
    stable_sort(v.begin(), v.end(), funktor());
    sw.pause();
    sw.print("stable_sort funktor()           =", 1000000);

    //Затем с функцией
    v= vt;
    sw.restart();
    sort(v.begin(), v.end(), funkcia);
    sw.pause();
    sw.print("sort funkcia                    =", 1000000);
    
    //Затем с функцией  (стабильная сортировка)
    v= vt;
    sw.restart();
    stable_sort(v.begin(), v.end(), funkcia);
    sw.pause();
    sw.print("stable_sort funkcia             =", 1000000);
    
    //И наконец квиксорт
    v= vt;
    sw.restart();
    qsort( &v[0], v.size(), sizeof (int),  f_qsort );
    sw.pause();
    sw.print("qsort                           =", 1000000);

    //make_haep
    v= vt;
    sw.restart();
    make_heap(v.begin(), v.end(), funktor());
    sw.pause();
    sw.print("make_heap funktor()             =", 1000000);

    //make_haep
    v= vt;
    sw.restart();
    make_heap(v.begin(), v.end(), funkcia);
    sw.pause();
    sw.print("make_heap funkcia               =", 1000000);

    //sort_haep funktor()
    v= vt;
    make_heap(v.begin(), v.end(), funktor());
    sw.restart();
    sort_heap(v.begin(), v.end(), funktor());
    sw.pause();
    sw.print("sort_heap funktor()             =", 1000000);

    //sort_haep funkcia
    v= vt;
    make_heap(v.begin(), v.end(), funkcia);
    sw.restart();
    sort_heap(v.begin(), v.end(), funkcia);
    sw.pause();
    sw.print("sort_heap funkcia               =", 1000000);

    //partial_sort funktor()
    v= vt;
    sw.restart();
    partial_sort(v.begin(), v.end(), v.end(), funktor());
    sw.pause();
    sw.print("partial_sort funktor()          =", 1000000);

    //partial_sort funkcia
    v= vt;
    sw.restart();
    partial_sort(v.begin(), v.end(), v.end(), funkcia);
    sw.pause();
    sw.print("partial_sort funkcia            =", 1000000);

    
    //partial_sort /3 funktor()
    v= vt;
    sw.restart();
    partial_sort(v.begin(), v.begin() + v.size()/3, v.end(), funktor());
    sw.pause();
    sw.print("partial_sort /3 funktor()       =", 1000000);

    //partial_sort /3funkcia
    v= vt;
    sw.restart();
    partial_sort(v.begin(), v.begin() + v.size()/3, v.end(),  funkcia);
    sw.pause();
    sw.print("partial_sort /3 funkcia         =", 1000000);

}

Здесь используется еще секундомер. (вот старая версия, использовавшаяся с этим кодом)

stopwatch.h
Код

#ifndef BxXMmQpkiGCiA_stopwatch_h_incl
#define BxXMmQpkiGCiA_stopwatch_h_incl
//======================================================================================================= 
//
// Класс секундомера, для измерения временных интервалов
//
//======================================================================================================= 
class stopwatch {
   LARGE_INTEGER m_time;
   bool f_on;
public:
//-------------------------------------------------------------------------------------------------------   
// Конструктор по умолчанию. Сразу запускает секундомер.
   stopwatch() { restart(); }
//-------------------------------------------------------------------------------------------------------   
// Конструктор с параметром. Если (f_start==true) - запускает секундомер,
// иначе создает в сброшенном и остановленном состоянии
   stopwatch(bool f_start) 
   { 
       f_start ? restart() : reset();
   }
//-------------------------------------------------------------------------------------------------------   
// Сбрасывает и Запускает секундомер
   void restart() 
   { 
      f_on=true; 
      QueryPerformanceCounter(&m_time);
   }
//-------------------------------------------------------------------------------------------------------   
// Сбрасывает и Останавливает секундомер
   void reset()
   {
      f_on = false;
      m_time.QuadPart = 0;
   }
//-------------------------------------------------------------------------------------------------------   
// Информация о состоянии
// Если секундомер запущен возвращает true, если в паузе то false;
   bool get_state() const {return f_on;}
//-------------------------------------------------------------------------------------------------------   
// Переключает по очереди pause/resume (стоп/пуск), возвращает новое состояние после переключения.
   bool pause_resume()
   {
      LARGE_INTEGER now;
      QueryPerformanceCounter(&now);
      m_time.QuadPart = now.QuadPart - m_time.QuadPart;
      return f_on = !f_on;
   }
//-------------------------------------------------------------------------------------------------------   
// если f_resume==true запускает, иначе останавливает секундомер
   void pause_resume(bool f_resume) { if (f_on == !f_resume) pause_resume(); }
//-------------------------------------------------------------------------------------------------------   
// Останавливает
   void pause() { if (f_on) pause_resume(); }
//-------------------------------------------------------------------------------------------------------   
// Запускает
   void resume() { if (!f_on) pause_resume(); }
//-------------------------------------------------------------------------------------------------------   
// возвращает показание секундомера в <микро/милли/секундах>  
// koef 1-sec; 1000-msec; 1000000-usec
   unsigned int get_time(unsigned int koef=1000) const 
   {
      LARGE_INTEGER freq;   // Системная частота
      QueryPerformanceFrequency(&freq);
      if (f_on)
      {
         LARGE_INTEGER now;
         QueryPerformanceCounter(&now);
         return (((now.QuadPart - m_time.QuadPart) * koef) / freq.QuadPart);
      }
      else
      {
         return ((m_time.QuadPart * koef) / freq.QuadPart);
      }
   }
//-------------------------------------------------------------------------------------------------------   
// Печатает показание секундомера
// koef 1-sec; 1000-msec; 1000000-usec
   void print(const char* pname, unsigned int koef=1000) const
   {
      double t = get_time(koef*10)/10.0;
      if (pname == NULL) pname = "";
      const char* p = "??";
      if (koef==1) p = "sec";
      else if (koef==1000) p = "ms";
      else if (koef==1000000) p = "us";

      std::cout << boost::format("%s %9.1f %s\n") % pname % t % p;
   };                                               
//-------------------------------------------------------------------------------------------------------   
// Печатает показание секундомера
// koef 1-sec; 1000-msec; 1000000-usec
   void print(unsigned int koef=1000) const { print (NULL, koef); }
//--------------------------------------------------------------------------------------------------------

// ---------------  Дальше идут служебные и редко используемые --------------------------------------------

//--------------------------------------------------------------------------------------------------------
// получить get_time_raw
   unsigned __int64 get_time_raw() const
   {
      if (f_on)
      {
         LARGE_INTEGER now;
         QueryPerformanceCounter(&now);
         return (now.QuadPart - m_time.QuadPart);
      }
      else
      {
         return m_time.QuadPart;
      }
   }

//--------------------------------------------------------------------------------------------------------
// получить системную частоту (u64)
   static unsigned __int64 get_frequency()
   {
      LARGE_INTEGER freq;   // количество отсчетов в секунду
      QueryPerformanceFrequency(&freq);
      return freq.QuadPart;
   }

//--------------------------------------------------------------------------------------------------------
// получить текущий счетчик системы (u64)
   static unsigned __int64 get_counter()
   {
      LARGE_INTEGER now;
      QueryPerformanceCounter(&now);
      return now.QuadPart;
   }

//--------------------------------------------------------------------------------------------------------
// Получить int для посева (seed) генератора случайных чисел
// возвращает некое число зависящее от системного счётчика.
   static int get_randomizer()
   {
      LARGE_INTEGER now;
      QueryPerformanceCounter(&now);
      return now.LowPart ^ now.HighPart;
   }
};


#endif//BxXMmQpkiGCiA_stopwatch_h_incl


так, что еще?
myrnd - генератор случайных чисел, используйте любой, решающего значения не имеет.

У меня такое ошущение, что я результаты здесь уже публиковал. (щас поищу)

Добавлено через 3 минуты и 15 секунд
да, результаты здесь уже постил


PM MAIL   Вверх
W4FhLF
Дата 16.12.2012, 13:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 20
Всего: 121



Цитата(volatile @  16.12.2012,  10:36 Найти цитируемый пост)

bool funkcia (int lhd, int rhd)
{
   return (lhd < rhd);
}


Я думал здесь должен быть inline? /Ob2 ещё не даёт гарантии, что она инлайн. 
Плюс надо добавить const по аналогии с funcktor, т.к. это влияет на оптимизацию.

Объективно, разницы между таким элементарным функтором и функцией быть недолжно. 



--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
volatile
Дата 16.12.2012, 19:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(W4FhLF @  16.12.2012,  13:28 Найти цитируемый пост)
Я думал здесь должен быть inline?

Цитата(volatile @  15.12.2012,  23:42 Найти цитируемый пост)
добавление inline к funkcia ничего не меняет


Цитата(W4FhLF @  16.12.2012,  13:28 Найти цитируемый пост)
Плюс надо добавить const 

инт передается по значению, зачем конст?

Добавлено через 1 минуту и 28 секунд
Цитата(W4FhLF @  16.12.2012,  13:28 Найти цитируемый пост)
по аналогии с funcktor

и там тоже по значению.

PM MAIL   Вверх
volatile
Дата 16.12.2012, 19:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(W4FhLF @  16.12.2012,  13:28 Найти цитируемый пост)
должен быть inline? /Ob2 ещё не даёт гарантии, что она инлайн. 

да и походу, добавление инлайн, тоже не дает никакой гарантии, что она будет инлайн.


PM MAIL   Вверх
EvilsInterrupt
Дата 16.12.2012, 20:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Executables research
***


Профиль
Группа: Завсегдатай
Сообщений: 1019
Регистрация: 14.7.2007
Где: Железнодорожный, МО, Россия

Репутация: 2
Всего: 9



Кой-чего интересного нашел на rsdn.ru : Производительность компиляторов С++
PM MAIL WWW ICQ Jabber   Вверх
feodorv
Дата 16.12.2012, 20:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



Цитата(W4FhLF @  16.12.2012,  14:28 Найти цитируемый пост)
Объективно, разницы между таким элементарным функтором и функцией быть недолжно. 

Я так думаю, надо смотреть ассемблерный код, чтобы понять, за счёт чего возникает такая разница...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
mes
Дата 16.12.2012, 22:21 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



мне видится это разница так:
Цитата(volatile @  16.12.2012,  09:36 Найти цитируемый пост)
   sort(v.begin(), v.end(), funktor());

Код

template<typename T>
void do_some() {  T()();  } 


Цитата(volatile @  16.12.2012,  09:36 Найти цитируемый пост)
    sort_heap(v.begin(), v.end(), funkcia);

Код

void do_some(void (*fn)()) { fn(); }



--------------------
PM MAIL WWW   Вверх
mes
Дата 17.12.2012, 10:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(volatile @  16.12.2012,  18:41 Найти цитируемый пост)
да и походу, добавление инлайн, тоже не дает никакой гарантии, что она будет инлайн.

(даже неявное) взятие адреса отменяет инлайн.. (для этого случая использования)


--------------------
PM MAIL WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1534 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.