Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

libs/multi_index/perf/test_perf.cpp

Boost , ,

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

libs/multi_index/perf/test_perf.cpp

/* Boost.MultiIndex performance test.
 *
 * Copyright 2003-2013 Joaquin M Lopez Munoz.
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * See http://www.boost.org/libs/multi_index for library home page.
 */
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <assert.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/next_prior.hpp>
#include <climits>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <list>
#include <set>
#include <string>
#include <vector>
using namespace std;
using namespace boost::multi_index;
/* Measurement harness by Andrew Koenig, extracted from companion code to
 *   Stroustrup, B.: "Wrapping C++ Member Function Calls", The C++ Report,
 *     June 2000, Vol 12/No 6.
 * Original code retrievable at: http://www.research.att.com/~bs/wrap_code.cpp
 */
// How many clock units does it take to interrogate the clock?
static double clock_overhead()
{
    clock_t k = clock(), start, limit;
    // Wait for the clock to tick
    do start = clock();
    while (start == k);
    // interrogate the clock until it has advanced at least a second
    // (for reasonable accuracy)
    limit = start + CLOCKS_PER_SEC;
    unsigned long r = 0;
    while ((k = clock()) < limit)
        ++r;
    return double(k - start) / r;
}
// We'd like the odds to be factor:1 that the result is
// within percent% of the median
const int factor = 10;
const int percent = 20;
// Measure a function (object) factor*2 times,
// appending the measurements to the second argument
template<class F>
void measure_aux(F f, vector<double>& mv)
{
    static double ovhd = clock_overhead();
    // Ensure we don't reallocate in mid-measurement
    mv.reserve(mv.size() + factor*2);
    // Wait for the clock to tick
    clock_t k = clock();
    clock_t start;
    do start = clock();
    while (start == k);
    // Do 2*factor measurements
    for (int i = 2*factor; i; --i) {
        unsigned long count = 0, limit = 1, tcount = 0;
        // Original code used CLOCKS_PER_SEC/100
        const clock_t clocklimit = start + CLOCKS_PER_SEC/10;
        clock_t t;
        do {
            while (count < limit) {
                f();
                ++count;
            }
            limit *= 2;
            ++tcount;
        } while ((t = clock()) < clocklimit);
        // Wait for the clock to tick again;
        clock_t t2;
        do ++tcount;
        while ((t2 = clock()) == t);
        // Append the measurement to the vector
        mv.push_back(((t2 - start) - (tcount * ovhd)) / count);
        // Establish a new starting point
        start = t2;
    }
}
// Returns the number of clock units per iteration
// With odds of factor:1, the measurement is within percent% of
// the value returned, which is also the median of all measurements.
template<class F>
double measure(F f)
{
    vector<double> mv;
    int n = 0;                        // iteration counter
    do {
        ++n;
        // Try 2*factor measurements
        measure_aux(f, mv);
        assert(mv.size() == 2*n*factor);
        // Compute the median.  We know the size is even, so we cheat.
        sort(mv.begin(), mv.end());
        double median = (mv[n*factor] + mv[n*factor-1])/2;
        // If the extrema are within threshold of the median, we're done
        if (mv[n] > (median * (100-percent))/100 &&
            mv[mv.size() - n - 1] < (median * (100+percent))/100)
            return median;
    } while (mv.size() < factor * 200);
    // Give up!
    clog << "Help!\n\n";
    exit(1);
}
/* dereferencing compare predicate */
template <typename Iterator,typename Compare>
struct it_compare
{
  bool operator()(const Iterator& x,const Iterator& y)const{return comp(*x,*y);}
private:
  Compare comp;
};
/* list_wrapper and multiset_wrapper adapt std::lists and std::multisets
 * to make them conform to a set-like insert interface which test
 * routines do assume.
 */
template <typename List>
struct list_wrapper:List
{
  typedef typename List::value_type value_type;
  typedef typename List::iterator   iterator;
  pair<iterator,bool> insert(const value_type& v)
  {
    List::push_back(v);
    return pair<iterator,bool>(boost::prior(List::end()),true);
  }
};
template <typename Multiset>
struct multiset_wrapper:Multiset
{
  typedef typename Multiset::value_type value_type;
  typedef typename Multiset::iterator   iterator;
  pair<iterator,bool> insert(const value_type& v)
  {
    return pair<iterator,bool>(Multiset::insert(v),true);
  }
};
/* space comsumption of manual simulations is determined by checking
 * the node sizes of the containers involved. This cannot be done in a
 * portable manner, so node_size has to be written on a per stdlibrary
 * basis. Add your own versions if necessary.
 */
