воскресенье, 4 сентября 2016 г.

[prog.c++] Нововведения в SObjectizer-5.5.18: расширение статистики для диспетчеров

В версии 5.5.18 расширен объем мониторинговой инфомации от диспетчеров. Теперь можно получать статистику по временам работы и простоя рабочих нитей диспетчеров.

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

using namespace so_5::disp::active_obj;
auto disp = create_private_disp( env, "my_disp",
      // В свойствах диспетчера явным образом включаем сбор
      // статистики об активности рабочих нитей.
      disp_params_t{}.turn_work_thread_activity_tracking_on() );

Либо это можно сделать сразу для всего SObjectizer Environment при запуске:

so_5::launch(
   []( so_5::environment_t & env ) {
      ... // Какие-то начальные действия.
   []( so_5::environment_params_t & params ) {
      // Явным образом включаем сбор статистики об активности
      // рабочих нитей для всех диспетчеров.
      params.turn_work_thread_activity_tracking_on();
      ...
   } );

В этом случае сбор статистики об активности рабочих нитей будет включен для всех диспетчеров, которые будут работать в рамках SObjectizer Environment. Если такую статистику для какого-то из диспетчеров нужно отключить, то это можно сделать в свойствах самого диспетчера:

so_5::launch(
   []( so_5::environment_t & env ) {
      ... // Какие-то начальные действия.

      // Создаем диспетчер, для которого сбор статистики об
      // активности рабочих нитей будет отключен не смотря на
      // глобальные параметры для всего SObjectizer Environment.
      auto my_disp = so_5::disp::one_thread::create_private_disp(
            env, "my_disp",
            so_5::disp::one_thread::disp_params_t{}
                  .turn_work_thread_activity_tracking_off() );
      ...
   []( so_5::environment_params_t & params ) {
      // Явным образом включаем сбор статистики об активности
      // рабочих нитей для всех диспетчеров.
      params.turn_work_thread_activity_tracking_on();
      ...
   } );

Распространение информации об активности рабочих нитей диспетчеров выполняется обычным образом -- через сообщения, которые отсылаются на почтовый ящик т.н. stats_collector-а. В качестве типа сообщения с этой информации используется тип work_thread_activity из пространства имен so_5::stats::messages.

class activity_listener final : public so_5::agent_t
   {
   public :
      activity_listener( context_t ctx )
         :  so_5::agent_t( ctx )
         {
            so_default_state().event(
                  so_environment().stats_controller().mbox(),
                  &activity_listener::evt_monitor_activity );
         }

   private :
      void
      evt_monitor_activity(
         const so_5::stats::messages::work_thread_activity & evt )
         {
            namespace stats = so_5::stats;

            std::cout << evt.m_prefix << evt.m_suffix
                  << " [" << evt.m_thread_id << "] ->\n"
                  << "  working: " << evt.m_stats.m_working_stats << "\n"
                  << "  waiting: " << evt.m_stats.m_waiting_stats << std::endl;
            ...
         }
   };

Внутри work_thread_activity, помимо уже привычных m_prefix и m_suffix, находятся следующие поля:

  • m_thread_id с идентификатором рабочей нити, для которой получена статистика;
  • m_working_stats с информацией о временах работы этой нити;
  • m_waiting_stats с информацией о временах простоя этой нити.

Поля m_working_stats и m_waiting_stats имеют тип so_5::stats::activity_stats_t:

struct activity_stats_t
   {
      //! Count of events in that period of time.
      std::uint_fast64_t m_count{};

      //! Total time spent for events in that period of time.
      duration_t m_total_time{};

      //! Average time for one event.
      duration_t m_avg_time{};
   };

Где тип duration_t -- это либо std::chrono::high_resolution_clock::duration, либо std::chrono::steady_clock::duration (в зависимости от того, является для на данной платформе high_resolution_clock т.н. steady clock-ом или нет).

Т.о. посредством сообщения work_thread_activity можно узнать: сколько всего событий было обработанно нитью (с самого начала ее работы), сколько всего времени было потрачено внутри обработчиков событий (с самого начала работы нити), какова средняя длительность обработчика события. Аналогично и по временам простоя рабочей нити.

Вот небольшой пример того, как эта статистическая информация может выглядеть:

disp/atp/0x2b7fb70/threads.count: 4
disp/atp/0x2b7fb70/agent.count: 5
disp/atp/0x2b7fb70/wt-14/thread.activity [14] ->
  working: [count=5651;total=3.86549ms;avg=0.000655ms]
  waiting: [count=5652;total=492.831ms;avg=3.60857ms]
disp/atp/0x2b7fb70/wt-15/thread.activity [15] ->
  working: [count=62394;total=40.4094ms;avg=0.000644ms]
  waiting: [count=62395;total=363.346ms;avg=0.201897ms]
disp/atp/0x2b7fb70/wt-16/thread.activity [16] ->
  working: [count=69073;total=46.2095ms;avg=0.000637ms]
  waiting: [count=69073;total=361.668ms;avg=0.000813ms]
disp/atp/0x2b7fb70/wt-17/thread.activity [17] ->
  working: [count=80587;total=52.904ms;avg=0.000656ms]
  waiting: [count=80588;total=325.136ms;avg=0.003536ms]
disp/atp/0x2b7fb70/cq/__so5_au...e_2__/agent.count: 5
disp/atp/0x2b7fb70/cq/__so5_au...e_2__/demands.count: 4

Это дамп мониторинговой информации для adv_thread_pool-диспетчера с четырьмя рабочими нитями. На этом диспетчере работает одна кооперация с пятью агентами внутри. Можно увидеть информацию по каждой из рабочих нитей (в квадратных скобках указан ID нити). В данном случае можно определить, что рабочие нити больше времени проводят в ожидании событий, а не в их обработке.

Несколько слов о влиянии сбора статистики об активности рабочих нитей на производительность диспечтеров. Это сильно зависит как от типа диспетчера, так и от профиля нагрузки. Для one_thread-диспетчера с большим потоком сообщений это влияние может быть совсем незаметным. А для active_obj-диспетчера с одиночными сообщениями производительность может просесть в 3-4 раза. Поэтому каких-то общих показателей изменения производительности в зависимости от включения режима сбора информации об активности рабочих нитей нет, слишком уж большой разброс.

В любом случае данный механизм сейчас рассматривается как вспомогательный, предназначенный для целей отладки и профилирования. Необходимо предварительно проверить, какое именно влияние данный механизм оказывает именно на ваше приложение под вашим профилем нагрузки. И только после этого принимать решение о том, стоит ли активировать этот механизм для запущенных "на бой" приложений.

Отправить комментарий