среда, 16 июля 2014 г.

[prog.c++] std::this_thread::get_id() -- очень дорогая штука под Windows и MSVS2013

Просто на удивление. Так что, если кому-то нужно очень часто вызывать std::this_thread::get_id(), то это может привести к серьезной просадке производительности.

Под катом исходник standalone benchmark-а, на котором я проводил замеры. Под Windows 8.1 и MSVS2013 Express у меня получается чуть меньше 2M вызовов get_id в секунду (компиляция через cl -EHsc -O2). Тогда как под тем же Windows 8.1 и Cygwin (GCC 4.8.3) получается уже чуть больше 10M в секунду (компиляция через g++ -std=c++11 -O3). А под VirtualBox-ом, ArchLinux и GCC 4.9.0 -- уже больше 400M! (компиляция такая же: g++ -std=c++11 -O3).

Причем это явно какая-то хитрая особенность реализации std::thread::id и std::this_thread::get_id() в MSVS. Т.к. если тупо пользоваться GetCurrentThreadId(), то этот же тест выдает более 500M в секунду при тех же самых параметрах компиляции.

#include <chrono>
#include <cstdlib>
#include <iostream>
#include <string>
#include <thread>

//! A helper for fixing starting and finishing time points and
//! calculate events processing time and events throughtput.
class benchmarker_t
   {
   public :
      //! Fix starting time.
      inline void
      start()
         {
            m_start = std::chrono::high_resolution_clock::now();
         }

      //! Fix finish time and show stats.
      inline void
      finish_and_show_stats(
         unsigned long long events,
         const std::string & title )
         {
            auto finish_time = std::chrono::high_resolution_clock::now();
            const double duration =
                  std::chrono::duration_cast< std::chrono::milliseconds >(
                        finish_time - m_start ).count() / 1000.0;
            const double price = duration / events;
            const double throughtput = 1 / price;

            std::cout.precision( 10 );
            std::cout << title << ": " << events
                  << ", total_time: " << duration << "s"
                  << ", price: " << price << "s"
                  << ", throughtput: " << throughtput << " " << title << "/s"
                  << std::endl;
         }

   private :
      std::chrono::high_resolution_clock::time_point m_start;
   };

int main()
   {
      const unsigned int iterations = 40000000;

      benchmarker_t bench;
      bench.start();

      const auto id = std::this_thread::get_id();

      forunsigned int i = 0; i != iterations; ++i )
         if( id != std::this_thread::get_id() )
            std::abort();

      bench.finish_and_show_stats( iterations, "gets" );
   }

Комментариев нет: