На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (3) 1 2 [3]  все  ( Перейти к последнему сообщению )  
> Шаблоны — примеры применения и альтернативы на других языках
    ExpandedWrap disabled
      #include <chrono>
      #include <iostream>
      #include <thread>
      #include <utility>
       
      /* динамически полиморфная иерархия */
      struct DynaPolyBase                                                                     // интерфейс
      {
        virtual void doIt() const = 0;
      };
      // реализации
      struct DynaPolyDerived1 : DynaPolyBase
      {
        virtual void doIt() const {};
      };
      struct DynaPolyDerived2 : DynaPolyBase
      {
        virtual void doIt() const {};
      };
      struct DynaPolyDerived3 : DynaPolyDerived1
      {
        virtual void doIt() const {};
      };
       
      /* статически полиморфная иерархия */
      // реализации
      struct StatPolyDerived1
      {
        void doIt() const {};
      };
      struct StatPolyDerived2
      {
        void doIt() const {};
      };
      struct StatPolyDerived3
      {
        void doIt() const {};
      };
      template <typename Class> requires ( requires { std::declval<Class>().doIt(); } )       // интерфейс
      struct StatPolyBase : Class
      {
      };
       
      /* простой тестер */
      template <typename C, auto Count = 1000u * 1000 * 1000>
      void doIt(const C& c)
      {
        for (decltype(Count) i = 0; i < Count; ++i) c.doIt();
      }
       
      int main()
      {
        auto start = std::chrono::high_resolution_clock::now();
        StatPolyBase<StatPolyDerived2> item1;
        DynaPolyDerived2               item2;
       
        doIt(item1);                                                          // чек статики
       
        auto diff  = std::chrono::high_resolution_clock::now() - start;
       
        std::cout << diff << std::endl;
        start = std::chrono::high_resolution_clock::now();
        doIt(item2);                                                          // чек динамики
        diff  = std::chrono::high_resolution_clock::now() - start;
        std::cout << diff << std::endl;
      }
    Не знаю, как у вас, у нас вот так:
    ExpandedWrap disabled
      200ns
      610564600ns
      Qraizer, что-то у тя какая-то жуть :-?
      Я попробовал твой пример прогнать в https://www.onlinegdb.com, выбрал там стандарт С++20, чет он заругался на твой код в отдельных местах. Ну не суть, я подредактировал.
      Посмотри, я ничего в логике не поломал?

      ExpandedWrap disabled
        #include <chrono>
        #include <iostream>
        #include <thread>
        #include <utility>
         
        /* динамически полиморфная иерархия */
        struct DynaPolyBase                                                                     // интерфейс
        {
          virtual void doIt() const = 0;
        };
        // реализации
        struct DynaPolyDerived1 : DynaPolyBase
        {
          void doIt() const override {};
        };
        struct DynaPolyDerived2 : DynaPolyBase
        {
          void doIt() const override {};
        };
        struct DynaPolyDerived3 : DynaPolyDerived1
        {
          void doIt() const override {};
        };
         
        /* статически полиморфная иерархия */
        // реализации
        struct StatPolyDerived1
        {
          void doIt() const {};
        };
        struct StatPolyDerived2
        {
          void doIt() const {};
        };
        struct StatPolyDerived3
        {
          void doIt() const {};
        };
        template <typename Class>       // интерфейс
        struct StatPolyBase : Class
        {
        };
         
        /* простой тестер */
        template <typename C, auto Count = 1000u * 1000 * 1000>
        void doIt(const C& c)
        {
          for (auto i = 0; i < Count; ++i) c.doIt();
        }
         
        int main()
        {
          
          StatPolyBase<StatPolyDerived2> item1;
          DynaPolyDerived2               item2;
         
          auto start = std::chrono::high_resolution_clock::now();
          doIt(item1);                                                          // чек статики
          auto diff  = std::chrono::high_resolution_clock::now() - start;
          std::cout << diff.count() << std::endl;
          
          start = std::chrono::high_resolution_clock::now();
          doIt(item2);                                                          // чек динамики
          diff  = std::chrono::high_resolution_clock::now() - start;
          std::cout << diff.count() << std::endl;
        }

      И вот какие я выводы получил после трех запусков:

      ExpandedWrap disabled
        2908372641
        2742338534

      ExpandedWrap disabled
        1867473111
        2083640450

      ExpandedWrap disabled
        1968410219
        2046030004

      А в твоем примере вообще какая-то лютая разница :-?
        Цитата Majestio @
        Я попробовал твой пример прогнать в https://www.onlinegdb.com, выбрал там стандарт С++20, чет он заругался на твой код в отдельных местах. Ну не суть, я подредактировал.
        В каких? Концепты не понял? С++20 в полной мере могут не все поддерживать. Та ну и хрен с ними, статика и на утиных работать будет, ей явно объявленные интерфейсы необязательны.
        Но ты прав, я сутрировал конечно. Намерено, причём. Включи оптимизацию и познай дзен inline, как говорится. ;)
        Твой пример ближе к истине, но тут такое дело... в общем, предсказатель переходов у современных процессоров всё равно не даст нормально потестить разницу в производительности между статически и динамически связанными вызовами. Надо как-то рандомизировать адресаты, чтобы у предсказателя побольше промахов было, иначе даже косвенные вызовы будут связаны статически, но в кэше процессора. И если для динамики это раз плюнуть, то вот для статики...
        Но это полбеды. Главная беда – это непонятно, а вообще нужно ли этот самый предсказатель нейтрализовывать. Как бы, синтетика синтетикой, но не до такой же степени, когда код сознательно пессимизируется.

        Добавлено
        С горем пополам у меня вышло
        ExpandedWrap disabled
          543405900ns
          578759500ns
        Это я уменьшил количество вызовов в 10 раз. Вот вам воочию работа предсказателя: более чем 10 кратный штраф за сбросы конвейера.

        Добавлено
        P.S. Ну не совсем, всё-таки. Код теперь выглядит примерно вот так:
        ExpandedWrap disabled
          template <typename C>
          auto doIt(const C& c)
          {
            auto start = std::chrono::high_resolution_clock::now();
           
            c.doIt();
            return std::chrono::high_resolution_clock::now() - start;
          }
          /* ... */
            StatPolyBase<StatPolyDerived1> itemS1;
            StatPolyBase<StatPolyDerived2> itemS2;
            StatPolyBase<StatPolyDerived3> itemS3;
            DynaPolyDerived1              *itemD1 = new DynaPolyDerived1;
            DynaPolyDerived2              *itemD2 = new DynaPolyDerived2;
            DynaPolyDerived3              *itemD3 = new DynaPolyDerived3;
            std::array<DynaPolyBase*, 3>   items = { itemD1, itemD2, itemD3 };
           
            std::random_device              rd;
            std::mt19937                    gen(rd());
            std::uniform_int_distribution<> distrib(0, 2);
           
            decltype(doIt(itemS1)) time = decltype(time)::zero();
           
            // статика
            for (int i = 0; i < 10000000; ++i)
              switch (distrib(gen))
              {
                case 0: time += doIt(itemS1); break;
                case 1: time += doIt(itemS2); break;
                case 2: time += doIt(itemS3); break;
              }
          /* ... */
            // динамика
            for (int i = 0; i < 10000000; ++i)
              time += doIt(*items[distrib(gen)]);
            delete itemD1;
            delete itemD2;
            delete itemD3;
        Т.е. в эти 10 крат входят также вызовы рандом-генератора и службы времени. Так что не всё таки так уж и плохо без предсказателя.

        Добавлено
        Если же подойти к этому ну оооочень аккуратно, то:
        ExpandedWrap disabled
          547698900ns
          833802200ns
        ExpandedWrap disabled
          700369200ns
          1015749800ns
        ExpandedWrap disabled
          664954600ns
          962311400ns
        Тут учитывается оверхед самого вызова std::chrono::high_resolution_clock::now(), усреднённый по миллиарду вызовов. И циклы снова увеличены до миллиарда.
        Но надо понимать, что если у вас нет аппаратной защиты от всяких там Spectre и вместо стоят программные патчи, то эта синтетика будет показывать попугаев вместо наносекунд.
        Сообщение отредактировано: Qraizer -
          Ну да, такое ближе к истине. А то я уже распереживался за динамику, чуть чяем не облился :lol:
          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
          0 пользователей:
          Страницы: (3) 1 2 [3]  все


          Рейтинг@Mail.ru
          [ Script execution time: 0,0329 ]   [ 15 queries used ]   [ Generated: 31.03.23, 04:10 GMT ]