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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> boost::call_once нужны добровольцы :) 
V
    Опции темы
SABROG
  Дата 8.6.2010, 00:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


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

Репутация: 4
Всего: 91



Может кто-нибудь выложить результаты теста вызова функции boost::call_once 1000 * 1000 * 1000 раз. То есть в цикле как обычно:

Код

static boost::once_flag once = BOOST_ONCE_INIT;

for (int i = 0; i < 1000 * 1000 * 1000; ++i) {
    boost::call_once(run_once(), once);
}


Интересует за сколько по времени выполнится этот цикл в release сборке. Это должно занять меньше минуты.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
boostcoder
Дата 8.6.2010, 00:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

Репутация: 49
Всего: 110



а в чем собственно проблема?
PM WWW   Вверх
SABROG
Дата 8.6.2010, 00:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


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

Репутация: 4
Всего: 91



Цитата(boostcoder @ 8.6.2010,  00:31)
а в чем собственно проблема?

Хочу понять есть ли разница в скорости между std::call_once и boost::call_once.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
boostcoder
Дата 8.6.2010, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

Репутация: 49
Всего: 110



т.е. у вас нет буста?
сейчас..
PM WWW   Вверх
boostcoder
Дата 8.6.2010, 01:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

Репутация: 49
Всего: 110



Код

const int max_ = 1000 * 1000 * 1000;
static boost::once_flag boost_once = BOOST_ONCE_INIT;
static std::once_flag std_once;

struct run_once {
   run_once() {}
   void operator()() {}
};

void test_boost() {
   for (int i = 0; i < max_; ++i) {
       boost::call_once(boost_once, run_once());
   }
}

void test_std() {
   for (int i = 0; i < max_; ++i) {
       std::call_once(std_once, run_once());
   }
}

int main(int argv, const char** argc) {
   struct timespec start = {0,0}, stop = {0,0};

   clock_gettime(CLOCK_REALTIME, &start);

   test_boost();

   clock_gettime(CLOCK_REALTIME, &stop);
   std::cout << "boost = " << stop.tv_sec-start.tv_sec << "sec, " << stop.tv_nsec-start.tv_nsec << "nsec" << std::endl;

   clock_gettime(CLOCK_REALTIME, &start);

   test_std();

   clock_gettime(CLOCK_REALTIME, &stop);
   std::cout << "std = " << stop.tv_sec-start.tv_sec << "sec, " << stop.tv_nsec-start.tv_nsec << "nsec" << std::endl;
   return 0;
}

Цитата

boost = 25sec, 32141272nsec
std = 9sec, -772863264nsec


amd phenom 2.33

Добавлено через 2 минуты и 38 секунд
не понятно почему бустовская версия такая тормознутая, в отличии от стандартной smile

Добавлено через 13 минут и 53 секунды
теперь понятно smile
бустовская версия:
Код

    // Based on Mike Burrows fast_pthread_once algorithm as described in
    // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
    template<typename Function>
    void call_once(once_flag& flag,Function f)
    {
        static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
        static boost::uintmax_t const being_initialized=uninitialized_flag+1;
        boost::uintmax_t const epoch=flag.epoch;
        boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
        
        if(epoch<this_thread_epoch)
        {
            pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);

            while(flag.epoch<=being_initialized)
            {
                if(flag.epoch==uninitialized_flag)
                {
                    flag.epoch=being_initialized;
#ifndef BOOST_NO_EXCEPTIONS
                    try
                    {
#endif
                        pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
                        f();
#ifndef BOOST_NO_EXCEPTIONS
                    }
                    catch(...)
                    {
                        flag.epoch=uninitialized_flag;
                        BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
                        throw;
                    }
#endif
                    flag.epoch=--detail::once_global_epoch;
                    BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
                }
                else
                {
                    while(flag.epoch==being_initialized)
                    {
                        BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
                    }
                }
            }
            this_thread_epoch=detail::once_global_epoch;
        }
    }
}

стандартная:
Код

  /// call_once
  template<typename _Callable, typename... _Args>
    void
    call_once(once_flag& __once, _Callable __f, _Args&&... __args)
    {
#ifdef _GLIBCXX_HAVE_TLS
      auto __bound_functor = std::bind<void>(__f, __args...);
      __once_callable = &__bound_functor;
      __once_call = &__once_call_impl<decltype(__bound_functor)>;
#else
      unique_lock<mutex> __functor_lock(__get_once_mutex());
      __once_functor = std::bind<void>(__f, __args...);
      __set_once_functor_lock_ptr(&__functor_lock);
#endif

      int __e = __gthread_once(&(__once._M_once), &__once_proxy);

#ifndef _GLIBCXX_HAVE_TLS
      if (__functor_lock)
        __set_once_functor_lock_ptr(0);
#endif

      if (__e)
    __throw_system_error(__e);
    }

  // @} group mutexes
}

нужно почитать что по той ссылке такого умного написано, раз уж такой тормоз получился smile

Добавлено через 14 минут и 36 секунд
ах да, проверял на линукс.
PM WWW   Вверх
SABROG
Дата 8.6.2010, 01:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


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

Репутация: 4
Всего: 91



Вообще результаты интересные. Дело в том, что автор алгоритма, который должен использоваться в std::call_once утверждает, что скорость "холостого" хода (после первого вызова функции) должна быть 1 миллиард в секунду. Но там была реализация только для pthreads, но на деле это не должно ничего менять, так как ОС зависимые функции не вызываются при холостом ходе.

Значит на деле скорость в 9 раз медленней для std::call_once и в 25 раз медленней для boost.

По крайней мере я немного успокоился так как моя версия call_once написанная на Qt тоже выполняется 25 секунд (под Windows). А алгоритм почти тот же что и в бусте, разве что классы Qt'шные. Это примерно 40 000 000 вызовов в секунду вместо 1 миллиарда.

Это сообщение отредактировал(а) SABROG - 8.6.2010, 01:20


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
boostcoder
Дата 8.6.2010, 01:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

Репутация: 49
Всего: 110



не понимаю, для чего эту функцию так часто вызывать? она ведь используется, в основном, при создании/инициализации некоторого ресурса.
неужели, есть реальная надобность ее так часто дергать?
PM WWW   Вверх
SABROG
Дата 8.6.2010, 01:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


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

Репутация: 4
Всего: 91



Она используется в некоторых версиях синглтонов внутри метода instance(), а уж на сколько часто будет вызываться этот синглтон зависит от разработчика. У меня например сейчас такая ситуация, что я не могу выставить приоритет потоку пока его не создаст библиотечный класс и пока я физически не попаду в функцию, которая будет выполняться в отдельном потоке. Но так как функция вызывается много раз, то выставлять приоритет потока на каждый вызов/итерацию слишком накладно, тут мне поможет функция call_once. Но .та функция есть пока только в boost, а в std::call_once она идет вместе с новым стандартом C++0x. В общем пришлось писать свою версию на Qt, так как там тоже аналогов нет несмотря на то, что Thiago Maciera обещал написать Q_ONCE еще пару лет назад.

Это сообщение отредактировал(а) SABROG - 8.6.2010, 01:32


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
boostcoder
Дата 8.6.2010, 01:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

Репутация: 49
Всего: 110



Цитата(SABROG @  8.6.2010,  01:28 Найти цитируемый пост)
в std::call_once она идет вместе с новым стандартом C++0x.

ну так пользуйте. компилятор давно зарелизили. я постоянно тещу новые снепшоты.
кстати, в релизе 4.5.0 есть баг, который проявляется при сборке openssl 0.9.8m и выше)
тут в теме, есть ссылка на мингв на базе 4.6.0.

Добавлено через 1 минуту и 44 секунды
да, по бинарникам, он не совместим c Qt-libraries и Qt-sdk. придется пересобирать.
PM WWW   Вверх
SABROG
Дата 8.6.2010, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


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

Репутация: 4
Всего: 91



Спасибо за ссылку, буду на досуге пересобирать. На линуксе Qt версия не намного отличается от виндовой 21-24сек.

Поставил на работе под linux boost 1.40.0, скорость при оптимизации -O3 такая же как и у Qt варианта - 21 сек.

Intel® Pentium® Dual  CPU  E2200  @ 2.20GHz
Intel® Core™2 Duo E6400 @ 2.13GHz
---
Вот код из gcc 4.4.0 для винды:

Код

int
__gthr_win32_once (__gthread_once_t *once, void (*func) (void))
{
  if (once == NULL || func == NULL)
    return EINVAL;

  if (! once->done)
    {
      if (InterlockedIncrement (&(once->started)) == 0)
        {
          (*func) ();
          once->done = TRUE;
        }
      else
        {
          /* Another thread is currently executing the code, so wait for it
             to finish; yield the CPU in the meantime.  If performance
             does become an issue, the solution is to use an Event that
             we wait on here (and set above), but that implies a place to
             create the event before this routine is called.  */
          while (! once->done)
            Sleep (0);
        }
    }
  return 0;
}


---
К сожалению с новым MinGW больше проблем. Qt не собирается с версией OpenSSL, которая там идет. Пришлось выковыривать его оттуда и прописывать переменную LPATH вместо LIBRARY_PATH, которая почему-то стала игнорироваться линкером (g++ -print-search-dirs) 
и вскрылся баг с ""error: '_clear87' was not declared in this scope"", причем как выяснилось баг разработчиков MinGW (решается копированием файлов float.h и stddef.h в $QTDIR/include, только float.h там 2, нужно выбирать тот, что пожирнее).

Это сообщение отредактировал(а) SABROG - 9.6.2010, 08:51


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
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.0583 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


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

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