#if defined(BOOST_DINKUMWARE_STDLIB)
template<typename Container>
size_t node_size(const Container&)
{
  return sizeof(*Container().begin()._Mynode());
}
#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
template<typename Container>
size_t node_size(const Container&)
{
  typedef typename Container::iterator::_Link_type node_ptr;
  node_ptr p=0;
  return sizeof(*p);
}
template<typename Value,typename Allocator>
size_t node_size(const list<Value,Allocator>&)
{
  return sizeof(typename list<Value,Allocator>::iterator::_Node);
}
template<typename List>
size_t node_size(const list_wrapper<List>&)
{
  return sizeof(typename List::iterator::_Node);
}
#else
/* default version returns 0 by convention */
template<typename Container>
size_t node_size(const Container&)
{
  return 0;
}
#endif
/* mono_container runs the tested routine on multi_index and manual
 * simulations comprised of one standard container.
 * bi_container and tri_container run the equivalent routine for manual
 * compositions of two and three standard containers, respectively.
 */
template <typename Container>
struct mono_container
{
  mono_container(int n_):n(n_){}
  void operator()()
  {
    typedef typename Container::iterator iterator;
    Container c;
    for(int i=0;i<n;++i)c.insert(i);
    for(iterator it=c.begin();it!=c.end();)c.erase(it++);
  }
  static size_t multi_index_node_size()
  {
    return sizeof(*Container().begin().get_node());
  }
  static size_t node_size()
  {
    return ::node_size(Container());
  }
private:
  int n;
};
template <typename Container1,typename Container2>
struct bi_container
{
  bi_container(int n_):n(n_){}
  void operator()()
  {
    typedef typename Container1::iterator iterator1;
    typedef typename Container2::iterator iterator2;
    Container1 c1;
    Container2 c2;
    for(int i=0;i<n;++i){
      iterator1 it1=c1.insert(i).first;
      c2.insert(it1);
    }
    for(iterator2 it2=c2.begin();it2!=c2.end();)
    {
      c1.erase(*it2);
      c2.erase(it2++);
    }
  }
  static size_t node_size()
  {
    return ::node_size(Container1())+::node_size(Container2());
  }
private:
  int n;
};
template <typename Container1,typename Container2,typename Container3>
struct tri_container
{
  tri_container(int n_):n(n_){}
  void operator()()
  {
    typedef typename Container1::iterator iterator1;
    typedef typename Container2::iterator iterator2;
    typedef typename Container3::iterator iterator3;
    Container1 c1;
    Container2 c2;
    Container3 c3;
    for(int i=0;i<n;++i){
      iterator1 it1=c1.insert(i).first;
      iterator2 it2=c2.insert(it1).first;
      c3.insert(it2);
    }
    for(iterator3 it3=c3.begin();it3!=c3.end();)
    {
      c1.erase(**it3);
      c2.erase(*it3);
      c3.erase(it3++);
    }
  }
  static size_t node_size()
  {
    return ::node_size(Container1())+
           ::node_size(Container2())+::node_size(Container3());
  }
private:
  int n;
};
/* measure and compare two routines for several numbers of elements
 * and also estimates relative memory consumption.
 */
template <typename IndexedTest,typename ManualTest>
void run_tests(const char* title)
{
  cout<<fixed<<setprecision(2);
  cout<<title<<endl;
  int n=1000;
  for(int i=0;i<3;++i){
    double indexed_t=measure(IndexedTest(n));
    double manual_t=measure(ManualTest(n));
    cout<<"  10^"<<i+3<<" elmts: "
        <<setw(6)<<100.0*indexed_t/manual_t<<"% "
        <<"("
          <<setw(6)<<1000.0*indexed_t/CLOCKS_PER_SEC<<" ms / "
          <<setw(6)<<1000.0*manual_t/CLOCKS_PER_SEC<<" ms)"
        <<endl;
    n*=10;
  }
  size_t indexed_t_node_size=IndexedTest::multi_index_node_size();
  size_t manual_t_node_size=ManualTest::node_size();
  if(manual_t_node_size){
    cout<<"  space gain: "
        <<setw(6)<<100.0*indexed_t_node_size/manual_t_node_size<<"%"<<endl;
  }
}
/* compare_structures accept a multi_index_container instantiation and
 * several standard containers, builds a manual simulation out of the
 * latter and run the tests.
 */
template <typename IndexedType,typename ManualType>
void compare_structures(const char* title)
{
  run_tests<
    mono_container<IndexedType>,
    mono_container<ManualType>
  >(title);
}
template <typename IndexedType,typename ManualType1,typename ManualType2>
void compare_structures2(const char* title)
{
  run_tests<
    mono_container<IndexedType>,
    bi_container<ManualType1,ManualType2>
  >(title);
}
template <
  typename IndexedType,
  typename ManualType1,typename ManualType2,typename ManualType3
>
void compare_structures3(const char* title)
{
  run_tests<
    mono_container<IndexedType>,
    tri_container<ManualType1,ManualType2,ManualType3>
  >(title);
}
int main()
{
  /* some stdlibs provide the discussed but finally rejected std::identity */
  using boost::multi_index::identity; 
  {
    /* 1 ordered index */
    typedef multi_index_container<int> indexed_t;
    typedef set<int>                   manual_t;
    compare_structures<indexed_t,manual_t>(
      "1 ordered index");
  }
  {
    /* 1 sequenced index */
    typedef list_wrapper<
      multi_index_container<
        int,
        indexed_by<sequenced<> > 
      >
    >                                  indexed_t;
    typedef list_wrapper<list<int> >   manual_t;
    compare_structures<indexed_t,manual_t>(
      "1 sequenced index");
  }
  {
    /* 2 ordered indices */
    typedef multi_index_container<
      int,
      indexed_by<
        ordered_unique<identity<int> >,
        ordered_non_unique<identity<int> >
      >
    >                                  indexed_t;
    typedef set<int>                   manual_t1;
    typedef multiset<
      manual_t1::iterator,
      it_compare<
        manual_t1::iterator,
        manual_t1::key_compare
      >
    >                                  manual_t2;
    compare_structures2<indexed_t,manual_t1,manual_t2>(
      "2 ordered indices");
  }
  {
    /* 1 ordered index + 1 sequenced index */
    typedef multi_index_container<
      int,
      indexed_by<
        boost::multi_index::ordered_unique<identity<int> >,
        sequenced<>
      >
    >                                  indexed_t;
    typedef list_wrapper<
      list<int>
    >                                  manual_t1;
    typedef multiset<
      manual_t1::iterator,
      it_compare<
        manual_t1::iterator,
        std::less<int>
      >
    >                                  manual_t2;
    compare_structures2<indexed_t,manual_t1,manual_t2>(
      "1 ordered index + 1 sequenced index");
  }
  {
    /* 3 ordered indices */
    typedef multi_index_container<
      int,
      indexed_by<
        ordered_unique<identity<int> >,
        ordered_non_unique<identity<int> >,
        ordered_non_unique<identity<int> >
      >
    >                                  indexed_t;
    typedef set<int>                   manual_t1;
    typedef multiset_wrapper<
      multiset<
        manual_t1::iterator,
        it_compare<
          manual_t1::iterator,
          manual_t1::key_compare
        >
      >
    >                                  manual_t2;
    typedef multiset<
      manual_t2::iterator,
      it_compare<
        manual_t2::iterator,
        manual_t2::key_compare
      >
    >                                  manual_t3;
    compare_structures3<indexed_t,manual_t1,manual_t2,manual_t3>(
      "3 ordered indices");
  }
  {
    /* 2 ordered indices + 1 sequenced index */
    typedef multi_index_container<
      int,
      indexed_by<
        ordered_unique<identity<int> >,
        ordered_non_unique<identity<int> >,
        sequenced<>
      >
    >                                  indexed_t;
    typedef list_wrapper<
      list<int>
    >                                  manual_t1;
    typedef multiset_wrapper<
      multiset<
        manual_t1::iterator,
        it_compare<
          manual_t1::iterator,
          std::less<int>
        >
      >
    >                                  manual_t2;
    typedef multiset<
      manual_t2::iterator,
      it_compare<
        manual_t2::iterator,
        manual_t2::key_compare
      >
    >                                  manual_t3;
    compare_structures3<indexed_t,manual_t1,manual_t2,manual_t3>(
      "2 ordered indices + 1 sequenced index");
  }
  return 0;
}

Статья libs/multi_index/perf/test_perf.cpp раздела может быть полезна для разработчиков на c++ и boost.




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



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 15:20:33/0.003917932510376/1